Documentation
¶
Overview ¶
Package direct is the table-backed implementation of the lookup stores. SQL is built from the configured Schema (table and column names) and Dialect (placeholders, quoting, booleans, insert-returning-id); no statement is written per database and no ORM is used.
Index ¶
- func BurnPasswordCheck(supplied string)
- func GenerateSessionToken() (string, error)
- func HashPassword(password string) (string, error)
- func ParseRoles(s string) []string
- func VerifyPassword(stored, supplied string) (ok, needsRehash bool)
- type Assignment
- type Auth
- func (a *Auth) JWTLogin(ctx context.Context, req sectypes.LoginRequest) (*sectypes.LoginResponse, error)
- func (a *Auth) JWTLogout(ctx context.Context, req sectypes.LogoutRequest) error
- func (a *Auth) Login(ctx context.Context, req sectypes.LoginRequest) (*sectypes.LoginResponse, error)
- func (a *Auth) LoginAPIKey(ctx context.Context, rawKey string, claims map[string]any) (*sectypes.LoginResponse, error)
- func (a *Auth) Logout(ctx context.Context, req sectypes.LogoutRequest) error
- func (a *Auth) Refresh(ctx context.Context, oldToken string) (*sectypes.LoginResponse, error)
- func (a *Auth) Register(ctx context.Context, req sectypes.RegisterRequest) (*sectypes.LoginResponse, error)
- func (a *Auth) ResetComplete(ctx context.Context, req sectypes.PasswordResetCompleteRequest) error
- func (a *Auth) ResetRequest(ctx context.Context, req sectypes.PasswordResetRequest) (*sectypes.PasswordResetResponse, error)
- func (a *Auth) Session(ctx context.Context, token, _ string) (*sectypes.UserContext, error)
- func (a *Auth) TouchSession(ctx context.Context, token string, _ *sectypes.UserContext) error
- type AuthOptions
- type Base
- type Cond
- func And(cs ...Cond) Cond
- func Eq(c lookup.Column, v any) Cond
- func EqCol(a, c lookup.Column) Cond
- func EqFold(c lookup.Column, v string) Cond
- func Gt(c lookup.Column, v any) Cond
- func In(c lookup.Column, vs ...any) Cond
- func InSelect(c lookup.Column, sub *Select) Cond
- func IsNull(c lookup.Column) Cond
- func Lt(c lookup.Column, v any) Cond
- func Ne(c lookup.Column, v any) Cond
- func Or(cs ...Cond) Cond
- type Delete
- type Insert
- type Keys
- func (k *Keys) Create(ctx context.Context, req sectypes.CreateKeyRequest, keyHash string) (*sectypes.UserKey, error)
- func (k *Keys) Delete(ctx context.Context, userID int, keyID int64) (string, error)
- func (k *Keys) List(ctx context.Context, userID int, keyType sectypes.KeyType) ([]sectypes.UserKey, error)
- func (k *Keys) Validate(ctx context.Context, keyHash string, keyType sectypes.KeyType) (*sectypes.UserKey, error)
- type OAuthClients
- func (o *OAuthClients) DeleteClient(ctx context.Context, clientID string) error
- func (o *OAuthClients) ExchangeCode(ctx context.Context, code string) (*sectypes.OAuthCode, error)
- func (o *OAuthClients) GetClient(ctx context.Context, clientID string) (*sectypes.OAuthServerClient, error)
- func (o *OAuthClients) Introspect(ctx context.Context, token string) (*sectypes.OAuthTokenInfo, error)
- func (o *OAuthClients) RegisterClient(ctx context.Context, client *sectypes.OAuthServerClient) (*sectypes.OAuthServerClient, error)
- func (o *OAuthClients) Revoke(ctx context.Context, token string) error
- func (o *OAuthClients) SaveCode(ctx context.Context, code *sectypes.OAuthCode) error
- func (o *OAuthClients) UpdateClient(ctx context.Context, client *sectypes.OAuthServerClient) error
- type OAuthGrants
- func (o *OAuthGrants) ConsumePushedRequest(ctx context.Context, requestURI string) (*lookup.PushedRequest, error)
- func (o *OAuthGrants) CreateDevice(ctx context.Context, d lookup.DeviceCode) error
- func (o *OAuthGrants) DeviceByUserCode(ctx context.Context, userCode string) (*lookup.DeviceCode, error)
- func (o *OAuthGrants) DeviceDecide(ctx context.Context, userCode string, approve bool, userID int, ...) error
- func (o *OAuthGrants) DevicePoll(ctx context.Context, deviceHash string) (*lookup.DeviceCode, error)
- func (o *OAuthGrants) GetConsent(ctx context.Context, userID int, clientID string) (*lookup.Consent, error)
- func (o *OAuthGrants) PeekRefresh(ctx context.Context, hash string) (*lookup.RefreshToken, error)
- func (o *OAuthGrants) RevokeConsent(ctx context.Context, userID int, clientID string) error
- func (o *OAuthGrants) RevokeRefreshBySession(ctx context.Context, sessionToken string) error
- func (o *OAuthGrants) RevokeRefreshFamily(ctx context.Context, familyID string) error
- func (o *OAuthGrants) RotateRefresh(ctx context.Context, oldHash string, next lookup.RefreshToken) (*lookup.RefreshToken, error)
- func (o *OAuthGrants) SaveConsent(ctx context.Context, c lookup.Consent) error
- func (o *OAuthGrants) SavePushedRequest(ctx context.Context, r lookup.PushedRequest) error
- func (o *OAuthGrants) SaveRefresh(ctx context.Context, t lookup.RefreshToken) error
- func (o *OAuthGrants) SeenJTI(ctx context.Context, key string, expires time.Time) (bool, error)
- type OAuthUsers
- func (o *OAuthUsers) CreateSession(ctx context.Context, s lookup.OAuthSession) error
- func (o *OAuthUsers) GetByRefreshToken(ctx context.Context, refreshToken string) (*lookup.OAuthRefreshSession, error)
- func (o *OAuthUsers) GetOrCreateUser(ctx context.Context, user *sectypes.UserContext, provider string) (int, error)
- func (o *OAuthUsers) GetUser(ctx context.Context, userID int) (*sectypes.UserContext, error)
- func (o *OAuthUsers) UpdateRefreshToken(ctx context.Context, userID int, ...) error
- type Passkey
- func (p *Passkey) ByUsername(ctx context.Context, username string) (int, []lookup.PasskeyCredentialRef, error)
- func (p *Passkey) Delete(ctx context.Context, userID int, credentialID string) error
- func (p *Passkey) Get(ctx context.Context, credentialID string) (userID int, signCount uint32, err error)
- func (p *Passkey) List(ctx context.Context, userID int) ([]sectypes.PasskeyCredential, error)
- func (p *Passkey) Login(ctx context.Context, userID int, claims map[string]any) (*sectypes.LoginResponse, error)
- func (p *Passkey) Rename(ctx context.Context, userID int, credentialID, name string) error
- func (p *Passkey) Store(ctx context.Context, rec lookup.PasskeyCredentialRecord) (int64, error)
- func (p *Passkey) UpdateCounter(ctx context.Context, credentialID string, newCounter uint32) (bool, error)
- type Policy
- type PolicyOptions
- type Querier
- type Runner
- type Select
- func (s *Select) Build() Stmt
- func (s *Select) Cols(cs ...lookup.Column) *Select
- func (s *Select) Exists(ctx context.Context, q Querier) (bool, error)
- func (s *Select) Join(e lookup.Entity, on Cond) *Select
- func (s *Select) OrderBy(cs ...lookup.Column) *Select
- func (s *Select) Query(ctx context.Context, q Querier) (*sql.Rows, error)
- func (s *Select) QueryRow(ctx context.Context, q Querier, dest ...any) error
- func (s *Select) Where(cs ...Cond) *Select
- type Stmt
- type TOTP
- func (t *TOTP) Disable(ctx context.Context, userID int) error
- func (t *TOTP) Enable(ctx context.Context, userID int, secret string, hashedCodes []string) error
- func (t *TOTP) RegenerateBackupCodes(ctx context.Context, userID int, hashedCodes []string) error
- func (t *TOTP) Secret(ctx context.Context, userID int) (string, error)
- func (t *TOTP) Status(ctx context.Context, userID int) (bool, error)
- func (t *TOTP) ValidateBackupCode(ctx context.Context, userID int, codeHash string) (bool, error)
- type Update
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BurnPasswordCheck ¶
func BurnPasswordCheck(supplied string)
BurnPasswordCheck spends roughly one bcrypt comparison so an unknown username costs about the same as a wrong password.
func GenerateSessionToken ¶
GenerateSessionToken returns "sess_<64 hex>_<unix>".
func HashPassword ¶
HashPassword returns the bcrypt hash of password.
func ParseRoles ¶
ParseRoles splits the comma-separated roles column.
func VerifyPassword ¶
VerifyPassword checks supplied against the stored value. A stored bcrypt hash is compared with bcrypt. A legacy cleartext value (written before hashing was implemented) is compared in constant time and, on a match, needsRehash is true so the caller can upgrade the row. An empty stored value (e.g. an OAuth2-only user) never matches.
Types ¶
type Assignment ¶
Assignment is one `col = value` of an UPDATE or INSERT.
type Auth ¶
type Auth struct {
*Base
// contains filtered or unexported fields
}
Auth implements lookup.AuthStore on the tables. Passwords are verified with bcrypt; legacy cleartext rows are accepted at login and only rewritten when UpgradePasswordHash is set. Registration never honours client-supplied user_level or roles. Multi-step writes (login, register, refresh, reset) run in one transaction.
func (*Auth) JWTLogin ¶
func (a *Auth) JWTLogin(ctx context.Context, req sectypes.LoginRequest) (*sectypes.LoginResponse, error)
JWTLogin implements lookup.AuthStore (mirrors resolvespec_jwt_login). The token is a placeholder until JWT signing is wired in.
func (*Auth) Login ¶
func (a *Auth) Login(ctx context.Context, req sectypes.LoginRequest) (*sectypes.LoginResponse, error)
Login implements lookup.AuthStore.
func (*Auth) LoginAPIKey ¶
func (a *Auth) LoginAPIKey(ctx context.Context, rawKey string, claims map[string]any) (*sectypes.LoginResponse, error)
LoginAPIKey implements lookup.AuthStore. Unknown, expired, inactive and wrong-type keys (and inactive users) all return lookup.ErrInvalidAPIKey; the raw key is never logged.
func (*Auth) Refresh ¶
Refresh implements lookup.AuthStore: the old session is replaced by a new one.
func (*Auth) Register ¶
func (a *Auth) Register(ctx context.Context, req sectypes.RegisterRequest) (*sectypes.LoginResponse, error)
Register implements lookup.AuthStore.
func (*Auth) ResetComplete ¶
ResetComplete implements lookup.AuthStore: sets the new password, ends every session of the user and consumes the reset token, atomically.
func (*Auth) ResetRequest ¶
func (a *Auth) ResetRequest(ctx context.Context, req sectypes.PasswordResetRequest) (*sectypes.PasswordResetResponse, error)
ResetRequest implements lookup.AuthStore. An unknown user yields a generic empty success so accounts cannot be enumerated.
func (*Auth) Session ¶
Session implements lookup.AuthStore. reference is only meaningful to the procedure backend.
func (*Auth) TouchSession ¶
TouchSession implements lookup.AuthStore.
type AuthOptions ¶
type AuthOptions struct {
// UpgradePasswordHash rewrites legacy cleartext passwords as bcrypt on a successful login.
UpgradePasswordHash bool
}
AuthOptions tunes Auth.
type Base ¶
type Base struct {
// Now is the clock; tests replace it.
Now func() time.Time
// contains filtered or unexported fields
}
Base is the state shared by every direct store: the runner, dialect, schema and clock.
func NewBase ¶
NewBase creates the shared state. The schema is merged with the defaults and validated.
type Cond ¶
type Cond func(*builder) string
Cond renders one boolean condition.
type Delete ¶
type Delete struct {
// contains filtered or unexported fields
}
Delete builds a DELETE.
type Insert ¶
type Insert struct {
// contains filtered or unexported fields
}
Insert builds an INSERT.
type Keys ¶
type Keys struct{ *Base }
Keys implements lookup.KeyStore on the user keys table. scopes and meta are stored as JSON through the dialect (native JSON column or TEXT).
func (*Keys) Create ¶
func (k *Keys) Create(ctx context.Context, req sectypes.CreateKeyRequest, keyHash string) (*sectypes.UserKey, error)
Create implements lookup.KeyStore.
func (*Keys) Delete ¶
Delete implements lookup.KeyStore: soft-deletes the key after checking ownership and returns its hash.
type OAuthClients ¶
type OAuthClients struct{ *Base }
OAuthClients implements lookup.OAuthClientStore. Array columns (redirect_uris, grant_types, allowed_scopes, scopes) are JSON through the dialect.
func NewOAuthClients ¶
func NewOAuthClients(b *Base) *OAuthClients
NewOAuthClients creates the direct OAuthClientStore.
func (*OAuthClients) DeleteClient ¶
func (o *OAuthClients) DeleteClient(ctx context.Context, clientID string) error
DeleteClient implements lookup.OAuthClientStore: the client is deactivated.
func (*OAuthClients) ExchangeCode ¶
ExchangeCode implements lookup.OAuthClientStore: the code is consumed in a transaction and only the caller whose delete removes the row gets it, so a code cannot be redeemed twice.
func (*OAuthClients) GetClient ¶
func (o *OAuthClients) GetClient(ctx context.Context, clientID string) (*sectypes.OAuthServerClient, error)
GetClient implements lookup.OAuthClientStore.
func (*OAuthClients) Introspect ¶
func (o *OAuthClients) Introspect(ctx context.Context, token string) (*sectypes.OAuthTokenInfo, error)
Introspect implements lookup.OAuthClientStore (RFC 7662). An unknown or expired token is {active:false}, not an error.
func (*OAuthClients) RegisterClient ¶
func (o *OAuthClients) RegisterClient(ctx context.Context, client *sectypes.OAuthServerClient) (*sectypes.OAuthServerClient, error)
RegisterClient implements lookup.OAuthClientStore.
func (*OAuthClients) Revoke ¶
func (o *OAuthClients) Revoke(ctx context.Context, token string) error
Revoke implements lookup.OAuthClientStore (RFC 7009): the session is deleted; an unknown token is not an error.
func (*OAuthClients) UpdateClient ¶
func (o *OAuthClients) UpdateClient(ctx context.Context, client *sectypes.OAuthServerClient) error
UpdateClient implements lookup.OAuthClientStore: it rewrites the mutable registration fields of an existing client (RFC 7592 management).
type OAuthGrants ¶
type OAuthGrants struct{ *Base }
OAuthGrants implements lookup.OAuthGrantStore on tables. Every multi-step operation runs in one transaction, and single-use records (refresh rotation, device codes, pushed requests) are consumed with a conditional write so concurrent callers cannot both succeed.
func NewOAuthGrants ¶
func NewOAuthGrants(b *Base) *OAuthGrants
NewOAuthGrants creates the direct OAuthGrantStore.
func (*OAuthGrants) ConsumePushedRequest ¶
func (o *OAuthGrants) ConsumePushedRequest(ctx context.Context, requestURI string) (*lookup.PushedRequest, error)
ConsumePushedRequest implements lookup.OAuthGrantStore.
func (*OAuthGrants) CreateDevice ¶
func (o *OAuthGrants) CreateDevice(ctx context.Context, d lookup.DeviceCode) error
CreateDevice implements lookup.OAuthGrantStore.
func (*OAuthGrants) DeviceByUserCode ¶
func (o *OAuthGrants) DeviceByUserCode(ctx context.Context, userCode string) (*lookup.DeviceCode, error)
DeviceByUserCode implements lookup.OAuthGrantStore.
func (*OAuthGrants) DeviceDecide ¶
func (o *OAuthGrants) DeviceDecide(ctx context.Context, userCode string, approve bool, userID int, sessionToken string) error
DeviceDecide implements lookup.OAuthGrantStore.
func (*OAuthGrants) DevicePoll ¶
func (o *OAuthGrants) DevicePoll(ctx context.Context, deviceHash string) (*lookup.DeviceCode, error)
DevicePoll implements lookup.OAuthGrantStore.
func (*OAuthGrants) GetConsent ¶
func (o *OAuthGrants) GetConsent(ctx context.Context, userID int, clientID string) (*lookup.Consent, error)
GetConsent implements lookup.OAuthGrantStore.
func (*OAuthGrants) PeekRefresh ¶
func (o *OAuthGrants) PeekRefresh(ctx context.Context, hash string) (*lookup.RefreshToken, error)
PeekRefresh implements lookup.OAuthGrantStore.
func (*OAuthGrants) RevokeConsent ¶
RevokeConsent implements lookup.OAuthGrantStore.
func (*OAuthGrants) RevokeRefreshBySession ¶
func (o *OAuthGrants) RevokeRefreshBySession(ctx context.Context, sessionToken string) error
RevokeRefreshBySession implements lookup.OAuthGrantStore.
func (*OAuthGrants) RevokeRefreshFamily ¶
func (o *OAuthGrants) RevokeRefreshFamily(ctx context.Context, familyID string) error
RevokeRefreshFamily implements lookup.OAuthGrantStore.
func (*OAuthGrants) RotateRefresh ¶
func (o *OAuthGrants) RotateRefresh(ctx context.Context, oldHash string, next lookup.RefreshToken) (*lookup.RefreshToken, error)
RotateRefresh implements lookup.OAuthGrantStore.
func (*OAuthGrants) SaveConsent ¶
SaveConsent implements lookup.OAuthGrantStore.
func (*OAuthGrants) SavePushedRequest ¶
func (o *OAuthGrants) SavePushedRequest(ctx context.Context, r lookup.PushedRequest) error
SavePushedRequest implements lookup.OAuthGrantStore.
func (*OAuthGrants) SaveRefresh ¶
func (o *OAuthGrants) SaveRefresh(ctx context.Context, t lookup.RefreshToken) error
SaveRefresh implements lookup.OAuthGrantStore.
type OAuthUsers ¶
type OAuthUsers struct{ *Base }
OAuthUsers implements lookup.OAuthUserStore.
func NewOAuthUsers ¶
func NewOAuthUsers(b *Base) *OAuthUsers
NewOAuthUsers creates the direct OAuthUserStore.
func (*OAuthUsers) CreateSession ¶
func (o *OAuthUsers) CreateSession(ctx context.Context, s lookup.OAuthSession) error
CreateSession implements lookup.OAuthUserStore: insert, or update when the token exists.
func (*OAuthUsers) GetByRefreshToken ¶
func (o *OAuthUsers) GetByRefreshToken(ctx context.Context, refreshToken string) (*lookup.OAuthRefreshSession, error)
GetByRefreshToken implements lookup.OAuthUserStore.
func (*OAuthUsers) GetOrCreateUser ¶
func (o *OAuthUsers) GetOrCreateUser(ctx context.Context, user *sectypes.UserContext, provider string) (int, error)
GetOrCreateUser implements lookup.OAuthUserStore: select by email, then update or insert, in one transaction (no upsert).
func (*OAuthUsers) GetUser ¶
func (o *OAuthUsers) GetUser(ctx context.Context, userID int) (*sectypes.UserContext, error)
GetUser implements lookup.OAuthUserStore.
func (*OAuthUsers) UpdateRefreshToken ¶
func (o *OAuthUsers) UpdateRefreshToken(ctx context.Context, userID int, oldRefreshToken, newSessionToken, newAccessToken, newRefreshToken string, expiresAt time.Time) error
UpdateRefreshToken implements lookup.OAuthUserStore.
type Passkey ¶
type Passkey struct{ *Base }
Passkey implements lookup.PasskeyStore. credential_id, public_key and aaguid are base64 TEXT (not native bytea) and transports is JSON, so one schema works on every dialect.
func (*Passkey) ByUsername ¶
func (p *Passkey) ByUsername(ctx context.Context, username string) (int, []lookup.PasskeyCredentialRef, error)
ByUsername implements lookup.PasskeyStore.
func (*Passkey) Get ¶
func (p *Passkey) Get(ctx context.Context, credentialID string) (userID int, signCount uint32, err error)
Get implements lookup.PasskeyStore.
func (*Passkey) Login ¶
func (p *Passkey) Login(ctx context.Context, userID int, claims map[string]any) (*sectypes.LoginResponse, error)
Login implements lookup.PasskeyStore: it creates the session for a user whose passkey assertion was already verified.
type Policy ¶
type Policy struct {
*Base
// contains filtered or unexported fields
}
Policy implements lookup.PolicyStore on the rule tables.
Applicable rules are the active rules whose user_id is the caller plus the rules of every group the caller belongs to; schema and table match case-insensitively and exactly (never a prefix). Column security returns the union of the matching rules. Row security: any applicable has_block rule wins, otherwise the templates are combined with AND, each in parentheses. No rule is an empty result; failures are errors so callers fail closed.
func NewPolicy ¶
func NewPolicy(b *Base, opts PolicyOptions) *Policy
NewPolicy creates the direct PolicyStore.
func (*Policy) ColumnSecurity ¶
func (p *Policy) ColumnSecurity(ctx context.Context, userID int, schema, table string) ([]sectypes.ColumnSecurity, error)
ColumnSecurity implements lookup.PolicyStore.
func (*Policy) RowSecurity ¶
func (p *Policy) RowSecurity(ctx context.Context, userRef any, schema, table string) (sectypes.RowSecurity, error)
RowSecurity implements lookup.PolicyStore.
type PolicyOptions ¶
type PolicyOptions struct {
// NoGroups skips the group membership table: only rules addressed to the user directly
// apply. Use it when the sec_group_members table is not deployed.
NoGroups bool
}
PolicyOptions tunes Policy.
type Querier ¶
type Querier interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}
Querier is implemented by *sql.DB and *sql.Tx.
type Runner ¶
Runner runs a database operation, reconnecting once when the *sql.DB has been closed. procedure.Runner (and procedure.DB) satisfy it.
type Select ¶
type Select struct {
// contains filtered or unexported fields
}
Select builds a SELECT.
type TOTP ¶
type TOTP struct{ *Base }
TOTP implements lookup.TOTPStore: the secret and enabled flag live on the users table, backup code hashes in their own table.
func (*TOTP) RegenerateBackupCodes ¶
RegenerateBackupCodes implements lookup.TOTPStore.
func (*TOTP) ValidateBackupCode ¶
ValidateBackupCode implements lookup.TOTPStore. An unknown code is (false, nil); a used code is an error. The code is consumed with a conditional update so it cannot be spent twice.