monorepo/cloud/maplepress-backend/internal/usecase/site/verify.go

132 lines
3.8 KiB
Go

package site
import (
"context"
"fmt"
"github.com/gocql/gocql"
"go.uber.org/zap"
domainsite "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/site"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/dns"
)
// VerifySiteUseCase handles site verification business logic
type VerifySiteUseCase struct {
repo domainsite.Repository
dnsVerifier *dns.Verifier
logger *zap.Logger
}
// ProvideVerifySiteUseCase creates a new VerifySiteUseCase
func ProvideVerifySiteUseCase(
repo domainsite.Repository,
dnsVerifier *dns.Verifier,
logger *zap.Logger,
) *VerifySiteUseCase {
return &VerifySiteUseCase{
repo: repo,
dnsVerifier: dnsVerifier,
logger: logger,
}
}
// VerifySiteInput is the input for verifying a site
// No input fields needed - verification is done via DNS TXT record lookup
type VerifySiteInput struct {
// Empty struct - DNS verification uses the token stored in the site entity
}
// VerifySiteOutput is the output after verifying a site
type VerifySiteOutput struct {
Success bool `json:"success"`
Status string `json:"status"`
Message string `json:"message"`
}
// Execute verifies a site using the verification token
func (uc *VerifySiteUseCase) Execute(
ctx context.Context,
tenantID gocql.UUID,
siteID gocql.UUID,
input *VerifySiteInput,
) (*VerifySiteOutput, error) {
uc.logger.Info("executing verify site use case via DNS",
zap.String("tenant_id", tenantID.String()),
zap.String("site_id", siteID.String()))
// Get site from repository
site, err := uc.repo.GetByID(ctx, tenantID, siteID)
if err != nil {
uc.logger.Error("failed to get site", zap.Error(err))
return nil, domainsite.ErrSiteNotFound
}
// Check if site is already verified
if site.IsVerified {
uc.logger.Info("site already verified",
zap.String("site_id", siteID.String()))
return &VerifySiteOutput{
Success: true,
Status: site.Status,
Message: "Site is already verified",
}, nil
}
// Test mode sites don't need verification
if site.IsTestMode() {
uc.logger.Info("test mode site, skipping DNS verification",
zap.String("site_id", siteID.String()))
site.Verify()
if err := uc.repo.Update(ctx, site); err != nil {
uc.logger.Error("failed to update site", zap.Error(err))
return nil, fmt.Errorf("failed to update site: %w", err)
}
return &VerifySiteOutput{
Success: true,
Status: site.Status,
Message: "Test mode site verified successfully",
}, nil
}
// Perform DNS TXT record verification
uc.logger.Info("performing DNS verification",
zap.String("site_id", siteID.String()),
zap.String("domain", site.Domain),
zap.String("expected_token", site.VerificationToken))
verified, err := uc.dnsVerifier.VerifyDomainOwnership(ctx, site.Domain, site.VerificationToken)
if err != nil {
uc.logger.Error("DNS verification failed",
zap.String("site_id", siteID.String()),
zap.String("domain", site.Domain),
zap.Error(err))
return nil, fmt.Errorf("DNS verification failed: %w", err)
}
if !verified {
uc.logger.Warn("DNS verification record not found",
zap.String("site_id", siteID.String()),
zap.String("domain", site.Domain))
return nil, fmt.Errorf("DNS TXT record not found. Please add the verification record to your domain's DNS settings")
}
// DNS verification successful - mark site as verified
site.Verify()
// Update in repository
if err := uc.repo.Update(ctx, site); err != nil {
uc.logger.Error("failed to update site", zap.Error(err))
return nil, fmt.Errorf("failed to update site: %w", err)
}
uc.logger.Info("site verified successfully via DNS",
zap.String("site_id", siteID.String()),
zap.String("domain", site.Domain))
return &VerifySiteOutput{
Success: true,
Status: site.Status,
Message: "Domain ownership verified successfully via DNS TXT record",
}, nil
}