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:
@@ -0,0 +1,60 @@
|
||||
# Spec Delta: fingerprint-wizard
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Two-finger enrollment flow
|
||||
The wizard SHALL enroll a profile by: selecting a permitted domain, looking
|
||||
up staff by reference (token-validated through the a2loft proxy), displaying
|
||||
the staff details, capturing the right thumb and right index finger, and
|
||||
saving both fingerprints through the a2loft proxy authenticated with the
|
||||
session token. The wizard SHALL offer per-finger recapture until save, SHALL
|
||||
require both fingers before save, and SHALL reset domain-independent state
|
||||
(reference, staff details, captured artifacts) when starting a new
|
||||
enrollment.
|
||||
|
||||
#### Scenario: Complete enrollment
|
||||
- **WHEN** the operator looks up staff, captures both fingers, and saves
|
||||
- **THEN** both fingerprints are saved through the a2loft proxy and the
|
||||
wizard reports success
|
||||
|
||||
#### Scenario: Save requires both fingers
|
||||
- **WHEN** the operator attempts to save with only one finger captured
|
||||
- **THEN** the wizard rejects the save and explains both fingers are
|
||||
required
|
||||
|
||||
#### Scenario: New enrollment resets state
|
||||
- **WHEN** the operator starts a new enrollment after a save
|
||||
- **THEN** the reference, staff details, and captured finger artifacts are
|
||||
cleared while the permitted domain list persists
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: OTP validated on every a2loft call
|
||||
**Reason**: a2loft's fingerprint staff-lookup and save endpoints now accept the
|
||||
session's PocketBase token, so the operator proves identity with the session
|
||||
instead of a per-call OTP. The OTP scoped operators to the domain's uploader
|
||||
list and rejected capture agents who hold only `capture_biometric`.
|
||||
**Migration**: the wizard sends the session token through the same-origin
|
||||
proxy and collects no OTP; a2loft keeps OTP mode for other clients.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Token authenticated on every a2loft call
|
||||
The wizard SHALL authenticate each a2loft call — staff lookup and fingerprint
|
||||
save — with the signed-in operator's PocketBase session token, sent by the
|
||||
same-origin proxy as an `Authorization: Bearer` credential. The wizard SHALL
|
||||
NOT collect an OTP.
|
||||
|
||||
#### Scenario: Lookup uses the session token
|
||||
- **WHEN** the operator submits a reference
|
||||
- **THEN** the wizard calls the staff-lookup proxy and a2loft authenticates the
|
||||
session token
|
||||
|
||||
#### Scenario: Save uses the session token
|
||||
- **WHEN** the operator saves the captured fingerprints
|
||||
- **THEN** the wizard calls the fingerprint-save proxy and a2loft authenticates
|
||||
the session token
|
||||
|
||||
#### Scenario: No OTP field
|
||||
- **WHEN** the wizard page is served
|
||||
- **THEN** it offers no OTP input for lookup or save
|
||||
@@ -0,0 +1,26 @@
|
||||
# Spec Delta: tools-app
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: a2loft proxies inject operator identity
|
||||
The app SHALL proxy staff lookup and fingerprint-save calls to
|
||||
`https://apis.a2loft.net` under same-origin API routes. The proxy SHALL
|
||||
authenticate the operator with the signed-in session's PocketBase token, sent
|
||||
as an `Authorization: Bearer` credential, preserving the a2loft request and
|
||||
response shapes. The proxies SHALL require a session; a request without one
|
||||
SHALL be rejected without contacting a2loft. The proxies SHALL NOT forward or
|
||||
require an OTP.
|
||||
|
||||
#### Scenario: Staff lookup via proxy
|
||||
- **WHEN** the page requests staff details for a domain and reference
|
||||
- **THEN** the app calls a2loft's identity endpoint with the session token as a
|
||||
bearer credential and returns a2loft's response unchanged
|
||||
|
||||
#### Scenario: Fingerprint save via proxy
|
||||
- **WHEN** the page saves fingerprints for a domain and reference
|
||||
- **THEN** the app posts them to a2loft's fingerprint endpoint with the session
|
||||
token as a bearer credential
|
||||
|
||||
#### Scenario: Unauthenticated proxy call rejected
|
||||
- **WHEN** a proxy route is called without a valid session
|
||||
- **THEN** the app rejects the call without contacting a2loft
|
||||
Reference in New Issue
Block a user