Files
ttstd-infinite-canvas/backend/internal/auth/host.go

89 lines
2.4 KiB
Go

package auth
import (
"context"
"strings"
"sync"
"time"
"infinite-canvas/backend/internal/model"
"infinite-canvas/backend/internal/repository"
)
const DefaultBrandName = "影策"
// Host 由组合根注入,避免 auth → service 回环。
type Host interface {
RequireAdmin(user *model.User) error
EncryptSecret(value string) (string, error)
DecryptSecret(value string) (string, error)
SettingsEncryptionKey() ([]byte, error)
BrandName() string
EnsureSignupBonus(userID string) error
RecordActivity(userID string, event string, count int)
AllowRequest(ctx context.Context, key string, limit int, window time.Duration) (bool, error)
RequestRetryAfter(ctx context.Context, key string, window time.Duration) time.Duration
}
type nopHost struct{}
func (nopHost) RequireAdmin(user *model.User) error { return nil }
func (nopHost) EncryptSecret(value string) (string, error) {
return value, nil
}
func (nopHost) DecryptSecret(value string) (string, error) {
return value, nil
}
func (nopHost) SettingsEncryptionKey() ([]byte, error) { return nil, nil }
func (nopHost) BrandName() string { return DefaultBrandName }
func (nopHost) EnsureSignupBonus(string) error { return nil }
func (nopHost) RecordActivity(string, string, int) {}
func (nopHost) AllowRequest(context.Context, string, int, time.Duration) (bool, error) {
return true, nil
}
func (nopHost) RequestRetryAfter(context.Context, string, time.Duration) time.Duration {
return 0
}
type Service struct {
repo *repository.Repository
host Host
mailSender func(EmailSettingValue, string, string, string) error
emailCodeMu sync.Mutex
registrationMu sync.Mutex
sms SMSDelivery
}
type SMSDelivery interface {
Available(string) (bool, error)
SendCode(context.Context, string, string, string) error
}
func (s *Service) SetSMSDelivery(delivery SMSDelivery) { s.sms = delivery }
func New(repo *repository.Repository, host Host, mailSender func(EmailSettingValue, string, string, string) error) *Service {
if host == nil {
host = nopHost{}
}
return &Service{repo: repo, host: host, mailSender: mailSender}
}
func (s *Service) SetMailSender(fn func(EmailSettingValue, string, string, string) error) {
if s == nil {
return
}
s.mailSender = fn
}
type brandHost struct {
nopHost
name string
}
func (h brandHost) BrandName() string {
if strings.TrimSpace(h.name) == "" {
return DefaultBrandName
}
return h.name
}