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

test

parent 3bfead73
Loading
Loading
Loading
Loading
+2 −1
Changes for admin/static/app.js: 2 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.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.acme_email}</td><td>${p.ca_plugin}</td><td></td>`;
      addDeleteButton(tr, () => deleteTlsProfile(p.profile));
      body.appendChild(tr);
    }
@@ -265,6 +265,7 @@ const ProxyPlusAdmin = (() => {
        acme_email: document.getElementById("tls-profile-email").value,
        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,
      });
      await refreshTlsProfiles();
    } catch (e) {
+2 −1
Changes for admin/static/index.html: 2 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@
  </div>

  <h2>TLS-Profile / Zertifikate</h2>
  <table id="tls-profiles"><thead><tr><th>Profil</th><th>Domains</th><th>ACME</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>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">
@@ -65,6 +65,7 @@
      <option value="letsencrypt">letsencrypt</option>
      <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>
    <button onclick="ProxyPlusAdmin.createTlsProfile()">Anlegen</button>
    <div id="tls-profile-error" class="error"></div>
  </div>
+14 −0
Changes for docs/ARCHITECTURE.md: 14 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -214,6 +214,20 @@ auf diesem System nicht installiert. Die Krypto-Grundlage ist ausschließlich
  wird **nie** geraten —, ruft es auf, schreibt `<dataPath>/tls/<profil>.{crt,key}` atomar und
  ruft registrierte Reload-Callbacks auf.

**Self-Signed als ACME-Alternative.** Ein `TlsProfileRecord` kann statt `acmeEnabled` das Feld
`selfSigned` setzen (mutually exclusive, von `JsonApiServer` erzwungen) — für Frontends ohne
öffentlichen, per HTTP-01 beweisbaren Hostnamen (internes/LAN-Listener, Erst-Boot der Admin-UI
vor jeder DNS-Konfiguration). `CertificateManager::provisionSelfSigned()` generiert dabei lokal
(kein Netzwerk, keine ACME-Rate-Limits) über `netplus::generateSelfSignedCert()` — dieselbe
selbstsignierte-Zertifikat-Funktion aus `libnetplus/src/utils/certgen.cpp`, jetzt mit
`subjectAltName` aus `TlsProfileRecord::domains` (moderne TLS-Clients ignorieren die Subject-CN
vollständig ohne SAN) — und schreibt nach demselben `<dataPath>/tls/<profil>.{crt,key}`-Pfad wie
ACME. Anders als ACME läuft das nicht nur im Hintergrund-Thread: `main.cpp` ruft
`provisionSelfSigned()` synchron auf, **bevor** die HTTP/SMTP/Admin-Listener konstruiert werden,
da `HttpD`/`SmtpD`s Konstruktor bei fehlender Zertifikatsdatei sofort wirft (kein Vorlauf wie bei
ACME's Hintergrund-Renewal möglich). Erneuerung nahe Ablauf läuft weiterhin über denselben
`checkLoop()` wie ACME.

**Bekannte Lücken dieser Implementierung:**
- Nur **HTTP-01**, kein DNS-01/TLS-ALPN-01 — keine Wildcard-Zertifikate möglich.
- Nur **RSA-2048** (Account- und Zertifikatsschlüssel), kein ECDSA.
+19 −0
Changes for test/test_configstore.cpp: 19 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -34,11 +34,23 @@ int main() {
        perm.gpoId = "11111111-1111-1111-1111-111111111111";
        store.putPermission(perm);

        TlsProfileRecord tlsProfile;
        tlsProfile.profile = "internal";
        tlsProfile.domains = {"proxy.internal.lan"};
        tlsProfile.selfSigned = true;
        store.putTlsProfile(tlsProfile);

        assert(store.listHttpRoutes().size() == 1);
        assert(store.listSmtpRelayRules().size() == 1);
        auto gpoId = store.gpoIdForPermission("smtp.domains.write", ResourceContext{"", ""});
        assert(gpoId && *gpoId == perm.gpoId);
        assert(store.version() > 0);

        auto profiles = store.listTlsProfiles();
        assert(profiles.size() == 1);
        assert(profiles[0].selfSigned);
        assert(!profiles[0].acmeEnabled);
        assert(profiles[0].domains == tlsProfile.domains);
    }

    // Reopen: WAL replay must reconstruct identical state.
@@ -53,6 +65,11 @@ int main() {
        assert(relays.size() == 1);
        assert(relays[0].smarthost == "smtp.example.com:587");

        auto profiles = store.listTlsProfiles();
        assert(profiles.size() == 1);
        assert(profiles[0].profile == "internal");
        assert(profiles[0].selfSigned);

        // compact() must fold the WAL into a snapshot without losing data.
        store.compact();
        assert(store.listHttpRoutes().size() == 1);
@@ -63,6 +80,8 @@ int main() {
        ConfigStore store(dir);
        assert(store.listHttpRoutes().size() == 1);
        assert(store.listSmtpRelayRules().size() == 1);
        assert(store.listTlsProfiles().size() == 1);
        assert(store.listTlsProfiles()[0].selfSigned);
    }

    std::system(("rm -rf " + dir).c_str());