MCPcopy Create free account
hub / github.com/bytebase/bytebase / sendEmailVerificationCode

Method sendEmailVerificationCode

backend/api/v1/auth_service.go:1713–1779  ·  view source on GitHub ↗

sendEmailVerificationCode generates a code, atomically stores its hash (subject to cooldown), and emails the plain code. Returns nil on a successful send as well as on silent-skip paths (cooldown active, or PASSWORD_RESET for an unknown email) — both are intentionally indistinguishable to the caller

(ctx context.Context, workspaceName *string, email string, purpose storepb.EmailVerificationCodePurpose, subject, bodyFmt string)

Source from the content-addressed store, hash-verified

1711// to know email delivery failed), `RequestPasswordReset` swallows it to avoid revealing that
1712// the account exists. `bodyFmt` must contain one %s for the 6-digit code.
1713func (s *AuthService) sendEmailVerificationCode(ctx context.Context, workspaceName *string, email string, purpose storepb.EmailVerificationCodePurpose, subject, bodyFmt string) error {
1714 // For password reset, only send to existing principals — no upsert, no email for unknown addresses.
1715 // Prevents arbitrary email spam. LOGIN intentionally skips this check (also covers signup).
1716 if purpose == storepb.EmailVerificationCodePurpose_PASSWORD_RESET {
1717 account, err := s.store.GetAccountByEmail(ctx, email)
1718 if err != nil {
1719 return errors.Wrap(err, "failed to look up account for password reset")
1720 }
1721 if account == nil || account.Type != storepb.PrincipalType_END_USER {
1722 return nil // silent: account doesn't exist
1723 }
1724 }
1725
1726 workspaceID, err := parseOptionalWorkspace(workspaceName)
1727 if err != nil {
1728 return errors.Wrap(err, "failed to parse workspace id")
1729 }
1730
1731 // Resolve the EMAIL setting FIRST — fail fast if misconfigured so we don't write a
1732 // verification row we can't actually deliver.
1733 emailSetting, err := resolvePreLoginEmailSetting(ctx, s.store, workspaceID)
1734 if err != nil {
1735 return err
1736 }
1737 if emailSetting == nil {
1738 return errors.Errorf("cannot found email config for workspace %v", workspaceID)
1739 }
1740
1741 code, err := generateEmailCode()
1742 if err != nil {
1743 return errors.Wrap(err, "failed to generate code")
1744 }
1745
1746 now := time.Now()
1747 sent, err := s.store.UpsertEmailVerificationCodeIfCooldownExpired(ctx, &store.EmailVerificationCodeMessage{
1748 Email: email,
1749 Purpose: purpose,
1750 CodeHash: s.hashEmailCode(code),
1751 ExpiresAt: now.Add(emailCodeExpiry),
1752 LastSentAt: now,
1753 Workspace: workspaceID,
1754 }, emailCodeResendCooldown)
1755 if err != nil {
1756 return errors.Wrap(err, "failed to upsert verification code")
1757 }
1758 if !sent {
1759 return nil // cooldown active — silent skip
1760 }
1761
1762 sender, err := mailer.NewSender(emailSetting)
1763 if err != nil {
1764 return errors.Wrap(err, "failed to create mail sender")
1765 }
1766
1767 body := fmt.Sprintf(bodyFmt, code, int(emailCodeExpiry.Minutes()))
1768 if err := sender.Send(ctx, &mailer.SendRequest{
1769 To: []string{email},
1770 Subject: subject,

Callers 2

RequestPasswordResetMethod · 0.95
SendEmailLoginCodeMethod · 0.95

Calls 10

hashEmailCodeMethod · 0.95
SendMethod · 0.95
NewSenderFunction · 0.92
parseOptionalWorkspaceFunction · 0.85
generateEmailCodeFunction · 0.85
GetAccountByEmailMethod · 0.80
ErrorfMethod · 0.80

Tested by

no test coverage detected