direct

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

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

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

func GenerateSessionToken() (string, error)

GenerateSessionToken returns "sess_<64 hex>_<unix>".

func HashPassword

func HashPassword(password string) (string, error)

HashPassword returns the bcrypt hash of password.

func ParseRoles

func ParseRoles(s string) []string

ParseRoles splits the comma-separated roles column.

func VerifyPassword

func VerifyPassword(stored, supplied string) (ok, needsRehash bool)

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

type Assignment struct {
	Col lookup.Column
	Val any
}

Assignment is one `col = value` of an UPDATE or INSERT.

func Set

func Set(c lookup.Column, v any) Assignment

Set builds an Assignment.

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 NewAuth

func NewAuth(b *Base, opts AuthOptions) *Auth

NewAuth creates the direct AuthStore.

func (*Auth) JWTLogin

JWTLogin implements lookup.AuthStore (mirrors resolvespec_jwt_login). The token is a placeholder until JWT signing is wired in.

func (*Auth) JWTLogout

func (a *Auth) JWTLogout(ctx context.Context, req sectypes.LogoutRequest) error

JWTLogout implements lookup.AuthStore: the token goes on the blacklist.

func (*Auth) Login

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

func (a *Auth) Logout(ctx context.Context, req sectypes.LogoutRequest) error

Logout implements lookup.AuthStore.

func (*Auth) Refresh

func (a *Auth) Refresh(ctx context.Context, oldToken string) (*sectypes.LoginResponse, error)

Refresh implements lookup.AuthStore: the old session is replaced by a new one.

func (*Auth) Register

Register implements lookup.AuthStore.

func (*Auth) ResetComplete

func (a *Auth) ResetComplete(ctx context.Context, req sectypes.PasswordResetCompleteRequest) error

ResetComplete implements lookup.AuthStore: sets the new password, ends every session of the user and consumes the reset token, atomically.

func (*Auth) ResetRequest

ResetRequest implements lookup.AuthStore. An unknown user yields a generic empty success so accounts cannot be enumerated.

func (*Auth) Session

func (a *Auth) Session(ctx context.Context, token, _ string) (*sectypes.UserContext, error)

Session implements lookup.AuthStore. reference is only meaningful to the procedure backend.

func (*Auth) TouchSession

func (a *Auth) TouchSession(ctx context.Context, token string, _ *sectypes.UserContext) error

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

func NewBase(run Runner, d dialect.Dialect, schema lookup.Schema) (*Base, error)

NewBase creates the shared state. The schema is merged with the defaults and validated.

func (*Base) Delete

func (b *Base) Delete(e lookup.Entity) *Delete

Delete starts a DELETE on e.

func (*Base) Dialect

func (b *Base) Dialect() dialect.Dialect

Dialect returns the dialect in use.

func (*Base) From

func (b *Base) From(e lookup.Entity) *Select

From starts a SELECT on e.

func (*Base) Insert

func (b *Base) Insert(e lookup.Entity) *Insert

Insert starts an INSERT into e.

func (*Base) Update

func (b *Base) Update(e lookup.Entity) *Update

Update starts an UPDATE of e.

type Cond

type Cond func(*builder) string

Cond renders one boolean condition.

func And

func And(cs ...Cond) Cond

And joins conditions with AND inside parentheses.

func Eq

func Eq(c lookup.Column, v any) Cond

Eq is `col = value`.

func EqCol

func EqCol(a, c lookup.Column) Cond

EqCol is `a = b` between two columns (join conditions).

func EqFold

func EqFold(c lookup.Column, v string) Cond

EqFold is a case-insensitive `LOWER(col) = value` match (the value is lowered in Go).

func Gt

func Gt(c lookup.Column, v any) Cond

Gt is `col > value`.

func In

func In(c lookup.Column, vs ...any) Cond

In is `col IN (v...)`; an empty list renders a condition that is never true.

func InSelect

func InSelect(c lookup.Column, sub *Select) Cond

InSelect is `col IN (subselect)`; the subselect's arguments share the outer numbering.

func IsNull

func IsNull(c lookup.Column) Cond

IsNull is `col IS NULL`.

func Lt

func Lt(c lookup.Column, v any) Cond

Lt is `col < value`.

func Ne

func Ne(c lookup.Column, v any) Cond

Ne is `col <> value`.

func Or

func Or(cs ...Cond) Cond

Or joins conditions with OR inside parentheses.

type Delete

type Delete struct {
	// contains filtered or unexported fields
}

Delete builds a DELETE.

func (*Delete) Exec

func (d *Delete) Exec(ctx context.Context, q Querier) (int64, error)

Exec runs the delete and returns the affected row count.

func (*Delete) Where

func (d *Delete) Where(cs ...Cond) *Delete

Where adds AND-ed conditions.

type Insert

type Insert struct {
	// contains filtered or unexported fields
}

Insert builds an INSERT.

func (*Insert) Exec

func (i *Insert) Exec(ctx context.Context, q Querier) error

Exec runs the insert.

func (*Insert) ExecID

func (i *Insert) ExecID(ctx context.Context, q Querier, idCol lookup.Column) (int64, error)

ExecID runs the insert and returns the generated value of idCol, using the dialect's insert-returning-id strategy.

func (*Insert) Set

func (i *Insert) Set(as ...Assignment) *Insert

Set adds assignments.

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 NewKeys

func NewKeys(b *Base) *Keys

NewKeys creates the direct KeyStore.

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

func (k *Keys) Delete(ctx context.Context, userID int, keyID int64) (string, error)

Delete implements lookup.KeyStore: soft-deletes the key after checking ownership and returns its hash.

func (*Keys) List

func (k *Keys) List(ctx context.Context, userID int, keyType sectypes.KeyType) ([]sectypes.UserKey, error)

List implements lookup.KeyStore: active, non-expired keys; an empty keyType means all types.

func (*Keys) Validate

func (k *Keys) Validate(ctx context.Context, keyHash string, keyType sectypes.KeyType) (*sectypes.UserKey, error)

Validate implements lookup.KeyStore: finds an active, non-expired key by hash (optionally of one type) and stamps last_used_at.

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

func (o *OAuthClients) ExchangeCode(ctx context.Context, code string) (*sectypes.OAuthCode, error)

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

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

func (o *OAuthClients) SaveCode(ctx context.Context, code *sectypes.OAuthCode) error

SaveCode implements lookup.OAuthClientStore.

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

func (o *OAuthGrants) RevokeConsent(ctx context.Context, userID int, clientID string) error

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

func (o *OAuthGrants) SaveConsent(ctx context.Context, c lookup.Consent) error

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.

func (*OAuthGrants) SeenJTI

func (o *OAuthGrants) SeenJTI(ctx context.Context, key string, expires time.Time) (bool, error)

SeenJTI 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 NewPasskey

func NewPasskey(b *Base) *Passkey

NewPasskey creates the direct PasskeyStore.

func (*Passkey) ByUsername

func (p *Passkey) ByUsername(ctx context.Context, username string) (int, []lookup.PasskeyCredentialRef, error)

ByUsername implements lookup.PasskeyStore.

func (*Passkey) Delete

func (p *Passkey) Delete(ctx context.Context, userID int, credentialID string) error

Delete 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) List

func (p *Passkey) List(ctx context.Context, userID int) ([]sectypes.PasskeyCredential, error)

List implements lookup.PasskeyStore, newest first.

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.

func (*Passkey) Rename

func (p *Passkey) Rename(ctx context.Context, userID int, credentialID, name string) error

Rename implements lookup.PasskeyStore.

func (*Passkey) Store

Store implements lookup.PasskeyStore.

func (*Passkey) UpdateCounter

func (p *Passkey) UpdateCounter(ctx context.Context, credentialID string, newCounter uint32) (bool, error)

UpdateCounter implements lookup.PasskeyStore. A counter that did not advance flags the credential as possibly cloned and leaves the stored counter unchanged.

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

type Runner interface {
	Run(run func(*sql.DB) error) error
}

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.

func (*Select) Build

func (s *Select) Build() Stmt

Build renders the statement.

func (*Select) Cols

func (s *Select) Cols(cs ...lookup.Column) *Select

Cols sets the selected columns.

func (*Select) Exists

func (s *Select) Exists(ctx context.Context, q Querier) (bool, error)

Exists reports whether the select returns at least one row.

func (*Select) Join

func (s *Select) Join(e lookup.Entity, on Cond) *Select

Join adds `JOIN e ON on`.

func (*Select) OrderBy

func (s *Select) OrderBy(cs ...lookup.Column) *Select

OrderBy adds ascending order columns.

func (*Select) Query

func (s *Select) Query(ctx context.Context, q Querier) (*sql.Rows, error)

Query runs the select.

func (*Select) QueryRow

func (s *Select) QueryRow(ctx context.Context, q Querier, dest ...any) error

QueryRow runs the select and scans the first row into dest.

func (*Select) Where

func (s *Select) Where(cs ...Cond) *Select

Where adds AND-ed conditions.

type Stmt

type Stmt struct {
	SQL  string
	Args []any
}

Stmt is a rendered statement.

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 NewTOTP

func NewTOTP(b *Base) *TOTP

NewTOTP creates the direct TOTPStore.

func (*TOTP) Disable

func (t *TOTP) Disable(ctx context.Context, userID int) error

Disable implements lookup.TOTPStore.

func (*TOTP) Enable

func (t *TOTP) Enable(ctx context.Context, userID int, secret string, hashedCodes []string) error

Enable implements lookup.TOTPStore.

func (*TOTP) RegenerateBackupCodes

func (t *TOTP) RegenerateBackupCodes(ctx context.Context, userID int, hashedCodes []string) error

RegenerateBackupCodes implements lookup.TOTPStore.

func (*TOTP) Secret

func (t *TOTP) Secret(ctx context.Context, userID int) (string, error)

Secret implements lookup.TOTPStore.

func (*TOTP) Status

func (t *TOTP) Status(ctx context.Context, userID int) (bool, error)

Status implements lookup.TOTPStore.

func (*TOTP) ValidateBackupCode

func (t *TOTP) ValidateBackupCode(ctx context.Context, userID int, codeHash string) (bool, error)

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.

type Update

type Update struct {
	// contains filtered or unexported fields
}

Update builds an UPDATE.

func (*Update) Exec

func (u *Update) Exec(ctx context.Context, q Querier) (int64, error)

Exec runs the update and returns the affected row count.

func (*Update) Set

func (u *Update) Set(as ...Assignment) *Update

Set adds assignments.

func (*Update) Where

func (u *Update) Where(cs ...Cond) *Update

Where adds AND-ed conditions.

Jump to

Keyboard shortcuts

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