feat(fpagent): authenticate the wizard's a2loft calls with the session token

The fingerprint wizard's staff-lookup and fingerprint-save proxies forwarded the page's OTP with the session phone. a2loft resolves that phone against the domain being addressed, so an operator who holds only capture_biometric was rejected unless they were a domain super-user. The cropper already saves with the session token.

- tools/server.js: both a2loft proxies send Authorization: Bearer <session token>, no phone/otp; validateProxy drops the OTP and phone checks.
- tools/public/assets/fp: both OTP fields, otpLookup/otpSave state, request params and resets removed; canLookup/canSave no longer gate on OTP.
- Tests assert the Bearer header, no query auth, no OTP field in the served page, and both gates without a credential (66/66 pass).
- README and Help page updated.

Requires the a2loft fingerprint-token-auth change deployed first. OpenSpec change: fingerprint-token-auth.
This commit is contained in:
2026-10-02 20:41:43 +01:00
parent 548e33390c
commit 14f6fd6a8e
13 changed files with 262 additions and 67 deletions
+8 -8
View File
@@ -107,11 +107,10 @@ is treated as anonymous and the stale cookie cleared.
### a2loft proxy
Staff lookup and the fingerprint save are proxied to `https://apis.a2loft.net`
under same-origin routes. The proxy attaches the operator's phone from the
server-side session and forwards the OTP supplied by the page; the operator
never sends credentials to a third party directly. The cropper's save call
instead authenticates with the session token (`Bearer`) after a live permission
check.
under same-origin routes. The proxy authenticates the operator with the
signed-in session's PocketBase token, sent to a2loft as a `Bearer` credential;
the operator never sends credentials to a third party directly. The cropper's
save call uses the same token flow after a live permission check.
## The Image Cropper
@@ -145,12 +144,13 @@ dotenvx set MINIO_SECRET_KEY "<value>" -f .env # add/rotate a value
The `/fingerprint` wizard walks the operator through:
1. **Locate profile** — pick a permitted domain, enter the staff reference and
OTP, and look up the record through the a2loft proxy.
1. **Locate profile** — pick a permitted domain, enter the staff reference, and
look up the record through the a2loft proxy.
2. **Capture** — right thumb and right index finger, one capture at a time, with
per-scan progress and cancel. The PocketBase token, domain and reference
travel with every `fprint-enroll` to fpagent.
3. **Save** — both templates are posted to a2loft with a fresh OTP.
3. **Save** — both templates are posted to a2loft authenticated with the
session token.
The wizard tracks fpagent's scanner availability: the header tag and the capture
panel show when the agent is offline or no reader is attached, and capture is