# YOUreka Tools — Fingerprint Service A small Express app that hosts the YOUreka tools landing page and the **Fingerprint Agent** enrollment wizard. Fingerprint capture is performed by the local [`fpagent`](../fingerprint-agent) binary (Socket.IO on `127.0.0.1:9000`); this app provides the login (YOUreka Auth), the permitted domain selection, and the a2loft integration that stores the enrolled fingerprints. ## Layout ``` tools/ ├── server.js # Express app: routes, session middleware, proxies ├── yrka-auth.js # YOUreka Auth cookie session → PocketBase (authRefresh) ├── permit.js # OpenFGA domain permission checks + 5-minute cache ├── public/ │ ├── index.html # landing page (Image Cropper + Fingerprint Agent) │ └── assets/ │ ├── style.css │ └── fp/ # /fingerprint enrollment wizard (Vue 2 via CDN) └── test/ # node --test suite (fake portal / PocketBase / a2loft) ``` ## Running Prerequisites: Node.js 22+, `fpagent` installed and running on this laptop (see the fingerprint-agent repository for installation), the U.are.U 4500 scanner attached. ```sh cd tools npm install npm start # → http://localhost:4173 ``` Open http://localhost:4173 and sign in with your YOUreka account. > fpagent must allow the tools origin. On a dev machine run it with: > `fpagent -allowed-origins http://localhost:4173` ## How enrollment works 1. **Sign in** — YOUreka Auth (portal web-auth redirect). The PocketBase session is kept in an httpOnly cookie and refreshed server-side. 2. **Pick a domain** — the hardcoded catalog (UNICAL, Metropolitan Hotel, UCTH, UNICAL Radio International, YOUreka) is filtered against the same portal OpenFGA endpoint fpagent uses (`capture_biometric` per domain). Results are cached for 5 minutes; the **Refresh domains** control unlocks once the cache expires. fpagent re-authorizes every capture regardless. 3. **Locate the staff profile** — reference + OTP, validated by `apis.a2loft.net` through a same-origin proxy (the operator's phone comes from the session). 4. **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. 5. **Save** — both templates are posted to a2loft (with a fresh OTP). ## Configuration Everything is hardcoded in `tools/server.js` by design — port `4173`, portal `https://portal.yrka.app`, PocketBase `https://pb.itcass.net`, a2loft `https://apis.a2loft.net`, agent `http://127.0.0.1:9000`, and the domain catalog. Change them there; there are no environment variables or config files. ## The Image Cropper The `/cropper` page (Smart Photo Editor) lets operators review, crop and save identity photos. It reuses the YOUreka session for identity, requires the `crop_image` permission on `domain:idid` for every proxied action (verified against the portal's OpenFGA endpoint — live on save, 5-minute cached on reads), and keeps the a2loft OTP requirement only on the save step. Its service credentials are the sole environment variables this app uses. They live in dotenvx-encrypted files at the repository root — `.env` for development, `.env.production` for deployment: ```sh MINIO_ACCESS_KEY=… MINIO_SECRET_KEY=… AZURE_STORAGE_CONNECTION_STRING=… NODERED_HTTP_USERNAME=… NODERED_HTTP_PASSWORD=… CARVEKIT_API_KEY=… ``` Without them the rest of the app works and `/cropper` routes answer `503`. The private decryption keys sit in `.env.keys` (gitignored, never commit it). ```sh dotenvx run -f .env -- node tools/server.js # local, from the repo root dotenvx set MINIO_SECRET_KEY "" -f .env # add/rotate a value ``` The Docker image contains the encrypted `.env.production` and runs through `dotenvx`; only the private key is supplied at runtime (never baked in): ```sh docker build -t yreka-tools . docker run -d -p 4173:4173 --name yreka-tools \ --env DOTENV_PRIVATE_KEY_PRODUCTION="$(grep -oP '^DOTENV_PRIVATE_KEY_PRODUCTION=\K.*' .env.keys)" \ yreka-tools ``` `dotenvx run --strict` makes the container exit rather than start with undecryptable credentials. Note that `--env` values are visible to `docker inspect`; on a shared host prefer an env file with restrictive permissions (`--env-file deploy.keys`) or your platform's secret store. ## Tests ```sh cd tools npm test # node --test — 35 tests, no network or hardware required ``` ## Docker ## Docker The app is stateless, so the container only serves the web front-end; fpagent keeps running on the operator's laptop (the wizard connects to `http://127.0.0.1:9000` from the browser, wherever this container lives). ```sh docker build -t yreka-tools . docker run -d -p 4173:4173 --name yreka-tools yreka-tools ``` Behind a TLS-terminating proxy the app honours `X-Forwarded-Proto` (`trust proxy` is enabled), so session cookies get the `Secure` flag automatically. Field walkthrough (real portal, PocketBase, a2loft, and U.are.U 4500): login → permitted-domain filtering → staff lookup → two scanner captures with cancel path → save → reset, all verified end to end via Playwright.