package site import ( "context" "go.uber.org/zap" domainsite "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/site" "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/security/apikey" ) // AuthenticateAPIKeyUseCase handles API key authentication type AuthenticateAPIKeyUseCase struct { repo domainsite.Repository apiKeyHasher apikey.Hasher logger *zap.Logger } // ProvideAuthenticateAPIKeyUseCase creates a new AuthenticateAPIKeyUseCase func ProvideAuthenticateAPIKeyUseCase( repo domainsite.Repository, apiKeyHasher apikey.Hasher, logger *zap.Logger, ) *AuthenticateAPIKeyUseCase { return &AuthenticateAPIKeyUseCase{ repo: repo, apiKeyHasher: apiKeyHasher, logger: logger, } } // AuthenticateAPIKeyInput is the input for authenticating an API key type AuthenticateAPIKeyInput struct { APIKey string } // AuthenticateAPIKeyOutput is the output after authenticating an API key type AuthenticateAPIKeyOutput struct { Site *domainsite.Site } // Execute authenticates an API key and returns the associated site func (uc *AuthenticateAPIKeyUseCase) Execute(ctx context.Context, input *AuthenticateAPIKeyInput) (*AuthenticateAPIKeyOutput, error) { // Hash the API key apiKeyHash := uc.apiKeyHasher.Hash(input.APIKey) // Lookup site by API key hash (from sites_by_apikey table) site, err := uc.repo.GetByAPIKeyHash(ctx, apiKeyHash) if err != nil { uc.logger.Debug("API key authentication failed", zap.Error(err)) return nil, domainsite.ErrInvalidAPIKey } // Verify API key using constant-time comparison if !uc.apiKeyHasher.Verify(input.APIKey, site.APIKeyHash) { uc.logger.Warn("API key hash mismatch", zap.String("site_id", site.ID.String())) return nil, domainsite.ErrInvalidAPIKey } // Check if site can access API (allows pending sites for initial setup) if !site.CanAccessAPI() { uc.logger.Warn("site cannot access API", zap.String("site_id", site.ID.String()), zap.String("status", site.Status), zap.Bool("verified", site.IsVerified)) return nil, domainsite.ErrSiteNotActive } uc.logger.Debug("API key authenticated successfully", zap.String("site_id", site.ID.String()), zap.String("domain", site.Domain)) return &AuthenticateAPIKeyOutput{Site: site}, nil }