Help us shape the future of Go! Take the 2026 Go Developer Survey

mailauth

package
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 17 Imported by: 0

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

View Source
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.

View Source
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).

View Source
const ResetPath = "/reset-password"

ResetPath is the SPA route of the reset link.

Variables

View Source
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

func MaskEmail(addr string) string

MaskEmail hides most of the local part for display on a code prompt: "alice@example.com" -> "a***e@example.com".

func ValidateInput

func ValidateInput(in *SMTPInput) map[string]string

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

type RateLimitError struct{ Wait time.Duration }

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 New

func New(o Options) *Service

New returns a Service.

func (*Service) CheckResetToken

func (s *Service) CheckResetToken(ctx context.Context, token string) (*store.User, error)

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

func (s *Service) DefaultLocale(ctx context.Context) string

DefaultLocale returns the panel's e-mail language.

func (*Service) Email2FARequiredByPolicy

func (s *Service) Email2FARequiredByPolicy(ctx context.Context) (bool, error)

Email2FARequiredByPolicy reports the auth.require_email_2fa setting.

func (*Service) Enabled

func (s *Service) Enabled(ctx context.Context) bool

Enabled reports whether e-mail can be sent (an SMTP host is configured).

func (*Service) LoginFactorRequired

func (s *Service) LoginFactorRequired(ctx context.Context, u *store.User) (bool, error)

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

func (s *Service) PasswordResetAvailable(ctx context.Context) bool

PasswordResetAvailable reports whether "Forgot password?" works: SMTP is configured and the panel URL (for the link) is known.

func (*Service) RequestPasswordReset

func (s *Service) RequestPasswordReset(ctx context.Context, login, ip string)

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

func (s *Service) ResendLoginCode(ctx context.Context, u *store.User, ip string) error

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

func (s *Service) SMTP(ctx context.Context) (config.SMTPConfig, Source, error)

SMTP returns the effective SMTP configuration and its source. The configuration file / environment wins over the panel settings.

func (*Service) SaveStored

func (s *Service) SaveStored(ctx context.Context, in SMTPInput, actor *int64) error

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

func (s *Service) SendLoginCode(ctx context.Context, u *store.User, ip string) error

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) SendTest

func (s *Service) SendTest(ctx context.Context, addr, locale string) error

SendTest delivers the test message to addr (admin "Send test e-mail").

func (*Service) SendVerification

func (s *Service) SendVerification(ctx context.Context, u *store.User, ip string) error

SendVerification e-mails a verification code to the user's address.

func (*Service) VerifyLoginCode

func (s *Service) VerifyLoginCode(ctx context.Context, userID int64, code string) (bool, error)

VerifyLoginCode checks and consumes a sign-in code.

func (*Service) View

func (s *Service) View(ctx context.Context) (SMTPView, error)

View returns the effective configuration for display.

func (*Service) Wait

func (s *Service) Wait()

Wait blocks until background deliveries (password reset) finished (tests).

type Source

type Source string

Source tells where the effective SMTP configuration comes from.

const (
	SourceNone     Source = "none"
	SourceConfig   Source = "config"
	SourceSettings Source = "settings"
)

Sources.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL