feat(auth): Argon2id passwords, opaque tokens, TOTP and recovery codes

Password hashes are self-describing PHC strings, so the cost parameters
can be raised later without locking anyone out: NeedsRehash reports which
hashes to upgrade at the next login, when the plaintext is briefly at hand.

Session, invite, reset and API tokens are stored only as SHA-256 hashes;
the plaintext exists once, in the link or the reply. Unsalted is correct
here and only here — the input is 256 bits of randomness that has to be
found by value in a WHERE clause.

feat(store): project roles with viewer/editor/owner and explicit denial

Roles are strictly ordered so every check is "at least X". Access to a
task is access to its project: being the assignee or the author confers
nothing, or removing someone from a project would leave them holding
tasks inside it. Checks take a Querier so they can run in the same
transaction as the write they guard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-16 23:00:28 +02:00
co-authored by Claude Opus 5
parent b6a44244c1
commit b44db32bf7
8 changed files with 1094 additions and 0 deletions
+3
View File
@@ -5,11 +5,14 @@ go 1.26.3
require modernc.org/sqlite v1.56.0
require (
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.24 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/pquerna/otp v1.5.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/crypto v0.55.0 // indirect
golang.org/x/sys v0.47.0 // indirect
modernc.org/libc v1.74.4 // indirect
modernc.org/mathutil v1.7.1 // indirect