Skip to main content

Module pin

Module pin 

Source
Expand description

Profile PIN: hashing, and the lockout policy that decides what a guess costs.

The policy half is deliberately pure — it takes the stored counter state and the current time, and returns the decision plus the next state. That is what makes “five wrong guesses then a lockout that survives a restart” testable without a database, a clock, or a running app.

What this is not: at-rest protection. The PIN gates switching to a profile; it does not encrypt that profile’s access token, so anyone holding the database and the keyring has every token regardless. That trade is deliberate and its reasoning lives in DR-268 — a wrapped token would leave a locked profile unable to resume its own downloads or drain its own sync queue until somebody walked past and typed the code.

TRACES: UR-083 | DR-268

Structs§

PinState
Persisted counter state for one profile’s PIN.

Enums§

PinDecision
What the caller should do with an attempt.

Constants§

BASE_LOCKOUT_SECS 🔒
How long the first lockout lasts. Each subsequent failure doubles it.
MAX_ATTEMPTS
Wrong guesses allowed before the first lockout.
MAX_LOCKOUT_SECS 🔒
Ceiling on the doubling, so a forgotten PIN never bricks the tile — the password route is always there, and a lockout measured in hours would push people towards not setting a PIN at all.

Functions§

evaluate
Decide an attempt and produce the state to persist.
hash_pin
Hash a PIN for storage. Returns a PHC string with the salt embedded.
validate_pin
A PIN must be 4–8 digits. Rejecting non-digits here rather than in the pad keeps the rule where the rule is enforced.
verify_pin
Compare a candidate PIN against a stored PHC string.