700a2d06fe
On create and edit, a non-empty cf_api_token is checked with Cloudflare (GET /zones): it is saved only when the token sees exactly one zone and the customer's domain is that zone or a name under it. More zones, another zone, no zone, or Cloudflare not answering -> the form re-renders with one sentence and nothing is saved (the previous token stays). An unchanged token on an unchanged domain and an empty token (HTTP-01) make no call. The token is never logged and never in a sentence or error. Tests use a fake Cloudflare (httptest). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
63 lines
2.1 KiB
Go
63 lines
2.1 KiB
Go
package cloudflare
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestZoneCovers(t *testing.T) {
|
|
for _, c := range []struct {
|
|
zone, domain string
|
|
want bool
|
|
}{
|
|
{"example.hu", "example.hu", true},
|
|
{"example.hu", "felhom.example.hu", true},
|
|
{"Example.HU.", "home.example.hu", true},
|
|
{"example.hu", "notexample.hu", false},
|
|
{"example.hu", "example.hu.evil.hu", false},
|
|
{"home.example.hu", "example.hu", false},
|
|
{"", "example.hu", false},
|
|
{"example.hu", "", false},
|
|
} {
|
|
if got := ZoneCovers(c.zone, c.domain); got != c.want {
|
|
t.Errorf("ZoneCovers(%q,%q)=%v want %v", c.zone, c.domain, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The count is Cloudflare's total_count, so a token that sees more zones than one page holds is not read as „one".
|
|
func TestTokenZones_CountsBeyondOnePage(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte(`{"success":true,"result":[{"id":"1","name":"a.hu"}],"result_info":{"total_count":7}}`))
|
|
}))
|
|
defer srv.Close()
|
|
names, total, err := TokenZones(context.Background(), srv.URL, "tok-secret-value-123")
|
|
if err != nil || total != 7 || len(names) != 1 {
|
|
t.Fatalf("got names=%v total=%d err=%v; want 1 name, total 7", names, total, err)
|
|
}
|
|
}
|
|
|
|
func TestTokenZones_ErrorsAreUnknownAndCarryNoToken(t *testing.T) {
|
|
const tok = "tok-secret-value-123"
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("Authorization") != "Bearer "+tok {
|
|
t.Errorf("token not sent as a bearer header")
|
|
}
|
|
w.WriteHeader(http.StatusBadGateway)
|
|
w.Write([]byte(`echo ` + tok))
|
|
}))
|
|
_, _, err := TokenZones(context.Background(), srv.URL, tok)
|
|
if !errors.Is(err, ErrReachUnknown) || strings.Contains(err.Error(), tok) {
|
|
t.Fatalf("5xx: want ErrReachUnknown without the token; got %v", err)
|
|
}
|
|
srv.Close()
|
|
_, _, err = TokenZones(context.Background(), srv.URL, tok)
|
|
if !errors.Is(err, ErrReachUnknown) || strings.Contains(err.Error(), tok) {
|
|
t.Fatalf("unreachable: want ErrReachUnknown without the token; got %v", err)
|
|
}
|
|
}
|