Document the self-service password change
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
This commit is contained in:
41
CLAUDE.md
41
CLAUDE.md
@@ -2470,6 +2470,47 @@ carrying no host or username, another merchant's shop and camera both 404,
|
||||
malformed identifiers 404 rather than 500, one real sale (INR 1000, V-1) read
|
||||
back by id, and every tenant route still 200 for an ordinary tenant account.
|
||||
|
||||
## Nobody could change their own password
|
||||
|
||||
`POST /api/auth/password`. The cost of its absence was measured rather than
|
||||
argued. Rotating the three production accounts took a shell on the host, three
|
||||
round trips, and briefly left the **platform admin** — the account that reads
|
||||
every company on the estate — with the password `PASTE_IT_HERE`, because a
|
||||
placeholder in a pasted command was taken literally and there was no way to
|
||||
correct it from the product itself.
|
||||
|
||||
A manager could always reset somebody *else's* password. A platform admin could
|
||||
be reset by nobody: they have no client, so the team routes are not theirs, and
|
||||
`provision user` on the host was the only route. For software that puts
|
||||
accounts on shop-floor PCs and staff phones, this is not a feature — it is what
|
||||
makes every other credential decision recoverable.
|
||||
|
||||
- **`authed`, not `tenantOnly`.** A session is not a company's data, and the
|
||||
account with no company is precisely the one that had no route. Scoping it by
|
||||
client would have reproduced the hole it exists to close — which is also why
|
||||
`SetUserPassword` is not client-scoped the way `ResetMemberPassword` beside
|
||||
it is. The user id comes from the verified session, never the request.
|
||||
- **The current password is required**, or an access token alone takes an
|
||||
account over permanently instead of for the rest of the day.
|
||||
- **Every other session is revoked and the caller's is kept.** A failure there
|
||||
is logged, not returned: the password is already changed, and an error would
|
||||
send the user to retry with a current password that no longer exists.
|
||||
|
||||
Verified live against production: wrong current password 403 and nothing
|
||||
changed, a change revoking **45** stale sessions while the caller's own
|
||||
survived, the new password in and the old one out, then changed back.
|
||||
|
||||
### And a shell quoting trap worth not repeating
|
||||
|
||||
The first attempt to rotate the admin password from the operator's terminal
|
||||
ran with the literal string `PASTE_IT_HERE`. The second, reading the value out
|
||||
of a file, produced **no output at all** and changed nothing — `~` was not
|
||||
expanded in that eval context, `awk` could not open the file, returned
|
||||
non-zero, and `&&` short-circuited silently. Absolute paths and `;` instead of
|
||||
`&&` fixed it, and echoing the password *length* first is what proved the
|
||||
third attempt was about to set something real. A command handed to somebody to
|
||||
paste should contain nothing to edit and should fail loudly.
|
||||
|
||||
## Setting up on a new machine
|
||||
|
||||
1. Copy the `Behavision` folder **including `.env`** (gitignored, holds
|
||||
|
||||
Reference in New Issue
Block a user