package link import ( "context" "crypto/ed25519" "encoding/json" "strings" "testing" "time" "github.com/nats-io/nats.go" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/testbus" ) // A fresh setuid search is asked of the machine on its own subject, signed under its own context — never a // hand-over's — naming no path, and the engine's answer comes back (novox/hq issue 361). The engine holds the // same subject and context (mesh-host internal/link, TestTheSetuidSearchAskKeepsItsSubjectAndContext). func TestASetuidSearchIsAskedOfTheMachineSignedUnderItsOwnContext(t *testing.T) { if broker.AskSetuidSearchSubject("laptop") != "mesh.node.laptop.ask.setuid-search" || SetuidSearchContext != "novox-mesh setuid-search v1\n" { t.Fatalf("the subject %q, the context %q", broker.AskSetuidSearchSubject("laptop"), SetuidSearchContext) } conn, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) } t.Cleanup(conn.Close) signer, public := testSigner(t) var heard HandOverAsk engine, err := conn.Subscribe(broker.AskSetuidSearchSubject("laptop"), func(msg *nats.Msg) { var signed SignedHandOver _ = json.Unmarshal(msg.Data, &signed) if ed25519.Verify(public, append([]byte(HandOverContext), signed.Ask...), signed.Signature) || !ed25519.Verify(public, append([]byte(SetuidSearchContext), signed.Ask...), signed.Signature) { _ = msg.Respond([]byte(`{"refused":"not signed as a setuid search"}`)) return } _ = json.Unmarshal(signed.Ask, &heard) body, _ := json.Marshal(HandOverAnswer{Said: "a new search starts, asked by " + heard.By}) _ = msg.Respond(body) }) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = engine.Unsubscribe() }) a, err := AskSetuidSearch(context.Background(), conn, signer, "laptop", "jo", 5*time.Second) if err != nil || a.Said != "a new search starts, asked by jo" { t.Fatalf("answered %+v, %v", a, err) } if heard.Node != "laptop" || heard.Path != "" || heard.Nonce == "" || heard.Expires.IsZero() { t.Fatalf("the engine heard %+v", heard) } if _, err := AskSetuidSearch(context.Background(), conn, signer, "anchor", "jo", 5*time.Second); err == nil || !strings.Contains(err.Error(), "no search was started") { t.Fatalf("a machine with no engine listening: %v", err) } }