Expand description
Persistent invite-token store (issue #756). Persistent invite-token store (issue #756 / Layer 6 gateway).
Invite tokens are short opaque secrets that grant a one-time-ish right to mint a principal. The kernel never stores the raw token — it stores SHA-256 of the URL-safe base64 form. Redemption hashes the incoming token and compares against the persisted set.
§On-disk layout
$ASTRID_HOME/etc/invites.toml:
[[invite]]
token_hash = "..." # hex(sha256(token)) — 64 hex chars
group = "agent"
remaining_uses = 1
expires_at_epoch = 1234567890
issued_at_epoch = 1234560000
metadata = "alice's tablet"Atomic writes via write-then-rename. The file is owned by the
daemon UID and chmod 0600 — same posture as
~/.astrid/run/system.token.
§Threat model
- Read-only leak: an attacker who reads
invites.tomlsees token hashes, not tokens. They cannot redeem. - Write leak: an attacker who can write
invites.tomlwins anyway — they can plant a hash whose pre-image they know. This matches the existinggroups.toml/profile.tomlthreat model (operator-trusted system files; file-system perms gate access). - Replay: each redemption decrements
remaining_uses; reaching zero removes the entry under the kernel’sadmin_write_lock. - Wall-clock expiry: enforced at redeem time. Expired entries
are removed lazily (next
prune) — no background sweeper is spun up for what is at most a few-hundred-entry file. - Side-channel on lookup: the redeem path uses constant-time comparison on the hash bytes.
Structs§
- Invite
- On-disk persisted invite record. The raw token is NEVER stored — only its SHA-256.
- Invite
Store - File-backed invite store. Read-modify-write with atomic rename;
concurrent mutators must serialise externally (the kernel uses
admin_write_lock).
Enums§
- Invite
Store Error - Errors surfaced by
InviteStoreoperations.
Constants§
- MAX_
EXPIRY_ SECS - Hard cap on a single token’s lifetime. Mirrors the issue’s “max 30 days” guidance; longer-lived invites should issue a fresh token rather than carry one forever.
- TOKEN_
RAW_ LEN - Length of the random token portion in bytes (192 bits → 32 chars URL-safe base64, comfortably exceeding the 128-bit work factor we need against online brute force given the per-IP redeem rate-limit at the gateway).
Functions§
- ct_
hash_ eq - Constant-time hash comparison. Both inputs must be hex-encoded
SHA-256 (64 hex chars). Returns
falseon any length mismatch without leaking the position via short-circuit. - generate_
token - Generate a random URL-safe-base64 token. Uses the OS CSPRNG.
- hash_
token - Hash a token for storage / lookup. Hex-encoded SHA-256.
- now_
epoch - Current wall-clock as seconds since Unix epoch. Saturating on the
(impossible) pre-1970 case so the returned
u64never wraps. - prune_
expired - Borrow-checked helper: prune the in-place list, returning the count
removed. Expired entries (wall-clock expiry passed) and consumed
entries (
remaining_uses == 0) both go. - prune_
file - Same conventions as
prune_expiredbut keyed onpath— used by the handlers under the admin write lock.