Documentation
¶
Overview ¶
Package loginflow holds the persistent state for the login flow. It stores one client authorization per pending enrolment and runs the atomic state transitions (approve, consume) that the flow needs. It does not authenticate anyone; its only job is to track an authorization until an appauth credential is minted.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClientDescription ¶
ClientDescription turns a raw User-Agent into a short, human-readable label for the confirmation page and the connected-clients list, e.g. "Nextcloud Sync Client v3.13.0 (on Linux)". It recognises the Nextcloud desktop sync client (which sends a "mirall/<version>" token) and falls back to the raw string for anything it does not know.
Types ¶
type ClientAuthorization ¶
type ClientAuthorization struct {
LoginHash []byte // SHA256(logintoken)
PollHash []byte // SHA256(polltoken)
ClientID string // UUIDv4, surfaced to audit / management API
UserAgent string // raw User-Agent from Init
CreatedAt time.Time // set at Init
ExpiresAt time.Time // PENDING lifetime
ApprovedAt *time.Time // nil = PENDING; non-nil = APPROVED
UserID string // set on approval, opaque user id
Username string // set on approval, login name for the poll response
DeviceName string // set on approval, becomes the app password label
}
ClientAuthorization is one pending or approved enrolment attempt by a client.
func (*ClientAuthorization) Approved ¶
func (ca *ClientAuthorization) Approved() bool
Approved reports whether the authorization has been granted.
func (*ClientAuthorization) Expired ¶
func (ca *ClientAuthorization) Expired() bool
Expired reports whether the authorization has passed its PENDING lifetime.
type Manager ¶
type Manager interface {
// Create inserts a new PENDING authorization.
Create(ctx context.Context, ca *ClientAuthorization) error
// GetByLogin returns the authorization for a login hash, including expired
// ones so the caller can tell "gone" from "unknown". Returns
// errtypes.NotFound if no live (non-deleted) row exists.
GetByLogin(ctx context.Context, loginHash []byte) (*ClientAuthorization, error)
// GetByPoll is GetByLogin keyed by poll hash.
GetByPoll(ctx context.Context, pollHash []byte) (*ClientAuthorization, error)
// Approve records the user's consent, once: who granted, and what they named
// the device. Returns errtypes.Conflict if the authorization was already
// granted, already denied, or has expired.
Approve(ctx context.Context, loginHash []byte, userID, username, deviceName string) error
// Consume hands out an approved authorization once and only once, so two
// polls can never mint two app passwords from one approval. The winner gets
// the user to mint for. Returns errtypes.NotFound if the authorization was
// never approved, is already consumed, or has expired.
Consume(ctx context.Context, pollHash []byte) (*ClientAuthorization, error)
// Deny soft-deletes a PENDING authorization. It is a no-op if no PENDING row
// exists.
Deny(ctx context.Context, loginHash []byte) error
}
Manager stores client authorizations and runs their state transitions.