feat: disable registration

This commit is contained in:
juancwu 2026-05-17 14:30:59 +00:00
commit 39330ce821
17 changed files with 179 additions and 132 deletions

View file

@ -27,7 +27,7 @@ func (s *stubSpaceAuditRepo) ListBySpace(_ string, limit, _ int) ([]*model.Space
}
return firstN(s.listSpace, limit), nil
}
func (s *stubSpaceAuditRepo) CountBySpace(string) (int, error) { return s.countSpace, s.err }
func (s *stubSpaceAuditRepo) CountBySpace(string) (int, error) { return s.countSpace, s.err }
func (s *stubSpaceAuditRepo) ListAccountEvents(_ string, limit, _ int) ([]*model.SpaceAuditLogWithActor, error) {
if s.err != nil {
return nil, s.err
@ -99,9 +99,9 @@ func TestAccountActivityService_List_MergesAndSortsByTimestamp(t *testing.T) {
}
txRepo := &stubTxAuditRepo{
listAccount: []*model.TransactionAuditLogWithActor{
txLog(model.TransactionAuditActionEdited, now), // newest overall
txLog(model.TransactionAuditActionEdited, now), // newest overall
txLog(model.TransactionAuditActionCreated, now.Add(-5*time.Minute)),
txLog(model.TransactionAuditActionDeleted, now.Add(-15*time.Minute)), // oldest overall
txLog(model.TransactionAuditActionDeleted, now.Add(-15*time.Minute)), // oldest overall
},
countAccount: 3,
}

View file

@ -20,15 +20,16 @@ import (
)
var (
ErrInvalidCredentials = errors.New("invalid email or password")
ErrNoPassword = errors.New("account uses passwordless login. Use magic link")
ErrPasswordsDoNotMatch = errors.New("passwords do not match")
ErrEmailAlreadyExists = errors.New("email already exists")
ErrWeakPassword = errors.New("password must be at least 12 characters")
ErrCommonPassword = errors.New("password is too common, please choose a stronger one")
ErrEmailNotVerified = errors.New("email not verified")
ErrInvalidEmail = errors.New("invalid email address")
ErrNameRequired = errors.New("name is required")
ErrInvalidCredentials = errors.New("invalid email or password")
ErrNoPassword = errors.New("account uses passwordless login. Use magic link")
ErrPasswordsDoNotMatch = errors.New("passwords do not match")
ErrEmailAlreadyExists = errors.New("email already exists")
ErrWeakPassword = errors.New("password must be at least 12 characters")
ErrCommonPassword = errors.New("password is too common, please choose a stronger one")
ErrEmailNotVerified = errors.New("email not verified")
ErrInvalidEmail = errors.New("invalid email address")
ErrNameRequired = errors.New("name is required")
ErrRegistrationDisabled = errors.New("registration is disabled")
)
type AuthService struct {
@ -41,6 +42,7 @@ type AuthService struct {
jwtExpiry time.Duration
tokenMagicLinkExpiry time.Duration
isProduction bool
disableRegistration bool
}
func NewAuthService(
@ -53,6 +55,7 @@ func NewAuthService(
jwtExpiry time.Duration,
tokenMagicLinkExpiry time.Duration,
isProduction bool,
disableRegistration bool,
) *AuthService {
return &AuthService{
emailService: emailService,
@ -64,6 +67,7 @@ func NewAuthService(
jwtExpiry: jwtExpiry,
tokenMagicLinkExpiry: tokenMagicLinkExpiry,
isProduction: isProduction,
disableRegistration: disableRegistration,
}
}
@ -235,6 +239,10 @@ func (s *AuthService) SendMagicLink(email string) error {
if err != nil {
// User doesn't exist - create a new passwordless account
if errors.Is(err, repository.ErrUserNotFound) {
if s.disableRegistration {
slog.Info("registration disabled, refusing to create new user", "email", email)
return ErrRegistrationDisabled
}
now := time.Now()
user = &model.User{
ID: uuid.NewString(),

View file

@ -30,6 +30,7 @@ func newTestAuthService(dbi testutil.DBInfo) *AuthService {
cfg.JWTExpiry,
cfg.TokenMagicLinkExpiry,
false,
false,
)
}

View file

@ -210,9 +210,9 @@ func TestFirstFireOnOrAfter_WeeklyShiftsToTargetDayOfWeek(t *testing.T) {
func TestAddMonths(t *testing.T) {
tests := []struct {
y int
m time.Month
n int
y int
m time.Month
n int
wy int
wm time.Month
}{

View file

@ -11,7 +11,7 @@ import (
)
type fakeSpaceAuditRepo struct {
created []*model.SpaceAuditLog
created []*model.SpaceAuditLog
failNext error
}

View file

@ -16,11 +16,11 @@ import (
// txnFixture builds a fully wired TransactionService against a real DB along with
// the helper repos the tests need to inspect post-state.
type txnFixture struct {
svc *TransactionService
txAudit repository.TransactionAuditLogRepository
accounts repository.AccountRepository
user *model.User
account *model.Account
svc *TransactionService
txAudit repository.TransactionAuditLogRepository
accounts repository.AccountRepository
user *model.User
account *model.Account
}
func newTxnFixture(t *testing.T, dbi testutil.DBInfo) *txnFixture {
@ -149,8 +149,8 @@ func TestTransactionService_UpdateDeposit_RebalancesAndDiffs(t *testing.T) {
assert.Equal(t, model.TransactionAuditActionEdited, logs[0].Action)
var meta struct {
AccountID string `json:"account_id"`
Changes map[string]map[string]any `json:"changes"`
AccountID string `json:"account_id"`
Changes map[string]map[string]any `json:"changes"`
}
require.NoError(t, json.Unmarshal(logs[0].Metadata, &meta))
assert.Equal(t, f.account.ID, meta.AccountID)