package admincrypto import ( "crypto/ed25519" "crypto/rand" "encoding/base64" "os" "path/filepath" "testing" ) // generateTestSigner creates a fresh Ed25519 Signer for testing. func generateTestSigner() (*Signer, error) { pub, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, err } return &Signer{priv: priv, pub: pub, KeyID: "v1"}, nil } func TestSigner_SignAndVerify(t *testing.T) { signer, err := generateTestSigner() if err != nil { t.Fatalf("generate signer: %v", err) } msg := []byte(`{"event_uri":"at://test","label":"CascadiaJS"}`) sig := signer.Sign(msg) if sig == "" { t.Fatal("Sign returned empty string") } if !signer.Verify(msg, sig) { t.Error("Verify returned false for valid signature") } } func TestSigner_VerifyRejectsModifiedMessage(t *testing.T) { signer, _ := generateTestSigner() msg := []byte(`{"test":"original"}`) sig := signer.Sign(msg) modified := []byte(`{"test":"modified"}`) if signer.Verify(modified, sig) { t.Error("Verify returned true for modified message") } } func TestSigner_VerifyRejectsModifiedSignature(t *testing.T) { signer, _ := generateTestSigner() msg := []byte(`{"test":"data"}`) sig := signer.Sign(msg) // Flip a character in the base64 signature. tampered := []byte(sig) if tampered[10] == 'A' { tampered[10] = 'B' } else { tampered[10] = 'A' } if signer.Verify(msg, string(tampered)) { t.Error("Verify returned true for tampered signature") } } func TestSigner_VerifyRejectsInvalidBase64(t *testing.T) { signer, _ := generateTestSigner() msg := []byte("test") if signer.Verify(msg, "not-valid-base64!@#$%") { t.Error("Verify returned true for invalid base64") } } func TestSigner_NilSafety(t *testing.T) { var s *Signer // Sign on nil signer returns empty. if got := s.Sign([]byte("test")); got != "" { t.Errorf("nil Sign = %q; want empty", got) } // Verify on nil signer returns false. if s.Verify([]byte("test"), "sig") { t.Error("nil Verify returned true") } // PublicKeyBase64 on nil returns empty. if got := s.PublicKeyBase64(); got != "" { t.Errorf("nil PublicKeyBase64 = %q; want empty", got) } } func TestSigner_KeyID(t *testing.T) { signer, _ := generateTestSigner() if signer.KeyID != "v1" { t.Errorf("KeyID = %q; want 'v1'", signer.KeyID) } } func TestSigner_PublicKeyBase64NotEmpty(t *testing.T) { signer, _ := generateTestSigner() pub := signer.PublicKeyBase64() if pub == "" { t.Error("PublicKeyBase64 is empty for valid signer") } } func TestSigner_DifferentSignersProduceDifferentSigs(t *testing.T) { s1, _ := generateTestSigner() s2, _ := generateTestSigner() msg := []byte("same message") sig1 := s1.Sign(msg) sig2 := s2.Sign(msg) if sig1 == sig2 { t.Error("different signers produced identical signatures") } // Cross-verify should fail. if s1.Verify(msg, sig2) { t.Error("signer 1 verified signer 2's signature") } if s2.Verify(msg, sig1) { t.Error("signer 2 verified signer 1's signature") } } func TestLoad_FromEnvVar(t *testing.T) { signer, _ := generateTestSigner() seed := signer.priv.Seed() encoded := base64.StdEncoding.EncodeToString(seed) t.Setenv("ADMIN_SIGNING_KEY", encoded) loaded, err := Load(false) if err != nil { t.Fatalf("Load from env: %v", err) } if loaded.PublicKeyBase64() != signer.PublicKeyBase64() { t.Error("loaded signer has different public key than original") } } func TestLoad_InvalidBase64InEnv(t *testing.T) { t.Setenv("ADMIN_SIGNING_KEY", "not-valid-base64!@#$") _, err := Load(false) if err == nil { t.Error("expected error for invalid base64 in env var") } } func TestLoad_WrongSizeInEnv(t *testing.T) { // 16 bytes instead of 32. t.Setenv("ADMIN_SIGNING_KEY", base64.StdEncoding.EncodeToString(make([]byte, 16))) _, err := Load(false) if err == nil { t.Error("expected error for wrong size key in env var") } } func TestLoad_NoKeyDisallowGenerate(t *testing.T) { t.Setenv("ADMIN_SIGNING_KEY", "") // Use a working dir that definitely has no key file. origDir, _ := os.Getwd() _ = os.Chdir(t.TempDir()) defer func() { _ = os.Chdir(origDir) }() _, err := Load(false) if err == nil { t.Error("expected error when no key and generate=false") } } func TestLoad_AllowGenerateCreatesKeyFile(t *testing.T) { t.Setenv("ADMIN_SIGNING_KEY", "") origDir, _ := os.Getwd() tmpDir := t.TempDir() _ = os.Chdir(tmpDir) defer func() { _ = os.Chdir(origDir) }() signer, err := Load(true) if err != nil { t.Fatalf("Load(generate=true): %v", err) } if signer == nil { t.Fatal("signer is nil") } // Key file should exist. keyPath := filepath.Join(tmpDir, "data", "admin_signing.key") if _, err := os.Stat(keyPath); os.IsNotExist(err) { t.Error("key file was not created") } // Loading again should produce the same key. signer2, err := Load(false) if err != nil { t.Fatalf("Load(reload): %v", err) } if signer2.PublicKeyBase64() != signer.PublicKeyBase64() { t.Error("reloaded signer has different public key") } } func TestLoad_FromFile(t *testing.T) { t.Setenv("ADMIN_SIGNING_KEY", "") origDir, _ := os.Getwd() tmpDir := t.TempDir() _ = os.Chdir(tmpDir) defer func() { _ = os.Chdir(origDir) }() // Write a known seed. _, priv, _ := ed25519.GenerateKey(rand.Reader) keyDir := filepath.Join(tmpDir, "data") _ = os.MkdirAll(keyDir, 0o700) _ = os.WriteFile(filepath.Join(keyDir, "admin_signing.key"), priv.Seed(), 0o600) signer, err := Load(false) if err != nil { t.Fatalf("Load from file: %v", err) } if signer == nil { t.Fatal("signer is nil") } // The public key should match what we seeded. expectedPub := priv.Public().(ed25519.PublicKey) if signer.PublicKeyBase64() != base64.StdEncoding.EncodeToString(expectedPub) { t.Error("loaded signer has wrong public key") } }