adebisi-fa 645d3d2bc9 fix(cropper): alias the queue's core domain to uc; show server error text
Saving failed with 400 'Unknown domain.' because queue items carry the
legacy domain 'core', which the old bot mapped to 'uc' for a2loft URLs —
my domain validation (added in the review pass) rejected it. The save now
applies the same alias before validating and forwarding.

Also: the client showed axios's generic 'Request failed with status code
400' because the catch destructured error.message; all cropper handlers now
prefer the server's response.data.message (errMessage helper), so the real
reason is visible.

Verified: save with a 'core' item forwards to /identity/uc/profile/picture;
a 400 shows 'Unknown domain.'; 46 tests.
2026-10-01 10:35:02 +01:00
2021-12-08 14:35:55 +01:00

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 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.

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:

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).

dotenvx run -f .env -- node tools/server.js          # local, from the repo root
dotenvx set MINIO_SECRET_KEY "<value>" -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):

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

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).

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.

S
Description
The web front-end for YOUreka ID field operations. A small Express app that hosts an authentication-aware landing page, an **Image Cropper**, a **Fingerprint Agent** enrollment wizard, and a public **Help** page.
Readme
920 KiB
Languages
JavaScript 74.7%
HTML 14.7%
CSS 6.9%
Shell 3%
Dockerfile 0.7%