Documentation
¶
Overview ¶
store.go is the data-access layer for User. Same conventions as the entity stores: sqlc-generated typed methods, no sqlc types in exported signatures, (nil, nil) on not-found.
Package user owns the DB-backed user account: the row behind a login session. Users are not a catalog kind — no metadata envelope, no snapshot, no NOTIFY; they are identity, not routing config.
Two credential shapes coexist on one row: a local bcrypt password hash (password login) and/or an external identity subject ("issuer|sub", OIDC login). Either may be absent. Authorization is out of scope — roles are carried verbatim for app/authz to interpret.
Index ¶
- Constants
- func HashPassword(password string) (string, error)
- func SeedFromIdentity(ctx context.Context, s *Store, id *identity.Store, log *slog.Logger) error
- func VerifyPassword(hash, password string) bool
- type Store
- func (s *Store) ByOIDCSubject(ctx context.Context, subject string) (*User, error)
- func (s *Store) ByUsername(ctx context.Context, username string) (*User, error)
- func (s *Store) Delete(ctx context.Context, id string) error
- func (s *Store) Get(ctx context.Context, id string) (*User, error)
- func (s *Store) List(ctx context.Context) ([]*User, error)
- func (s *Store) Upsert(ctx context.Context, u *User) error
- type User
Constants ¶
const RoleAdmin = "admin"
RoleAdmin is the only role with defined meaning today: full access, including rows owned by other users.
Variables ¶
This section is empty.
Functions ¶
func HashPassword ¶
HashPassword bcrypt-hashes a cleartext password for storage.
func SeedFromIdentity ¶
SeedFromIdentity copies YAML identity users (config/users/) into the users table, seed-if-absent by username — same pattern as the settings seed. The YAML files remain the bootstrap/break-glass path; the table is what login reads. Plain-text YAML passwords are bcrypt-hashed on ingest so cleartext never lands in Postgres; already-hashed values are stored verbatim.
func VerifyPassword ¶
VerifyPassword checks cleartext against the stored hash. bcrypt hashes ("$2a$"/"$2b$"/"$2y$" prefix) compare via bcrypt; anything else is treated as a legacy plain value and compared constant-time (the YAML seed hashes plain passwords on ingest, so plain values here should not occur — kept for defense in depth). Empty hash never matches: an OIDC-only user has no password login.
Types ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the User data-access type.
func (*Store) ByOIDCSubject ¶
ByOIDCSubject returns the user bound to the external identity subject ("issuer|sub"), or (nil, nil).
func (*Store) ByUsername ¶
ByUsername returns the user with the given username, or (nil, nil).
type User ¶
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email,omitempty"`
PasswordHash string `json:"-"`
OIDCSubject string `json:"oidcSubject,omitempty"`
Roles []string `json:"roles,omitempty"`
Disabled bool `json:"disabled,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}
User is one account row.