auth

package
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package auth owns the ctm serve password hashing, user credentials file, and in-memory session store (V27 single-user auth).

Index

Constants

View Source
const DefaultSessionTTL = 30 * 24 * time.Hour

DefaultSessionTTL bounds how long an in-memory session token remains valid. Caps the blast radius of a leaked token on a shared machine.

Variables

View Source
var DefaultParams = Params{
	M:       64 * 1024,
	T:       3,
	P:       2,
	SaltLen: 16,
	HashLen: 32,
}

DefaultParams is the canonical set of argon2id params used by Hash. Stored inside Encoded so a future bump does not invalidate old hashes.

Functions

func Delete

func Delete() error

Delete removes user.json. Returns nil if the file was already absent (idempotent by design so ctm auth reset can be run twice without confusion).

func Exists

func Exists() bool

Exists reports whether user.json is present.

func Required

func Required(token string, next http.Handler) http.Handler

Required returns an HTTP middleware that enforces a static bearer token. Requests without an `Authorization: Bearer <token>` header matching the expected token (constant-time compared) are rejected with 401 + a small JSON body and the standard `WWW-Authenticate` challenge header.

An empty `token` argument is a programming error (Required is wired at server boot, not per-request) and panics rather than silently disabling auth.

func Save

func Save(u User) error

Save writes u to UserPath() atomically (tmp-file + rename) with 0600 perms, creating the config directory if needed.

func UserFrom

func UserFrom(ctx context.Context) string

UserFrom returns the authenticated username from ctx, or "" if there is none.

func UserPath

func UserPath() string

UserPath returns the absolute path to user.json.

func Verify

func Verify(enc Encoded, password string) bool

Verify returns true iff password matches enc. Runs in constant time with respect to the hash comparison; salt/base64 decode errors are treated as a non-match (no panic). An empty password always returns false.

func WithUser

func WithUser(ctx context.Context, user string) context.Context

WithUser returns a context carrying the authenticated username.

Types

type Encoded

type Encoded struct {
	Algo    string `json:"algo"`
	Params  Params `json:"params"`
	SaltB64 string `json:"salt_b64"`
	HashB64 string `json:"hash_b64"`
}

Encoded is the on-disk representation of a hashed password. Everything needed to verify a password against this hash is contained here; no external key material is required.

func Hash

func Hash(password string) (Encoded, error)

Hash returns an Encoded value derived from password using DefaultParams and a fresh random salt. Each call produces a different salt — hashing the same password twice yields two distinct Encoded values.

type Limiter added in v0.1.4

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

Limiter tracks recent timestamps per IP and allows at most max attempts within window. Safe for concurrent use.

func NewLimiter added in v0.1.4

func NewLimiter(max int, window time.Duration) *Limiter

NewLimiter returns a Limiter using the wall clock.

func NewLimiterWithClock added in v0.1.4

func NewLimiterWithClock(max int, window time.Duration, now func() time.Time) *Limiter

NewLimiterWithClock returns a Limiter with an injectable clock. The clock must be monotonic-ish within the window (tests inject a closure that advances deterministically).

func (*Limiter) Allow added in v0.1.4

func (l *Limiter) Allow(ip string) (bool, time.Duration)

Allow records an attempt for ip and reports whether it is within budget. If denied, retryAfter is the duration until the oldest in-window attempt ages out.

func (*Limiter) Reset added in v0.1.4

func (l *Limiter) Reset(ip string)

Reset clears all recorded attempts for ip. Called after a successful login to avoid locking out a legitimate user who mistyped a few times first.

type Params

type Params struct {
	M       uint32 `json:"m"`
	T       uint32 `json:"t"`
	P       uint8  `json:"p"`
	SaltLen uint32 `json:"salt_len"`
	HashLen uint32 `json:"hash_len"`
}

Params holds the argon2id cost parameters. Defaults follow current OWASP guidance for modest-power servers.

type Store

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

Store is a goroutine-safe in-memory map of session tokens to usernames. The zero value is unusable; callers must use NewStore. Single-user assumption: the map contains 0..N entries for a single username (one per device).

func NewStore

func NewStore() *Store

NewStore constructs an empty session store with the default TTL.

func NewStoreWithTTL added in v0.1.4

func NewStoreWithTTL(ttl time.Duration) *Store

NewStoreWithTTL constructs an empty session store with a custom TTL. Exposed for tests; production code should use NewStore.

func (*Store) Create

func (s *Store) Create(username string) (string, error)

Create issues a new random 32-byte session token for username and returns it. Token format: base64.URL-encoded.

func (*Store) EntryCountForTest added in v0.1.4

func (s *Store) EntryCountForTest() int

EntryCountForTest returns the number of map entries. Test-only accessor used to assert lazy eviction.

func (*Store) Lookup

func (s *Store) Lookup(tok string) (string, bool)

Lookup returns the username bound to tok, or ("", false) if the token is unknown. If user.json has been deleted since last check, the entire store is wiped before reporting false. Expired entries (older than the store's TTL) are evicted lazily and reported as not-found.

func (*Store) Revoke

func (s *Store) Revoke(tok string)

Revoke removes the given token. No-op if it doesn't exist.

func (*Store) Seed

func (s *Store) Seed(token, username string)

Seed inserts a pre-known token → username mapping. Intended only for test seams where the caller injects a fixed token via Options.Token.

func (*Store) SetClockForTest added in v0.1.4

func (s *Store) SetClockForTest(now func() time.Time)

SetClockForTest injects a fake clock for TTL tests. Not safe for concurrent use with live traffic; tests only.

func (*Store) SetStaleWindowForTest

func (s *Store) SetStaleWindowForTest(d time.Duration)

SetStaleWindowForTest lets tests force an immediate restat.

func (*Store) Wipe

func (s *Store) Wipe()

Wipe drops every session.

type User

type User struct {
	Username  string    `json:"username"`
	Password  Encoded   `json:"-"`
	CreatedAt time.Time `json:"created_at"`
}

User is the single-user record persisted at userPath().

func Load

func Load() (User, error)

Load reads + parses user.json. Returns fs.ErrNotExist if the file is absent.

Jump to

Keyboard shortcuts

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