package checker import ( "encoding/json" "net" "strings" "testing" "github.com/miekg/dns" sdk "git.happydns.org/checker-sdk-go/checker" happydns "git.happydns.org/happyDomain/model" "git.happydns.org/happyDomain/services/abstract" ) func serverOpts(t *testing.T, domain string, srv abstract.Server, extra map[string]any) sdk.CheckerOptions { t.Helper() raw, err := json.Marshal(srv) if err != nil { t.Fatal(err) } opts := sdk.CheckerOptions{ OptionService: happydns.ServiceMessage{ ServiceMeta: happydns.ServiceMeta{ Type: "abstract.Server", Domain: domain, }, Service: raw, }, OptionDomainName: "example.org", } for k, v := range extra { opts[k] = v } return opts } func TestShareKey_StableAndPrefixed(t *testing.T) { p := &sshProvider{} srv := abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}} a, err := p.ShareKey(serverOpts(t, "host", srv, nil)) if err != nil { t.Fatal(err) } b, _ := p.ShareKey(serverOpts(t, "host", srv, nil)) if a != b { t.Fatalf("non-deterministic key: %q vs %q", a, b) } if !strings.HasPrefix(a, "ssh:") { t.Fatalf("missing prefix: %q", a) } } // The host/Domain label must not change the key: the same server answers // identically behind every name (SSH has no SNI). func TestShareKey_IgnoresDomainLabel(t *testing.T) { p := &sshProvider{} srv := abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}} a, _ := p.ShareKey(serverOpts(t, "alpha", srv, nil)) b, _ := p.ShareKey(serverOpts(t, "beta", srv, nil)) if a != b { t.Fatalf("domain label must not affect the key: %q vs %q", a, b) } } func TestShareKey_DiffersByAddress(t *testing.T) { p := &sshProvider{} a, _ := p.ShareKey(serverOpts(t, "host", abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}}, nil)) b, _ := p.ShareKey(serverOpts(t, "host", abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.2").To4()}}, nil)) if a == b { t.Fatalf("different addresses must yield different keys") } } func TestShareKey_DiffersByPortsAndKnobs(t *testing.T) { p := &sshProvider{} srv := abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}} def, _ := p.ShareKey(serverOpts(t, "host", srv, nil)) ports, _ := p.ShareKey(serverOpts(t, "host", srv, map[string]any{OptionPorts: "22,2222"})) auth, _ := p.ShareKey(serverOpts(t, "host", srv, map[string]any{OptionIncludeAuthProbe: false})) timeout, _ := p.ShareKey(serverOpts(t, "host", srv, map[string]any{OptionProbeTimeoutMs: float64(1000)})) for name, got := range map[string]string{"ports": ports, "authProbe": auth, "timeout": timeout} { if got == def { t.Fatalf("%s must affect the key", name) } } } // SSHFP fingerprints live in the observation and drive the SSHFP-match rule, so // they must be part of the key. func TestShareKey_DiffersBySSHFP(t *testing.T) { p := &sshProvider{} bare := abstract.Server{A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}} withFP := abstract.Server{ A: &dns.A{A: net.ParseIP("192.0.2.1").To4()}, SSHFP: []*dns.SSHFP{{Algorithm: 4, Type: 2, FingerPrint: "abcdef"}}, } a, _ := p.ShareKey(serverOpts(t, "host", bare, nil)) b, _ := p.ShareKey(serverOpts(t, "host", withFP, nil)) if a == b { t.Fatalf("declared SSHFP must affect the key") } } func TestShareKey_EmptyWhenNoAddress(t *testing.T) { p := &sshProvider{} if sk, err := p.ShareKey(sdk.CheckerOptions{}); err != nil || sk != "" { t.Fatalf("expected empty key, got %q (err=%v)", sk, err) } }