#include "Data.hpp" #include #include "Caps.hpp" namespace molo::example::fw { std::string SessionStore::create() { std::lock_guard lock(mu_); std::string id = "sess-" + std::to_string(next_id_++); sessions_[id] = {}; return id; } bool SessionStore::get(const std::string& id, std::map& out) { std::lock_guard lock(mu_); auto it = sessions_.find(id); if (it == sessions_.end()) return false; out = it->second; return true; } void SessionStore::put(const std::string& id, const std::string& key, const std::string& value) { std::lock_guard lock(mu_); if (!sessions_.count(id) && sessions_.size() >= caps::kMaxSessions) return; sessions_[id][key] = value; } void SessionStore::rotate(const std::string& old_id, std::string& new_id) { std::lock_guard lock(mu_); new_id = "sess-" + std::to_string(next_id_++); auto it = sessions_.find(old_id); if (it != sessions_.end()) { sessions_[new_id] = it->second; sessions_.erase(it); } else { sessions_[new_id] = {}; } } std::string demo_hash_password(const std::string& password) { unsigned long long h = 1469598103934665603ULL; std::string salted = "demo-salt|" + password; for (unsigned char c : salted) { h ^= c; h *= 1099511628211ULL; } char buf[32]; std::snprintf(buf, sizeof(buf), "demo$%016llx", (unsigned long long)h); return buf; } namespace { int b64val(char c) { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+') return 62; if (c == '/') return 63; return -1; } std::string b64decode(const std::string& in) { std::string out; int acc = 0, bits = 0; for (char c : in) { if (c == '=') break; int v = b64val(c); if (v < 0) continue; acc = (acc << 6) | v; bits += 6; if (bits >= 8) { bits -= 8; out.push_back((char)((acc >> bits) & 0xFF)); } } return out; } } // namespace bool parse_basic_auth(const std::string& header, std::string& user, std::string& password) { const std::string prefix = "Basic "; if (header.compare(0, prefix.size(), prefix) != 0) return false; std::string decoded = b64decode(header.substr(prefix.size())); std::size_t colon = decoded.find(':'); if (colon == std::string::npos) return false; user = decoded.substr(0, colon); password = decoded.substr(colon + 1); return true; } void Auth::add_user(const std::string& username, const std::string& password) { std::lock_guard lock(mu_); users_[username] = demo_hash_password(password); } bool Auth::check(const std::string& username, const std::string& password) const { std::lock_guard lock(mu_); auto it = users_.find(username); if (it == users_.end()) return false; return it->second == demo_hash_password(password); } std::string backend_name(OrmBackend backend) { return backend == OrmBackend::Sqlite ? "sqlite" : "postgres"; } OrmBackend parse_backend(const std::string& name) { return name == "postgres" ? OrmBackend::Postgres : OrmBackend::Sqlite; } OrmDb::OrmDb(OrmBackend backend) : backend_(backend) {} OrmBackend OrmDb::backend() const { return backend_; } OrmResult OrmDb::insert(const std::string& table, const std::map& values) { std::lock_guard lock(mu_); OrmResult res; auto& cols = schema_[table]; if (cols.empty()) { if (schema_.size() > caps::kMaxOrmTables) { res.ok = false; return res; } for (const auto& [k, v] : values) cols.push_back(k); res.healed = true; res.healed_note = "auto-created table " + table; } else { for (const auto& [k, v] : values) { bool known = false; for (const auto& c : cols) { if (c == k) { known = true; break; } } if (!known) { cols.push_back(k); res.healed = true; res.healed_note = "auto-added column " + k + " to " + table; } } } auto& vec = rows_[table]; if (vec.size() >= caps::kMaxOrmRows) { res.ok = false; return res; } OrmRow row; row.columns = values; vec.push_back(row); res.rows = {row}; return res; } OrmResult OrmDb::select_all(const std::string& table) { std::lock_guard lock(mu_); OrmResult res; auto it = rows_.find(table); if (it == rows_.end()) { if (!schema_.count(table)) { schema_[table] = {"id"}; res.healed = true; res.healed_note = "auto-created table " + table; } return res; } res.rows = it->second; return res; } OrmResult OrmDb::ensure_column(const std::string& table, const std::string& column) { std::lock_guard lock(mu_); OrmResult res; auto& cols = schema_[table]; for (const auto& c : cols) { if (c == column) return res; } cols.push_back(column); res.healed = true; res.healed_note = "auto-added column " + column + " to " + table; return res; } std::vector OrmDb::tables() const { std::lock_guard lock(mu_); std::vector out; for (const auto& [k, v] : schema_) out.push_back(k); return out; } std::vector OrmDb::columns(const std::string& table) const { std::lock_guard lock(mu_); auto it = schema_.find(table); if (it == schema_.end()) return {}; return it->second; } bool UploadStore::store(const std::string& filename, const std::string& content_type, const std::string& data, UploadInfo& out, std::string& error) { if (data.size() > caps::kMaxUploadBytes) { error = "file too large"; return false; } bool allowed = content_type == "text/plain" || content_type == "image/png" || content_type == "application/json"; if (!allowed) { error = "content type not allowed"; return false; } if (filename.find("..") != std::string::npos || filename.find('/') != std::string::npos) { error = "unsafe filename"; return false; } std::lock_guard lock(mu_); out = UploadInfo{filename, content_type, data.size()}; uploads_.push_back(out); return true; } std::vector UploadStore::list() const { std::lock_guard lock(mu_); return uploads_; } void WebdavStore::put(const std::string& path, const std::string& content) { std::lock_guard lock(mu_); if (!files_.count(path) && files_.size() >= caps::kMaxWebdavEntries) return; files_[path] = content; } bool WebdavStore::get(const std::string& path, std::string& out) const { std::lock_guard lock(mu_); auto it = files_.find(path); if (it == files_.end()) return false; out = it->second; return true; } bool WebdavStore::remove(const std::string& path) { std::lock_guard lock(mu_); return files_.erase(path) > 0; } std::string WebdavStore::propfind_xml(const std::string& root) const { std::lock_guard lock(mu_); std::string out = ""; for (const auto& [k, v] : files_) { if (k.compare(0, root.size(), root) != 0) continue; out += "" + k + "" + std::to_string(v.size()) + "HTTP/1.1 200 OK" ""; } return out + ""; } } // namespace molo::example::fw