Documentation
¶
Index ¶
- Constants
- Variables
- func ClientIP(r *http.Request, trusted []netip.Prefix) string
- func GenerateRecoveryCodes(count int) (plainCodes []string, hashedJSON string, err error)
- func GenerateTOTPSecret() (string, error)
- func GenerateTOTPURL(issuer, accountName, secret string) string
- func RateKey(ip string) string
- func RedeemRecoveryCode(candidateCode, hashedJSON string) (string, bool)
- func TrustedPeer(r *http.Request, trusted []netip.Prefix) bool
- func ValidateCSRF(r *http.Request) bool
- func ValidateEmail(email string) error
- func ValidatePassword(password string) error
- func ValidateTOTP(secret, code string) (int64, bool)
- func ValidateUsername(username string) error
- type PoWChallenge
- type PoWSolution
- type PoWVerifier
- type SessionManager
- func (sm *SessionManager) AuthenticateRequest(r *http.Request) (*store.User, *store.Session, error)
- func (sm *SessionManager) IssueSSOSession(ctx context.Context, w http.ResponseWriter, r *http.Request, user *store.User, ...) (*store.Session, string, error)
- func (sm *SessionManager) IssueSession(ctx context.Context, w http.ResponseWriter, r *http.Request, user *store.User) (*store.Session, string, error)
- func (sm *SessionManager) RevokeSession(ctx context.Context, w http.ResponseWriter, r *http.Request) error
Constants ¶
const ( SessionCookieName = "ky_session" CSRFCookieName = "ky_csrf" HeaderCSRF = "X-CSRF-Token" )
Variables ¶
var ( ErrPasswordTooShort = errors.New("password must be at least 12 characters") ErrInvalidUsername = errors.New("username must be 3-64 alphanumeric characters, underscores, or hyphens") ErrInvalidEmail = errors.New("invalid email address format") )
var ErrPasswordChangeRequired = errors.New("password change required")
Functions ¶
func ClientIP ¶
ClientIP returns the address a request should be attributed to: the rate limiter's key and the IP bound into a session. Both must agree, or a caller could be throttled as one client and recorded as another.
trusted is the parsed KY_TRUSTED_PROXIES allowlist. It is empty by default, and then the peer address is the answer and every header is ignored: X-Forwarded-For is caller-supplied, so honouring it unconditionally lets anyone mint a fresh limiter bucket per request.
When the peer is a trusted proxy, X-Forwarded-For is walked from the right, skipping entries that are themselves trusted proxies, and the first untrusted entry wins. Everything to its left was appended by a hop we do not trust and may be forged. An entry that does not parse as an IP ends the walk and the peer is used, since the rest of the chain sits behind something that is not speaking the protocol.
X-Real-IP is ignored outright. It carries no chain, so it cannot be walked; a deployment that needs a client IP must forward X-Forwarded-For.
func GenerateRecoveryCodes ¶
GenerateRecoveryCodes returns count one-time codes and the JSON array of digests to store in users.recovery_codes_hash.
func GenerateTOTPSecret ¶
GenerateTOTPSecret returns a fresh base32 RFC 6238 secret.
func GenerateTOTPURL ¶
GenerateTOTPURL returns the otpauth:// URI an authenticator app enrols from.
func RateKey ¶
RateKey groups a ClientIP result for rate limiting: an IPv6 address counts as its /64, since one host is routinely handed a whole /64 and could otherwise rotate through 2^64 fresh limiter windows. IPv4 and unparsable values pass through.
func RedeemRecoveryCode ¶
RedeemRecoveryCode matches what the user typed against the stored digests and blanks the matching slot in place. Removing the entry instead renumbers the list, which is how two concurrent redemptions lose one another's write under the store's compare-and-swap.
func TrustedPeer ¶
TrustedPeer applies the same transport-peer rule as ClientIP when interpreting the forwarded scheme for the installer's public network self-check.
func ValidateCSRF ¶
func ValidateEmail ¶
ValidateEmail checks email syntax if provided.
func ValidatePassword ¶
ValidatePassword ensures password satisfies standard KySecurity length policy (>= 12 chars).
func ValidateTOTP ¶
ValidateTOTP reports whether code is valid for secret now, and the counter it matched. The caller must spend the counter with UserStore.SpendTOTPCounter before trusting it.
func ValidateUsername ¶
ValidateUsername checks username syntax.
Types ¶
type PoWChallenge ¶
type PoWChallenge struct {
Algorithm string `json:"algorithm"`
Salt string `json:"salt"`
Challenge string `json:"challenge"`
MaxNumber int `json:"maxnumber"`
ExpiresAt int64 `json:"expires_at"`
Signature string `json:"signature"`
}
PoWChallenge represents a client-side SHA256 puzzle matching the KySecurity standard.
func GeneratePoWChallenge ¶
func GeneratePoWChallenge(difficulty int, signingSecret string) (*PoWChallenge, error)
GeneratePoWChallenge creates a puzzle of given difficulty (e.g. 5000 to 50000 max iterations).
type PoWSolution ¶
type PoWSolution struct {
Algorithm string `json:"algorithm"`
Salt string `json:"salt"`
Challenge string `json:"challenge"`
Number int `json:"number"`
MaxNumber int `json:"maxnumber"`
ExpiresAt int64 `json:"expires_at"`
Signature string `json:"signature"`
}
PoWSolution represents the client's submitted answer.
type PoWVerifier ¶
type PoWVerifier struct {
// contains filtered or unexported fields
}
PoWVerifier accepts each signed challenge once, remembering it until it expires.
func (*PoWVerifier) Verify ¶
func (v *PoWVerifier) Verify(solutionBase64, signingSecret string) bool
Verify reports whether the solution is valid and its challenge not yet spent.
type SessionManager ¶
type SessionManager struct {
// contains filtered or unexported fields
}
func NewSessionManager ¶
func NewSessionManager(st store.Store, cfg config.SecurityConfig) *SessionManager
func (*SessionManager) AuthenticateRequest ¶
AuthenticateRequest extracts the session token from cookie or Authorization header and returns the user.
func (*SessionManager) IssueSSOSession ¶ added in v0.5.0
func (sm *SessionManager) IssueSSOSession(ctx context.Context, w http.ResponseWriter, r *http.Request, user *store.User, provider, sid string, issuedAt time.Time) (*store.Session, string, error)
IssueSSOSession issues a session for a provider sign-in named by its ID token sid and dates it by the ID token's issuedAt, so a back-channel logout for that sid or subject ends it. It fails with store.ErrSSOSessionEnded when the provider already ended that login. Empty provider and sid issue a local session.
func (*SessionManager) IssueSession ¶
func (sm *SessionManager) IssueSession(ctx context.Context, w http.ResponseWriter, r *http.Request, user *store.User) (*store.Session, string, error)
IssueSession creates an active session in the database and writes HttpOnly cookie + CSRF token.
func (*SessionManager) RevokeSession ¶
func (sm *SessionManager) RevokeSession(ctx context.Context, w http.ResponseWriter, r *http.Request) error
RevokeSession deletes the active session and clears the browser cookies.