Loading src/api/JsonApiServer.cpp +48 −0 Changes for src/api/JsonApiServer.cpp: 48 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -288,6 +288,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/smtp/relays", "smtp.domains.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string id = getStringField(body, "id"); if (id.empty()) return jsonError("id is required"); _configStore.deleteSmtpRelayRule(id); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); _routes.push_back( {"GET", "/api/v1/tls/profiles", "tls.profiles.read", [this](RouteContext &) -> std::string { JsonGuard arr(json_object_new_array()); Loading Loading @@ -344,6 +356,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/tls/profiles", "tls.profiles.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string profile = getStringField(body, "profile"); if (profile.empty()) return jsonError("profile is required"); _configStore.deleteTlsProfile(profile); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); // Load-balancer pools, shared by HttpRouteRecord::upstreamPool and // SmtpRelayRuleRecord::smarthostPool (see src/lb/LoadBalancer). "kind" is informational // only -- LoadBalancer itself doesn't care whether a target string is an HTTP URL or an Loading Loading @@ -422,6 +446,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/pools", "lb.pools.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string id = getStringField(body, "id"); if (id.empty()) return jsonError("id is required"); _configStore.deleteUpstreamPool(id); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); // Per-domain DKIM signing keys, consulted by SmtpProxyServer::DataEvent for outbound mail // (see docs/ARCHITECTURE.md §6). Verifying an *incoming* signature needs no config here -- // DkimAdapter::verify() resolves the signer's public key via DNS itself. Loading Loading @@ -457,6 +493,18 @@ void JsonApiController::registerRoutes() { json_object_object_add(resp, "status", json_object_new_string("created")); return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/security/dkim-keys", "security.dkim.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string domain = getStringField(body, "domain"); if (domain.empty()) return jsonError("domain is required"); _configStore.deleteDkimKey(domain); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); } namespace { Loading src/store/ConfigStore.cpp +13 −2 Changes for src/store/ConfigStore.cpp: 13 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -338,11 +338,14 @@ void ConfigStore::applyRecord(RecordTable table, RecordOp op, const std::vector< _permissions[permissionKey(rec.permission, rec.resourcePattern)] = rec; break; } case RecordTable::TlsProfile: { case RecordTable::TlsProfile: if (op == RecordOp::Put) { auto rec = decodeTlsProfile(r); _tlsProfiles[rec.profile] = rec; break; } else { _tlsProfiles.erase(r.str()); } break; case RecordTable::UpstreamPool: if (op == RecordOp::Put) { auto rec = decodeUpstreamPool(r); Loading Loading @@ -447,6 +450,14 @@ void ConfigStore::putTlsProfile(const TlsProfileRecord &rec) { _tlsProfiles[rec.profile] = rec; } void ConfigStore::deleteTlsProfile(const std::string &profile) { std::unique_lock lk(_mutex); ByteWriter w; w.str(profile); appendWal(RecordTable::TlsProfile, RecordOp::Delete, w.buffer()); _tlsProfiles.erase(profile); } std::vector<TlsProfileRecord> ConfigStore::listTlsProfiles() const { std::shared_lock lk(_mutex); std::vector<TlsProfileRecord> out; Loading src/store/ConfigStore.h +1 −0 Changes for src/store/ConfigStore.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ public: std::vector<PermissionRegistryRecord> listPermissions() const; void putTlsProfile(const TlsProfileRecord &rec); void deleteTlsProfile(const std::string &profile); std::vector<TlsProfileRecord> listTlsProfiles() const; void putUpstreamPool(const UpstreamPoolRecord &rec); Loading Loading
src/api/JsonApiServer.cpp +48 −0 Changes for src/api/JsonApiServer.cpp: 48 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -288,6 +288,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/smtp/relays", "smtp.domains.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string id = getStringField(body, "id"); if (id.empty()) return jsonError("id is required"); _configStore.deleteSmtpRelayRule(id); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); _routes.push_back( {"GET", "/api/v1/tls/profiles", "tls.profiles.read", [this](RouteContext &) -> std::string { JsonGuard arr(json_object_new_array()); Loading Loading @@ -344,6 +356,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/tls/profiles", "tls.profiles.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string profile = getStringField(body, "profile"); if (profile.empty()) return jsonError("profile is required"); _configStore.deleteTlsProfile(profile); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); // Load-balancer pools, shared by HttpRouteRecord::upstreamPool and // SmtpRelayRuleRecord::smarthostPool (see src/lb/LoadBalancer). "kind" is informational // only -- LoadBalancer itself doesn't care whether a target string is an HTTP URL or an Loading Loading @@ -422,6 +446,18 @@ void JsonApiController::registerRoutes() { return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/pools", "lb.pools.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string id = getStringField(body, "id"); if (id.empty()) return jsonError("id is required"); _configStore.deleteUpstreamPool(id); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); // Per-domain DKIM signing keys, consulted by SmtpProxyServer::DataEvent for outbound mail // (see docs/ARCHITECTURE.md §6). Verifying an *incoming* signature needs no config here -- // DkimAdapter::verify() resolves the signer's public key via DNS itself. Loading Loading @@ -457,6 +493,18 @@ void JsonApiController::registerRoutes() { json_object_object_add(resp, "status", json_object_new_string("created")); return json_object_to_json_string(resp); }}); _routes.push_back( {"DELETE", "/api/v1/security/dkim-keys", "security.dkim.write", [this](RouteContext &ctx) -> std::string { JsonGuard body(json_tokener_parse(ctx.body.c_str())); if (!body.obj) return jsonError("invalid JSON body"); std::string domain = getStringField(body, "domain"); if (domain.empty()) return jsonError("domain is required"); _configStore.deleteDkimKey(domain); JsonGuard resp(json_object_new_object()); json_object_object_add(resp, "status", json_object_new_string("deleted")); return json_object_to_json_string(resp); }}); } namespace { Loading
src/store/ConfigStore.cpp +13 −2 Changes for src/store/ConfigStore.cpp: 13 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -338,11 +338,14 @@ void ConfigStore::applyRecord(RecordTable table, RecordOp op, const std::vector< _permissions[permissionKey(rec.permission, rec.resourcePattern)] = rec; break; } case RecordTable::TlsProfile: { case RecordTable::TlsProfile: if (op == RecordOp::Put) { auto rec = decodeTlsProfile(r); _tlsProfiles[rec.profile] = rec; break; } else { _tlsProfiles.erase(r.str()); } break; case RecordTable::UpstreamPool: if (op == RecordOp::Put) { auto rec = decodeUpstreamPool(r); Loading Loading @@ -447,6 +450,14 @@ void ConfigStore::putTlsProfile(const TlsProfileRecord &rec) { _tlsProfiles[rec.profile] = rec; } void ConfigStore::deleteTlsProfile(const std::string &profile) { std::unique_lock lk(_mutex); ByteWriter w; w.str(profile); appendWal(RecordTable::TlsProfile, RecordOp::Delete, w.buffer()); _tlsProfiles.erase(profile); } std::vector<TlsProfileRecord> ConfigStore::listTlsProfiles() const { std::shared_lock lk(_mutex); std::vector<TlsProfileRecord> out; Loading
src/store/ConfigStore.h +1 −0 Changes for src/store/ConfigStore.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ public: std::vector<PermissionRegistryRecord> listPermissions() const; void putTlsProfile(const TlsProfileRecord &rec); void deleteTlsProfile(const std::string &profile); std::vector<TlsProfileRecord> listTlsProfiles() const; void putUpstreamPool(const UpstreamPoolRecord &rec); Loading