Documentation
¶
Overview ¶
Package mailauth implements the e-mail based account features on top of internal/mail: the effective SMTP configuration (environment/config file, or the panel settings with an AEAD-sealed password), address verification codes, the e-mail second factor (panel login and the RustDesk client /api/login "email_check" step) and password reset links.
Codes are 6 random digits, stored as sha256 bound to user and purpose, valid 10 minutes, invalidated after 5 wrong guesses and by a newer code. Sending is limited by a resend cooldown and hourly caps per user and per client IP (counted in email_codes, so limits survive restarts).
Index ¶
- Constants
- Variables
- func MaskEmail(addr string) string
- func ValidateInput(in *SMTPInput) map[string]string
- type Options
- type RateLimitError
- type SMTPInput
- type SMTPView
- type Service
- func (s *Service) CheckResetToken(ctx context.Context, token string) (*store.User, error)
- func (s *Service) ConfirmVerification(ctx context.Context, u *store.User, code string) (bool, error)
- func (s *Service) DefaultLocale(ctx context.Context) string
- func (s *Service) Email2FARequiredByPolicy(ctx context.Context) (bool, error)
- func (s *Service) Enabled(ctx context.Context) bool
- func (s *Service) LoginFactorRequired(ctx context.Context, u *store.User) (bool, error)
- func (s *Service) PasswordResetAvailable(ctx context.Context) bool
- func (s *Service) RequestPasswordReset(ctx context.Context, login, ip string)
- func (s *Service) ResendLoginCode(ctx context.Context, u *store.User, ip string) error
- func (s *Service) ResetPassword(ctx context.Context, token, hash, algo string) (*store.User, int64, error)
- func (s *Service) SMTP(ctx context.Context) (config.SMTPConfig, Source, error)
- func (s *Service) SaveStored(ctx context.Context, in SMTPInput, actor *int64) error
- func (s *Service) SendLoginCode(ctx context.Context, u *store.User, ip string) error
- func (s *Service) SendTest(ctx context.Context, addr, locale string) error
- func (s *Service) SendVerification(ctx context.Context, u *store.User, ip string) error
- func (s *Service) VerifyLoginCode(ctx context.Context, userID int64, code string) (bool, error)
- func (s *Service) View(ctx context.Context) (SMTPView, error)
- func (s *Service) Wait()
- type Source
Constants ¶
const ( CodeTTL = 10 * time.Minute ResetTTL = 30 * time.Minute MaxAttempts = 5 ResendCooldown = time.Minute // MaxPerUserHour caps e-mails sent to one user (all purposes) per hour. MaxPerUserHour = 10 // MaxPerIPHour caps e-mails triggered from one client IP per hour. MaxPerIPHour = 30 )
Tuning.
const ( // SettingSMTP holds the panel-managed SMTP server (storedSMTP); ignored // while the configuration (RDPANEL_SMTP_HOST / smtp.host) defines one. SettingSMTP = "mail.smtp" // SettingDefaultLocale is the e-mail language for users without one. SettingDefaultLocale = "mail.default_locale" // SettingRequireEmail2FA (bool): users without TOTP but with a verified // address must enter an e-mailed code at sign-in. SettingRequireEmail2FA = "auth.require_email_2fa" )
Settings keys (JSON values in the settings table).
const ResetPath = "/reset-password"
ResetPath is the SPA route of the reset link.
Variables ¶
var ( // ErrDisabled: no SMTP server is configured. ErrDisabled = errors.New("mailauth: e-mail is not configured") // ErrNoAddress: the user has no e-mail address. ErrNoAddress = errors.New("mailauth: user has no e-mail address") // ErrSend wraps delivery failures. ErrSend = errors.New("mailauth: could not send e-mail") // ErrInvalidToken: unknown, used or expired reset token. ErrInvalidToken = errors.New("mailauth: invalid or expired token") )
Errors.
Functions ¶
func MaskEmail ¶
MaskEmail hides most of the local part for display on a code prompt: "alice@example.com" -> "a***e@example.com".
func ValidateInput ¶
ValidateInput normalises in and returns per-field errors.
Types ¶
type Options ¶
type Options struct {
Store *store.Store
AEAD *crypto.AEAD
// Config supplies smtp.* and admin_url (reset links).
Config *config.Config
Log *slog.Logger
// NewSender builds the Sender for a configuration (default mail.NewSMTP).
NewSender func(config.SMTPConfig) rdmail.Sender
}
Options configure a Service.
type RateLimitError ¶
RateLimitError is returned when a send is refused by the cooldown or the hourly caps.
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
func (*RateLimitError) RetryAfter ¶
func (e *RateLimitError) RetryAfter() time.Duration
RetryAfter returns how long to wait before the next send.
type SMTPInput ¶
type SMTPInput struct {
Host string
Port int
Username string
// Password: nil keeps the stored one, "" clears it.
Password *string
From string
Encryption string
InsecureSkipVerify bool
}
SMTPInput is an update of the panel-managed SMTP configuration.
type SMTPView ¶
type SMTPView struct {
Source Source
Host string
Port int
Username string
PasswordSet bool
From string
Encryption string
InsecureSkipVerify bool
}
SMTPView is the SMTP configuration without the password (admin UI).
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service implements the e-mail features. Safe for concurrent use.
func (*Service) CheckResetToken ¶
CheckResetToken returns the user a reset token belongs to (ErrInvalidToken when it is unknown, used or expired).
func (*Service) ConfirmVerification ¶
func (s *Service) ConfirmVerification(ctx context.Context, u *store.User, code string) (bool, error)
ConfirmVerification marks the address verified when code matches and the address did not change since the code was sent.
func (*Service) DefaultLocale ¶
DefaultLocale returns the panel's e-mail language.
func (*Service) Email2FARequiredByPolicy ¶
Email2FARequiredByPolicy reports the auth.require_email_2fa setting.
func (*Service) LoginFactorRequired ¶
LoginFactorRequired reports whether u must enter an e-mailed code at sign-in. Callers check TOTP first (TOTP wins). The factor needs a verified address and a configured SMTP server: when e-mail is not configured it is not enforced (an administrator removed the server).
func (*Service) PasswordResetAvailable ¶
PasswordResetAvailable reports whether "Forgot password?" works: SMTP is configured and the panel URL (for the link) is known.
func (*Service) RequestPasswordReset ¶
RequestPasswordReset e-mails a reset link to the account named by login (username, or e-mail address of up to 5 accounts) when it is active, has a password, may use password sign-in and has a verified address. The lookup and delivery run in the background so the caller's response does not depend on whether the account exists.
func (*Service) ResendLoginCode ¶
ResendLoginCode e-mails a fresh sign-in code (subject to the cooldown).
func (*Service) ResetPassword ¶
func (s *Service) ResetPassword(ctx context.Context, token, hash, algo string) (*store.User, int64, error)
ResetPassword consumes token, stores the new password hash and revokes every session and client token of the user. It returns the user and the number of revoked tokens.
func (*Service) SMTP ¶
SMTP returns the effective SMTP configuration and its source. The configuration file / environment wins over the panel settings.
func (*Service) SaveStored ¶
SaveStored stores the panel-managed SMTP configuration (an empty Host removes it). It refuses while the configuration file / environment defines the server.
func (*Service) SendLoginCode ¶
SendLoginCode e-mails a sign-in code. A code sent less than a minute ago that is still valid is reused (no new e-mail).
func (*Service) SendVerification ¶
SendVerification e-mails a verification code to the user's address.
func (*Service) VerifyLoginCode ¶
VerifyLoginCode checks and consumes a sign-in code.