package authsnapshot import ( "crypto/ed25519" "crypto/rand" "encoding/base64" "testing" "time" ) func signedFixture(t *testing.T, now time.Time) (Signed, Keyring) { t.Helper() public, private, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } encodedKey := base64.RawURLEncoding.EncodeToString(make([]byte, 32)) payload := Payload{ SnapshotVersion: 1, TenantID: "tenant_0123456789abcdef0123456789abcdef", TenantStatus: "active", HomeRegion: "cn-east", RelayNodeID: "node_east_1", PlacementGeneration: 2, AuthorizationRevision: 7, Devices: []Device{{ DeviceID: "host_0123456789abcdef0123456789abcdef", CredentialHash: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", IdentityFingerprint: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Ed25519Public: encodedKey, X25519Public: encodedKey, Name: "Laptop", OS: "windows", }}, Phones: []Phone{{ PhoneID: "phone_0123456789abcdef", CredentialHash: "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", IdentityFingerprint: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Ed25519Public: encodedKey, X25519Public: encodedKey, Name: "Phone", }}, IssuedAt: now.Format(time.RFC3339Nano), ExpiresAt: now.Add(MaxTTL).Format(time.RFC3339Nano), } message, err := SigningBytes(payload) if err != nil { t.Fatal(err) } return Signed{ Algorithm: "Ed25519", KID: "key-1", Payload: payload, Signature: base64.RawURLEncoding.EncodeToString(ed25519.Sign(private, message)), }, Keyring{"key-1": {PublicKey: public, NotBefore: now.Add(-time.Hour), RetainUntil: now.Add(MaxTTL)}} } func TestVerifyAcceptsPinnedCurrentSnapshot(t *testing.T) { now := time.Date(2026, 8, 12, 10, 0, 0, 0, time.UTC) snapshot, keys := signedFixture(t, now) payload, err := Verify(snapshot, keys, now) if err != nil || payload.TenantID != snapshot.Payload.TenantID { t.Fatalf("payload=%#v err=%v", payload, err) } } func TestVerifyRejectsTamperingExpiryAndInsufficientKeyOverlap(t *testing.T) { now := time.Date(2026, 8, 12, 10, 0, 0, 0, time.UTC) snapshot, keys := signedFixture(t, now) tampered := snapshot tampered.Payload.AuthorizationRevision++ if _, err := Verify(tampered, keys, now); err == nil { t.Fatal("tampered snapshot accepted") } if _, err := Verify(snapshot, keys, now.Add(MaxTTL)); err == nil { t.Fatal("expired snapshot accepted") } key := keys["key-1"] key.RetainUntil = now.Add(MaxTTL - time.Second) keys["key-1"] = key if _, err := Verify(snapshot, keys, now); err == nil { t.Fatal("key without full TTL overlap accepted") } }