Add the native Go client and finish M3 hardening
The new cmd/tunnel client keeps the API URL and tunnel identity in ~/.config/tunnel/config.json (0600), provisions the key/CSR and certificate, terminates TLS, proxies to local routes, reloads routes without a restart, and runs as a background service. `tunnel import` takes over an existing official CLI profile, preserving its tunnel ID, token, key and certificate. Server hardening: per-IP and per-tunnel rate limits for creates and binds, a CA cool-down after repeated ACME failures, a startup sweep for stale _acme-challenge records, admin metrics, a 60-second half-close timeout, and separate prioritized control / ordered data bridge queues (with `end` ordered after the final bytes). The dashboard shows the new metrics.
This commit is contained in:
@@ -72,3 +72,46 @@ func TestPorkbunDNS(t *testing.T) {
|
||||
t.Errorf("expected the API error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPorkbunSweepChallenges(t *testing.T) {
|
||||
var deletes []string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case r.URL.Path == "/dns/retrieve/tzgyn.dev":
|
||||
w.Write([]byte(`{"status":"SUCCESS","records":[
|
||||
{"name":"_acme-challenge.a.tunnel.tzgyn.dev","type":"TXT","content":"one"},
|
||||
{"name":"_acme-challenge.a.tunnel.tzgyn.dev","type":"TXT","content":"two"},
|
||||
{"name":"_acme-challenge.b.tunnel.tzgyn.dev","type":"TXT","content":"three"},
|
||||
{"name":"www.tzgyn.dev","type":"TXT","content":"keep"},
|
||||
{"name":"_acme-challenge.other.example.com","type":"TXT","content":"outside"}
|
||||
]}`))
|
||||
case strings.HasPrefix(r.URL.Path, "/dns/deleteByNameType/"):
|
||||
deletes = append(deletes, r.URL.Path)
|
||||
w.Write([]byte(`{"status":"SUCCESS"}`))
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
p := &PorkbunDNS{APIKey: "pk", SecretKey: "sk", Zone: "tzgyn.dev", BaseURL: srv.URL, HTTP: srv.Client()}
|
||||
count, err := p.SweepChallenges(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != 2 {
|
||||
t.Errorf("count = %d, want 2", count)
|
||||
}
|
||||
want := []string{
|
||||
"/dns/deleteByNameType/tzgyn.dev/TXT/_acme-challenge.a.tunnel",
|
||||
"/dns/deleteByNameType/tzgyn.dev/TXT/_acme-challenge.b.tunnel",
|
||||
}
|
||||
if len(deletes) != len(want) {
|
||||
t.Fatalf("deletes = %v, want %v", deletes, want)
|
||||
}
|
||||
for i := range want {
|
||||
if deletes[i] != want[i] {
|
||||
t.Errorf("delete[%d] = %q, want %q", i, deletes[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user