Files
Evan JarrettandClaude Fable 5.1 87eff20ae8 appview: drop the bcrypt fallback for device secret authentication
Migration 0028 made devices.secret_lookup (hex(sha256(secret))) the verifier
for device authentication, but it could not be backfilled: the plaintext is
not recoverable from the bcrypt hash. Rows created before it were left NULL,
and ValidateDeviceSecret carried a fallback that scanned every such row with
bcrypt.CompareHashAndPassword and then lazily wrote the lookup value in.

That branch is the last way a single legacy row can put an O(number of
devices) bcrypt scan back on /auth/token, which is the defect 0028 was written
to remove. Production has no NULL-lookup rows left, so it is removed: the
indexed lookup is now the only path, and a miss is an authentication failure.
validateBySecretLookup is folded into ValidateDeviceSecret, since there is no
longer a second path to fall through to.

bcrypt is still written at device creation. secret_hash backs the UNIQUE
constraint and keys UpdateLastUsed; it is simply never compared against on the
authentication path.

Migration 0036 deletes rows with a NULL or empty secret_lookup. They cannot
authenticate once the fallback is gone, and leaving them would only misreport
them as live devices in the UI and the MAU queries. The column stays nullable
because SQLite cannot add NOT NULL to an existing column without a table
rebuild, and a NULL now reads as a non-match either way.

Tests: TestDeviceStore_LegacyDeviceBackfills is replaced by
TestDeviceStore_NullSecretLookupDoesNotAuthenticate, which asserts a row whose
secret_hash genuinely matches the presented secret is still rejected once its
lookup value is cleared, and that nothing backfills it. test/e2e/seed-legacy-
devices.go existed only to reproduce the legacy scan and is deleted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PD7KfLzE27F3qeCqDSwF3
2026-09-12 12:53:26 -05:00
..
2026-05-09 21:21:20 -05:00
2026-01-04 22:39:48 -06:00
2026-01-06 23:56:17 -06:00
2026-02-03 20:35:13 -06:00