Tunnels now get a per-tunnel certificate from the configured ACME CA (Let's Encrypt by default) with DNS-01 through Porkbun, keeping the client's CSR and key. Issuance is asynchronous (issuing/ready/failed); the account persists in the store, renewals run in a 30-day window with retries, and a failed renewal keeps the old certificate serving. Switching from the local CA reissues existing tunnels automatically, and the admin dashboard shows the issuer and certificate state. Verified against Pebble and Let's Encrypt staging.
58 lines
1.6 KiB
Go
58 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestChallengeTestSrvDNS(t *testing.T) {
|
|
var setBody, clearBody map[string]string
|
|
var setPath, clearPath string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
body, _ := io.ReadAll(r.Body)
|
|
switch r.URL.Path {
|
|
case "/set-txt":
|
|
setPath = r.URL.Path
|
|
_ = json.Unmarshal(body, &setBody)
|
|
case "/clear-txt":
|
|
clearPath = r.URL.Path
|
|
_ = json.Unmarshal(body, &clearBody)
|
|
default:
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := &ChallengeTestSrvDNS{BaseURL: srv.URL, HTTP: srv.Client()}
|
|
ctx := context.Background()
|
|
|
|
if err := c.CreateTXT(ctx, "_acme-challenge.abc.localhost", "value"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if setPath != "/set-txt" || setBody["host"] != "_acme-challenge.abc.localhost" || setBody["value"] != "value" {
|
|
t.Errorf("set: path %q body %v", setPath, setBody)
|
|
}
|
|
|
|
if err := c.DeleteTXT(ctx, "_acme-challenge.abc.localhost"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if clearPath != "/clear-txt" || clearBody["host"] != "_acme-challenge.abc.localhost" {
|
|
t.Errorf("clear: path %q body %v", clearPath, clearBody)
|
|
}
|
|
|
|
bad := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
http.Error(w, "no", http.StatusInternalServerError)
|
|
}))
|
|
defer bad.Close()
|
|
c = &ChallengeTestSrvDNS{BaseURL: bad.URL, HTTP: bad.Client()}
|
|
if err := c.CreateTXT(ctx, "x", "y"); err == nil {
|
|
t.Error("expected an error for a non-200 response")
|
|
}
|
|
}
|