Commit b87bf3b4 authored by jan.koester's avatar jan.koester
Browse files

test

parent d3c369e4
Loading
Loading
Loading
Loading
+1 −0
Changes for CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ set(PROXYPLUS_CORE_SOURCES
    src/security/DmarcAdapter.cpp
    src/security/SpfAdapter.cpp
    src/tls/CertificateManager.cpp
    src/tls/CertSeal.cpp
    src/lb/LoadBalancer.cpp
)

+3 −1
Changes for admin/static/app.js: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ const ProxyPlusAdmin = (() => {
    body.innerHTML = "";
    for (const p of profiles) {
      const tr = document.createElement("tr");
      tr.innerHTML = `<td>${p.profile}</td><td>${(p.domains || []).join(", ")}</td><td>${p.acme_enabled ? "ja" : "nein"}</td><td>${p.self_signed ? "ja" : "nein"}</td><td>${p.acme_email}</td><td>${p.ca_plugin}</td><td></td>`;
      tr.innerHTML = `<td>${p.profile}</td><td>${(p.domains || []).join(", ")}</td><td>${p.acme_enabled ? "ja" : "nein"}</td><td>${p.self_signed ? "ja" : "nein"}</td><td>${p.has_manual_cert ? "ja" : "nein"}</td><td>${p.acme_email}</td><td>${p.ca_plugin}</td><td></td>`;
      addDeleteButton(tr, () => deleteTlsProfile(p.profile));
      body.appendChild(tr);
    }
@@ -267,6 +267,8 @@ const ProxyPlusAdmin = (() => {
        acme_directory_url: document.getElementById("tls-profile-directory").value,
        ca_plugin: document.getElementById("tls-profile-ca-plugin").value,
        self_signed: document.getElementById("tls-profile-selfsigned").checked,
        cert_pem: document.getElementById("tls-profile-cert-pem").value,
        key_pem: document.getElementById("tls-profile-key-pem").value,
      });
      await refreshTlsProfiles();
    } catch (e) {
+3 −1
Changes for admin/static/index.html: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@
  </div>

  <h2>TLS-Profile / Zertifikate</h2>
  <table id="tls-profiles"><thead><tr><th>Profil</th><th>Domains</th><th>ACME</th><th>Self-Signed</th><th>E-Mail</th><th>CA-Plugin</th><th>Aktionen</th></tr></thead><tbody></tbody></table>
  <table id="tls-profiles"><thead><tr><th>Profil</th><th>Domains</th><th>ACME</th><th>Self-Signed</th><th>Eigenes Zertifikat</th><th>E-Mail</th><th>CA-Plugin</th><th>Aktionen</th></tr></thead><tbody></tbody></table>
  <button onclick="ProxyPlusAdmin.showNewTlsProfileForm()">Neues Profil</button>
  <div id="new-tls-profile-form" hidden>
    <input id="tls-profile-id" placeholder="Profil-ID, z.B. www">
@@ -67,6 +67,8 @@
      <option value="zerossl">zerossl</option>
    </select>
    <label><input type="checkbox" id="tls-profile-selfsigned"> Self-Signed (lokal generiert, kein ACME -- fuer interne Frontends ohne oeffentlichen Hostnamen)</label>
    <textarea id="tls-profile-cert-pem" placeholder="Eigenes Zertifikat (PEM) -- nur im Cluster-Modus, sonst Datei direkt unter <data>/tls/<profil>.crt ablegen" rows="4"></textarea>
    <textarea id="tls-profile-key-pem" placeholder="Eigener privater Schluessel (PEM) -- wird vor der Speicherung mit dem Cluster-Schluessel versiegelt" rows="4"></textarea>
    <button onclick="ProxyPlusAdmin.createTlsProfile()">Anlegen</button>
    <div id="tls-profile-error" class="error"></div>
  </div>
+5 −0
Changes for config/proxyplus.yaml: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -27,6 +27,11 @@ proxyplus:
      #   port: 443
      #   tls_profile: "www"   # resolves to /var/lib/proxyplus/tls/www.{crt,key}; see
      #                        # POST /api/v1/tls/profiles to have plugins/letsencrypt keep it renewed
      # - address: "0.0.0.0"          # SNI virtual hosting: several profiles on one :443 listener,
      #   port: 443                   # each presented only for its own TlsProfileRecord.domains --
      #   tls_profiles:                # mutually exclusive with the single tls_profile above.
      #     - "www"                   # e.g. domains: ["example.com", "www.example.com"]
      #     - "shop"                  # e.g. domains: ["shop.example.com"], can be a wholly separate cert

  smtp:
    listen:
+31 −0
Changes for src/api/JsonApiServer.cpp: 31 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@

#include <json-c/json.h>

#include "../cluster/ClusterManager.h"
#include "../tls/CertSeal.h"

namespace proxyplus::api {

namespace {
@@ -337,6 +340,7 @@ void JsonApiController::registerRoutes() {
                                         json_object_new_string(r.acmeDirectoryUrl.c_str()));
                 json_object_object_add(item, "ca_plugin", json_object_new_string(r.caPlugin.c_str()));
                 json_object_object_add(item, "self_signed", json_object_new_boolean(r.selfSigned));
                 json_object_object_add(item, "has_manual_cert", json_object_new_boolean(!r.certPem.empty()));
                 json_object_get(item.obj);
                 json_object_array_add(arr.obj, item.obj);
             }
@@ -348,6 +352,12 @@ void JsonApiController::registerRoutes() {
    // Encrypt/ACME section); it does not itself talk to the ACME server or block on
    // issuance. ca_plugin selects which loaded ICertificateProviderPlugin to use by name
    // (e.g. "letsencrypt", "zerossl") -- required once more than one is loaded.
    //
    // cert_pem/key_pem cover the third case: an operator-supplied cert that's neither
    // ACME-issued nor self-signed, which CertificateManager can't (re)create on its own. Only
    // meaningful in cluster mode -- see src/tls/CertSeal.h for why the key is sealed before it
    // touches ConfigStore. In single-node mode there's no cluster to sync to; the operator
    // should just drop the cert/key files at <dataPath>/tls/<profile>.{crt,key} directly.
    _routes.push_back(
        {"POST", "/api/v1/tls/profiles", "tls.profiles.write", [this](RouteContext &ctx) -> std::string {
             JsonGuard body(json_tokener_parse(ctx.body.c_str()));
@@ -359,6 +369,8 @@ void JsonApiController::registerRoutes() {
             rec.acmeDirectoryUrl = getStringField(body, "acme_directory_url");
             rec.caPlugin = getStringField(body, "ca_plugin");
             rec.selfSigned = getBoolField(body, "self_signed");
             std::string certPem = getStringField(body, "cert_pem");
             std::string keyPem = getStringField(body, "key_pem");
             json_object *domainsArr = nullptr;
             if (json_object_object_get_ex(body, "domains", &domainsArr) && domainsArr) {
                 int n = json_object_array_length(domainsArr);
@@ -374,6 +386,25 @@ void JsonApiController::registerRoutes() {
             if (rec.acmeEnabled && (rec.domains.empty() || rec.acmeEmail.empty())) {
                 return jsonError("acme_enabled requires at least one domain and acme_email");
             }
             if (!certPem.empty() != !keyPem.empty()) {
                 return jsonError("cert_pem and key_pem must be provided together");
             }
             if (!certPem.empty()) {
                 if (rec.acmeEnabled || rec.selfSigned) {
                     return jsonError("cert_pem/key_pem are mutually exclusive with acme_enabled/self_signed");
                 }
                 if (!_cfg.clusterEnabled) {
                     return jsonError("cert_pem/key_pem replication needs cluster mode -- in single-node "
                                       "mode, place the cert/key directly at <data>/tls/" +
                                       rec.profile + ".{crt,key} instead");
                 }
                 auto clusterKey = cluster::ClusterManager::loadOrCreateSharedKey(_cfg.dataPath);
                 auto sealed = tls::sealPrivateKey(clusterKey, keyPem);
                 rec.certPem = certPem;
                 rec.encryptedKeyPem = sealed.ciphertext;
                 rec.keyNonce = sealed.nonce;
                 rec.keyTag = sealed.tag;
             }
             _configStore.putTlsProfile(rec);
             JsonGuard resp(json_object_new_object());
             json_object_object_add(resp, "status", json_object_new_string("created"));
Loading