Documentation
¶
Overview ¶
Package authcred mints and verifies the credentials both apps' auth flows are built on: session tokens, invite codes, telegram auth/login codes, and password hashes.
Index ¶
- Constants
- func CreateSession(ctx context.Context, ex Execer, userID int64, now time.Time) (string, error)
- func DeleteSession(ctx context.Context, ex Execer, sessionID int64) error
- func HashPassword(password string) (string, error)
- func HashSessionToken(token string) string
- func LegacySHA256Password(password, salt string) string
- func NeedsRefresh(lastSeen, expiry, now time.Time) bool
- func NewInviteCode() (string, error)
- func NewSessionToken() (string, error)
- func NewTelegramAuthCode() (string, error)
- func NewTelegramLoginCode() (string, error)
- func RandomBase32(n int) (string, error)
- func SlideSession(ctx context.Context, ex Execer, sessionID int64, now time.Time) error
- func VerifyPassword(storedHash, password string) bool
- func VerifyPasswordUpgrading(storedHash, storedSalt, password string) (ok bool, upgraded string, err error)
- type Execer
- type Queryer
- type SessionState
- type Sessions
Constants ¶
const ( SessionTokenBytes = 32 InviteCodeBytes = 12 TelegramAuthBytes = 12 TelegramLoginCodeLen = 8 PasswordMinLen = 8 PasswordMaxLen = 72 // bcrypt truncates beyond this // TelegramLoginCodeAlphabet is the human-typed alphabet: uppercase letters // and digits, so a code can be read aloud and retyped without ambiguity. TelegramLoginCodeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" )
const SessionRefreshInterval = time.Minute
SessionRefreshInterval is the minimum gap between sessions.last_seen_at writes for a given session. Most authenticated requests are served from a single SELECT; only every ~minute do we round-trip a write to extend the sliding lifetime.
Variables ¶
This section is empty.
Functions ¶
func CreateSession ¶
CreateSession inserts a session row and returns the raw token — only the hash is stored. A token collision is astronomically unlikely but cheap to retry; any other error is real and returned at once.
func DeleteSession ¶
DeleteSession forgets one session (an expired one, a logout).
func HashPassword ¶
HashPassword returns a bcrypt hash. The bcrypt format embeds its own salt, so callers pass none in.
func HashSessionToken ¶
HashSessionToken hashes a raw session token into the value stored in sessions.token_hash.
func LegacySHA256Password ¶
LegacySHA256Password is the pre-bcrypt scheme: sha256(salt + ":" + password).
func NeedsRefresh ¶
NeedsRefresh reports whether a session's sliding expiry should be extended. It says yes once last_seen_at has drifted by SessionRefreshInterval — and also whenever expires_at has drifted in from the full lifetime, which keeps the sliding window correct if something (an admin tool, a migration, a test) shortened expires_at independently of last_seen_at.
func NewInviteCode ¶
func NewSessionToken ¶
func NewTelegramAuthCode ¶
func NewTelegramLoginCode ¶
func RandomBase32 ¶
RandomBase32 returns n random bytes as unpadded uppercase base32.
func SlideSession ¶
SlideSession extends a live session by the full Lifetime from now.
func VerifyPassword ¶
VerifyPassword checks a candidate against a bcrypt hash.
func VerifyPasswordUpgrading ¶
func VerifyPasswordUpgrading(storedHash, storedSalt, password string) (ok bool, upgraded string, err error)
VerifyPasswordUpgrading checks a candidate against a stored hash that may be either bcrypt or the legacy SHA256 scheme. On a legacy match it returns a fresh bcrypt hash in upgraded, which the caller should persist so the next login no longer relies on the weaker scheme. Apps with no legacy rows should call VerifyPassword instead.
Types ¶
type Execer ¶
type Execer interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
}
Execer is the write side of a session store: a *sql.Tx, or any type that routes the write through the app's own write discipline.
type SessionState ¶
type SessionState int
SessionState is what a token resolves to.
const ( NoSession SessionState = iota // unknown token Expired // a row past its expiry — the caller deletes it Live )
type Sessions ¶
type Sessions struct {
UserColumns string
UserDest func(u *session.User) (dest []any, done func())
}
Sessions resolves cookies over an app's users table. The session columns are the same in both apps; the user columns differ (dope reads is_system), so the app names the ones the join selects — prefixed "u." — and says where they scan: UserDest answers the destinations in column order and a step to run once scanned (an int column into a bool), or nil.
func (Sessions) Lookup ¶
func (s Sessions) Lookup(ctx context.Context, q Queryer, token string, now time.Time) (u session.User, state SessionState, slide bool)
Lookup resolves a raw session token in one statement: the user, the state, and whether the sliding expiry is due (NeedsRefresh) — the caller slides it with SlideSession under its own write discipline, as it deletes an Expired row. A scan error reads as NoSession, like a missing row.