Documentation
¶
Overview ¶
Package auth implements credential primitives: password hashing and verification (argon2id, bcrypt, legacy rustdesk-api md5), client JWTs, opaque session tokens, TOTP, recovery codes and login rate limiting.
Index ¶
- Constants
- Variables
- func BearerToken(header string) (string, bool)
- func HashRecoveryCode(code string) []byte
- func IsAPIToken(s string) bool
- func NormalizeRecoveryCode(code string) string
- func TOTPCode(secret string, t time.Time) (string, error)
- func ValidateTOTP(secret, code string, now time.Time, lastStep int64) (int64, error)
- type Algo
- type Argon2Params
- type Backoff
- type BackoffConfig
- type ClientClaims
- type ClientJWT
- type Hasher
- type Limiter
- type OpaqueToken
- type RecoveryCode
- type TOTPKey
Constants ¶
const ( APITokenPrefix = "rdp_" // APITokenLen is the length of a well-formed API token. APITokenLen = len(APITokenPrefix) + apiTokenChars // APITokenDisplayLen is how many leading characters are kept for display. APITokenDisplayLen = len(APITokenPrefix) + 6 )
Personal API tokens: "rdp_" followed by apiTokenChars base62 characters (~238 bits of entropy).
const MaxPasswordBytes = 1024
MaxPasswordBytes bounds password input to keep hashing cost predictable. It is far above anything a human types; there is no 32-char cap (legacy bug).
const RecoveryCodeCount = 10
RecoveryCodeCount is the number of codes issued per enrolment.
Variables ¶
var DefaultArgon2Params = Argon2Params{Memory: 64 * 1024, Time: 2, Threads: 2, SaltLen: 16, KeyLen: 32}
DefaultArgon2Params follow the OWASP/RFC 9106 guidance for interactive logins on a small server (64 MiB, 2 passes, 2 lanes).
var DefaultBackoffConfig = BackoffConfig{Free: 3, Base: time.Second, Max: 15 * time.Minute, Forget: time.Hour}
DefaultBackoffConfig: 3 free attempts, then 1s, 2s, 4s ... capped at 15 min.
var ErrEmptyPassword = errors.New("auth: empty password")
ErrEmptyPassword is returned by Hash for an empty password.
var ErrInvalidToken = errors.New("auth: invalid token")
ErrInvalidToken is returned for any malformed, mis-signed or expired token.
var ErrPasswordTooLong = errors.New("auth: password too long")
ErrPasswordTooLong is returned by Hash for inputs above MaxPasswordBytes.
var ErrTOTPInvalid = errors.New("auth: invalid TOTP code")
ErrTOTPInvalid is returned for a wrong, malformed or replayed code.
Functions ¶
func BearerToken ¶
BearerToken extracts the token from an Authorization header value. The scheme must be "Bearer" (case-insensitive) followed by a single space and a non-empty token; anything else yields "", false.
func HashRecoveryCode ¶
HashRecoveryCode returns the digest stored in recovery_codes.code_sha256.
func IsAPIToken ¶ added in v0.4.0
IsAPIToken reports whether s is a well-formed personal API token.
func NormalizeRecoveryCode ¶
NormalizeRecoveryCode lowercases and strips separators/whitespace so users may type codes with or without dashes.
func ValidateTOTP ¶
ValidateTOTP checks code against secret at time now, allowing ±1 step of clock skew. lastStep is the last step accepted for this user (0 if none); a code whose step is <= lastStep is rejected as a replay. On success the matched step is returned and must be persisted as the new lastStep.
Types ¶
type Algo ¶
type Algo string
Algo identifies a stored password hash format. Values match users.password_algo.
type Argon2Params ¶
type Argon2Params struct {
Memory uint32 // KiB
Time uint32
Threads uint8
SaltLen uint32
KeyLen uint32
}
Argon2Params are the argon2id cost parameters for new hashes.
type Backoff ¶
type Backoff struct {
// contains filtered or unexported fields
}
Backoff is an in-memory Limiter with per-key exponential backoff.
func NewBackoff ¶
func NewBackoff(cfg BackoffConfig, now func() time.Time) *Backoff
NewBackoff returns an in-memory exponential backoff limiter. now may be nil.
func (*Backoff) Prune ¶
func (b *Backoff) Prune()
Prune removes keys whose history is older than Forget.
type BackoffConfig ¶
type BackoffConfig struct {
// Free is the number of failures tolerated before any delay applies.
Free int
// Base is the delay after the first failure beyond Free; it doubles with
// every further failure.
Base time.Duration
// Max caps the delay.
Max time.Duration
// Forget drops a key's history after this long without failures.
Forget time.Duration
}
BackoffConfig parameterises Backoff.
type ClientClaims ¶
type ClientClaims struct {
UserID uint32 `json:"user_id"`
jwt.RegisteredClaims
}
ClientClaims are the claims of a RustDesk client token. The JSON shape is exactly {"user_id": <u32>, "exp": <unix seconds>}, matching legacy rustdesk-api and the Rust `Claims { user_id: u32, exp: usize }` that hbbs verifies with `jsonwebtoken` (HS256, exp required) when MUST_LOGIN is on.
func ParseUnverified ¶
func ParseUnverified(token string) (ClientClaims, error)
ParseUnverified extracts claims without checking the signature or expiry. Only for the legacy importer (classifying old tokens); never for auth.
type ClientJWT ¶
type ClientJWT struct {
// contains filtered or unexported fields
}
ClientJWT mints and verifies client JWTs with the shared HS256 key (RUSTDESK_API_JWT_KEY, raw bytes).
func NewClientJWT ¶
NewClientJWT returns a ClientJWT for key. now may be nil (time.Now).
type Hasher ¶
type Hasher struct {
Params Argon2Params
}
Hasher hashes and verifies passwords.
func (*Hasher) NeedsRehash ¶
NeedsRehash reports whether a (successfully verified) hash should be replaced by a fresh argon2id hash with the current parameters.
type Limiter ¶
type Limiter interface {
// Allow reports whether an attempt for key may proceed now. When it may
// not, retryAfter is how long the caller must wait.
Allow(key string) (ok bool, retryAfter time.Duration)
// Failure records a failed attempt, extending the backoff for key.
Failure(key string)
// Success clears the failure history for key.
Success(key string)
}
Limiter throttles repeated failures per key (e.g. "ip:1.2.3.4", "user:alice"). Implementations must be safe for concurrent use; the in-memory Backoff can later be swapped for a shared store.
type OpaqueToken ¶
type OpaqueToken struct {
// Plain is handed to the client exactly once (cookie, URL, ...).
Plain string
// Hash is sha256(Plain), the only form persisted.
Hash []byte
}
OpaqueToken is a freshly generated bearer secret and its storage digest.
func NewAPIToken ¶ added in v0.4.0
func NewAPIToken() (OpaqueToken, error)
NewAPIToken generates a personal API token and its sha256 digest.
func NewOpaqueToken ¶
func NewOpaqueToken() (OpaqueToken, error)
NewOpaqueToken generates a random 256-bit token (unpadded base64url) for panel sessions, CSRF secrets, share links and OAuth states.
type RecoveryCode ¶
type RecoveryCode struct {
// Plain is shown to the user once, formatted "xxxx-xxxx-xxxx-xxxx".
Plain string
// Hash is sha256 of the normalised code (80 bits of entropy, so a fast
// hash is sufficient).
Hash []byte
}
RecoveryCode is a one-time 2FA bypass code and its storage digest.
func GenerateRecoveryCodes ¶
func GenerateRecoveryCodes(n int) ([]RecoveryCode, error)
GenerateRecoveryCodes returns n fresh recovery codes.
type TOTPKey ¶
type TOTPKey struct {
// Secret is the base32 seed; store it AEAD-encrypted.
Secret string
// URL is the otpauth:// URI to render as a QR code.
URL string
}
TOTPKey is a newly generated TOTP secret for enrolment.
func GenerateTOTP ¶
GenerateTOTP creates a new TOTP seed for account (usually the username).