From 6769bf4b0f45f6a4ed85698d3d0e116f88fff0d5 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Sun, 9 Aug 2026 05:05:50 +0000 Subject: [PATCH] fix(auth): make account lockout recoverable and visible The lockout was checked before the password was verified, so a correct password on a locked account returned the same generic invalid-credentials error as a wrong one. Users had no way to tell the two apart, and the natural response was to keep retrying a password that was already right. Completing a password reset did not clear the lock either, so the one recovery path the UI advertises appeared to fail for up to fifteen minutes after a successful reset. Verify the password first and report the lockout, with the remaining wait, only when the supplied password was correct. Someone guessing wrong passwords still gets the generic failure, so account existence is not leaked. Clear the lock whenever a password is reset or changed, and give admins an explicit unlock action for the case where waiting is not acceptable. --- .github/pull_request_template.md | 33 ++------ client/src/features/admin/UsersPage.vue | 46 ++++++++++- .../admin/__tests__/UsersPage.spec.ts | 29 +++++++ .../features/admin/composables/useUsers.ts | 1 + client/src/features/auth/LoginPage.vue | 11 ++- .../composables/__tests__/useAuth.spec.ts | 19 +++++ .../src/features/auth/composables/useAuth.ts | 12 ++- client/src/locales/en.json | 11 ++- packages/types/src/audit.ts | 1 + packages/types/src/auth.ts | 4 + .../common/filters/http-exception.filter.ts | 2 + server/src/modules/auth/auth.service.test.ts | 78 +++++++++++++++++++ server/src/modules/auth/auth.service.ts | 59 +++++++++----- .../src/modules/user/user.controller.test.ts | 3 + server/src/modules/user/user.controller.ts | 12 +++ .../src/modules/user/user.repository.test.ts | 8 ++ server/src/modules/user/user.repository.ts | 7 ++ server/src/modules/user/user.service.ts | 10 +++ server/test/auth-session-security.e2e-spec.ts | 62 +++++++++++++++ .../route-inventory/manifest.json | 4 +- .../route-inventory/routes-07.json | 12 +++ 21 files changed, 366 insertions(+), 58 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1b9db532c..bef54e610 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,9 +8,7 @@ Closes # - **Maintainer approval:** (link to the approval comment) - **Assigned contributor:** @ -- **Type:** bug fix | feature | refactor | docs | chore - **UI changed:** yes | no -- **How I ran this:** `pnpm dev` | Docker | I did not run it - **Evidence captured at commit:** (run `git rev-parse --short HEAD`) ## What changed @@ -38,33 +36,13 @@ summarize it. ## Evidence -Upload a recording that proves the changed behavior works in the real client. Show the starting state, -the user action, and the final result. If the workflow crosses multiple clients, show the result in -each affected client. +Upload a video of yourself using the change in the app. Show what it looked like before, what you +did, and what happened. -Ready-for-review PRs without the required evidence will not be reviewed. Keep the PR in draft until -the evidence has been uploaded. +Record it yourself. Videos made by a model, or by a coding agent driving the app, do not count, and +the PR will be closed without review. -Examples: - -- **Web:** Start from a page load, perform the affected workflow, and show the saved result after - refreshing the page. -- **KOReader:** Perform the affected workflow inside KOReader and show the result there. For sync - changes, also show the corresponding result in BookOrbit. -- **Kobo:** Perform the affected workflow on the device, run the sync, and show the resulting state on - the device and in BookOrbit where applicable. -- **Scanner, import, or metadata:** Add or modify a real book, run the operation through its normal - BookOrbit control, and show the resulting book state in the BookOrbit UI. -- **Server code used by a client:** Trigger the behavior from that client and show the result in the - client. Calling the endpoint directly is not end-to-end evidence. - -"No UI changes," written testing claims, automated test output, logs, API requests, database queries, -and direct service calls are not evidence. They may support the recording but cannot replace it. - -Evidence must match the final commit. If the workflow cannot be demonstrated in its real client or -device, keep the PR in draft and state what remains untested. - - + ## Authorship and review @@ -83,7 +61,6 @@ AI assistance is welcome on this project; unreviewed AI output is not. See the - [ ] One focused change, linked above to an issue a maintainer approved - [ ] I discussed my approach and was assigned the issue before writing code or opening this PR -- [ ] I read every line of the final diff - [ ] `pnpm verify` passes against the final diff - [ ] Tests added or updated per the [testing expectations](https://github.com/bookorbit/bookorbit/blob/main/docs/CONTRIBUTING.md#phase-7-write-and-run-tests) - [ ] User-facing text uses Vue I18n keys added only to `client/src/locales/en.json`; non-English catalogs are unchanged, and accessibility was checked diff --git a/client/src/features/admin/UsersPage.vue b/client/src/features/admin/UsersPage.vue index d612e4e94..a28df4fe6 100644 --- a/client/src/features/admin/UsersPage.vue +++ b/client/src/features/admin/UsersPage.vue @@ -1,7 +1,7 @@