Drop resend verification email cooldown
Resend only runs after an explicit form submit, so a per-address cooldown is unnecessary overhead compared with forgot-password. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -100,7 +100,7 @@ func NewPresenter(baseURL string, fullName string) *Presenter {
|
||||
}
|
||||
|
||||
const (
|
||||
SubjectConfirmEmail = "Confirm your email address"
|
||||
subjectConfirmEmail = "Confirm your email address"
|
||||
subjectPasswordReset = "Reset your password"
|
||||
subjectInvitation = "Invitation to join %s on Probo"
|
||||
subjectDocumentApproval = "Action Required – Please review and approve %s compliance documents"
|
||||
@@ -185,7 +185,7 @@ func (p *Presenter) RenderConfirmEmail(ctx context.Context, confirmationURLPath
|
||||
|
||||
textBody, htmlBody, err = renderEmail(confirmEmailTextTemplate, confirmEmailHTMLTemplate, data)
|
||||
|
||||
return SubjectConfirmEmail, textBody, htmlBody, err
|
||||
return subjectConfirmEmail, textBody, htmlBody, err
|
||||
}
|
||||
|
||||
func (p *Presenter) RenderPasswordReset(ctx context.Context, resetPasswordURLPath string, resetPasswordToken string) (subject string, textBody string, htmlBody *string, err error) {
|
||||
|
||||
@@ -319,39 +319,6 @@ WHERE id = @id
|
||||
return err
|
||||
}
|
||||
|
||||
// ExistsByRecipientSubjectCreatedAfter reports whether an email with the given
|
||||
// recipient and subject was created at or after createdAfter.
|
||||
func ExistsByRecipientSubjectCreatedAfter(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
recipientEmail mail.Addr,
|
||||
subject string,
|
||||
createdAfter time.Time,
|
||||
) (bool, error) {
|
||||
q := `
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM emails
|
||||
WHERE recipient_email = @recipient_email
|
||||
AND subject = @subject
|
||||
AND created_at >= @created_after
|
||||
)
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"recipient_email": recipientEmail.String(),
|
||||
"subject": subject,
|
||||
"created_after": createdAfter,
|
||||
}
|
||||
|
||||
var exists bool
|
||||
if err := conn.QueryRow(ctx, q, args).Scan(&exists); err != nil {
|
||||
return false, fmt.Errorf("cannot check recent email: %w", err)
|
||||
}
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func ResetStaleProcessingEmails(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
|
||||
@@ -76,11 +76,6 @@ 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 {
|
||||
@@ -248,20 +243,6 @@ 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