From 7e2e98b30a1cda71dac3ddeaeeae5591b2647eba Mon Sep 17 00:00:00 2001 From: Donkie Date: Mon, 17 Aug 2026 21:36:48 +0200 Subject: [PATCH] design: correct two claims the shipped relay made false The phase 1 doc still said 'not yet implemented', and pointed at a TagsSection path the frontend did not use. More worth fixing: both documents offered an unguessable reader_id as a weak secret for people who care. The reader registry that shipped alongside undoes that entirely, since GET /api/v1/tag/reader hands every recently-seen reader id to any caller by design, so the picker can list them. Offering obscurity that the same API gives away is worse than offering none. --- design/nfc-phase-1-tag-identity.md | 16 +++++++++++----- design/wiki-tag-scanners.md | 6 +++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/design/nfc-phase-1-tag-identity.md b/design/nfc-phase-1-tag-identity.md index c1b7d0de..612ac848 100644 --- a/design/nfc-phase-1-tag-identity.md +++ b/design/nfc-phase-1-tag-identity.md @@ -1,6 +1,8 @@ # NFC Phase 1 — Tag identity, lookup, and the scan relay -Status: design, not yet implemented. +Status: implemented. This document is the design as built, kept for the reasoning behind the +decisions rather than as a plan; the endpoint reference that users need lives in +[`wiki-tag-scanners.md`](./wiki-tag-scanners.md) and the generated API docs. Companion document: [`nfc-phase-2-openprinttag.md`](./nfc-phase-2-openprinttag.md). --- @@ -353,9 +355,13 @@ Guard rails, all of which matter: Spoolman ships with no authentication. Any device on the LAN can POST a scan and make paired browsers navigate. The blast radius is navigation only — no data is written by a scan — but it -should be stated plainly in the docs rather than discovered. An unguessable `reader_id` acts as a -weak shared secret for users who care; do not present it as a real one. This is consistent with the -existing threat model, where anyone on the LAN can already `DELETE` a spool. +should be stated plainly in the docs rather than discovered. This is consistent with the existing +threat model, where anyone on the LAN can already `DELETE` a spool. + +An earlier draft of this section offered an unguessable `reader_id` as a weak shared secret for +users who care. Shipping the reader registry killed that idea and the docs should not repeat it: +`GET /api/v1/tag/reader` hands every recently-seen reader id to any caller, because that is what +the "choose a reader" picker reads. The obscurity is worth nothing, so do not offer it. --- @@ -609,7 +615,7 @@ builds the response. No background task, no lifecycle hook, nothing to shut down | `client_v2/src/lib/api/scanRelay.ts` | The scan websocket client: connect, resubscribe, reconnect. | | `client_v2/src/lib/stores/scanner.svelte.ts` | Paired `reader_id`, auto-navigate toggle, most recent scan. localStorage-backed, following `theme.svelte.ts`. | | `client_v2/src/lib/utils/nfc.ts` | Web NFC wrapper plus the `'NDEFReader' in window` capability check, so no component touches the API directly. | -| `client_v2/src/lib/components/library/TagsSection.svelte` | The inspector's tag list and unlink control, modeled on `ExtraFieldsSection.svelte`. | +| `client_v2/src/lib/components/TagsSection.svelte` | The inspector's tag list and unlink control, modeled on `ExtraFieldsSection.svelte`. | | `client_v2/src/lib/components/AddTagModal.svelte` | Link a tag by relay scan, by Web NFC, or by typing a UID. | | `client_v2/src/lib/components/settings/ScannerSettings.svelte` | Pair by tap, show current pairing, unpair, auto-navigate toggle. | diff --git a/design/wiki-tag-scanners.md b/design/wiki-tag-scanners.md index a05c43fd..8e841fe6 100644 --- a/design/wiki-tag-scanners.md +++ b/design/wiki-tag-scanners.md @@ -484,7 +484,11 @@ never sees a de-duplicated scan as a failed lookup. **There is no authentication.** Spoolman has none, and the tag endpoints are the same. Anything on your network can report a scan and navigate a paired browser. Worst case, it moves someone's page. -Scans don't write. Keep Spoolman off the open internet, as the [security page](https://github.com/Donkie/Spoolman/wiki/Security) advises. An unguessable `reader_id` makes it harder to target a specific browser. It's not a password. +Scans don't write. Keep Spoolman off the open internet, as the [security page](https://github.com/Donkie/Spoolman/wiki/Security) advises. + +Do not treat a hard-to-guess `reader_id` as any kind of secret. `GET /api/v1/tag/reader` lists every +reader that has scanned recently, by id and name, to anyone who can reach the API, which is what +makes the "choose a reader" picker work. Guessing is not required. **Reader state is per server process.** The recently-seen list and de-duplication window live in memory. If you run Spoolman with multiple workers, each has its own, and readers come and go. The