Harden email verification resend against abuse
Add a per-address confirmation-email cooldown and disable the resend/forgot-password submit buttons while the mutation is in flight so callers cannot flood the mail queue or double-submit. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -76,6 +76,11 @@ var SupportedIdentityLocales = []string{
|
||||
|
||||
const (
|
||||
TokenTypeEmailConfirmation = "email_confirmation"
|
||||
|
||||
// emailConfirmationResendCooldown is the minimum time between confirmation
|
||||
// emails for the same address. Resend requests inside this window succeed
|
||||
// without enqueueing another message (anti-enumeration + anti-abuse).
|
||||
emailConfirmationResendCooldown = time.Minute
|
||||
)
|
||||
|
||||
func NewAccountService(svc *Service) *AccountService {
|
||||
@@ -243,6 +248,20 @@ func (s AccountService) ResendVerificationEmail(ctx context.Context, email mail.
|
||||
return nil // Don't leak information about already-verified identities
|
||||
}
|
||||
|
||||
recent, err := coredata.ExistsByRecipientSubjectCreatedAfter(
|
||||
ctx,
|
||||
tx,
|
||||
identity.EmailAddress,
|
||||
emails.SubjectConfirmEmail,
|
||||
time.Now().Add(-emailConfirmationResendCooldown),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot check recent confirmation email: %w", err)
|
||||
}
|
||||
if recent {
|
||||
return nil // Cooldown: avoid flooding the recipient / mail queue
|
||||
}
|
||||
|
||||
confirmationToken, err := statelesstoken.NewToken(
|
||||
s.tokenSecret,
|
||||
TokenTypeEmailConfirmation,
|
||||
|
||||
Reference in New Issue
Block a user