75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
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
|
|
}
|