package ai import ( "crypto/sha256" "encoding/base64" "path/filepath" "testing" "github.com/vstockwell/wraith/internal/db" "github.com/vstockwell/wraith/internal/settings" "github.com/vstockwell/wraith/internal/vault" ) func TestGenerateCodeVerifier(t *testing.T) { v, err := generateCodeVerifier() if err != nil { t.Fatalf("unexpected error: %v", err) } // 32 bytes -> 43 base64url chars (no padding) if len(v) != 43 { t.Errorf("expected verifier length 43, got %d", len(v)) } if !isBase64URL(v) { t.Errorf("verifier contains non-base64url characters: %s", v) } // Should be different each time v2, _ := generateCodeVerifier() if v == v2 { t.Error("two generated verifiers should not be identical") } } func TestGenerateCodeChallenge(t *testing.T) { verifier := "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" challenge := generateCodeChallenge(verifier) // Verify it matches a manually computed S256 hash h := sha256.Sum256([]byte(verifier)) expected := base64.RawURLEncoding.EncodeToString(h[:]) if challenge != expected { t.Errorf("expected challenge %s, got %s", expected, challenge) } // Same verifier should produce the same challenge (deterministic) challenge2 := generateCodeChallenge(verifier) if challenge != challenge2 { t.Error("challenge should be deterministic for the same verifier") } } func TestGenerateState(t *testing.T) { s, err := generateState() if err != nil { t.Fatalf("unexpected error: %v", err) } // 32 bytes -> 43 base64url chars (no padding) if len(s) != 43 { t.Errorf("expected state length 43, got %d", len(s)) } if !isBase64URL(s) { t.Errorf("state contains non-base64url characters: %s", s) } } func TestIsAuthenticatedWhenNoTokens(t *testing.T) { database, err := db.Open(filepath.Join(t.TempDir(), "test.db")) if err != nil { t.Fatalf("open db: %v", err) } if err := db.Migrate(database); err != nil { t.Fatalf("migrate: %v", err) } t.Cleanup(func() { database.Close() }) settingsSvc := settings.NewSettingsService(database) key := vault.DeriveKey("test-password", []byte("test-salt-1234567890123456789012")) vaultSvc := vault.NewVaultService(key) oauth := NewOAuthManager(settingsSvc, vaultSvc) if oauth.IsAuthenticated() { t.Error("expected IsAuthenticated to return false when no tokens are stored") } }