summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md25
1 files changed, 14 insertions, 11 deletions
diff --git a/README.md b/README.md
index ffe2f91..87c3a46 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,14 @@
A Garmin Connect IQ watch app that shows one-time passwords (TOTP, HOTP, and optional Steam Guard codes) and stores barcodes and QR codes (loyalty cards, tickets) to show at a scanner. Everything lives encrypted on the watch. There is no cloud, no backend and no analytics, and the app requests no permissions, so it cannot use the network.
-> **Status: M6 (barcodes) done; next is M7, the phone settings forms; M1 (settings spike) ready for your phone test.** The plan below was approved on 2026-10-18. M0 built the Docker toolchain and pipeline, M2 the crypto and OTP core, M3 the encrypted vault ([docs/SECURITY.md](docs/SECURITY.md)), M4 the screens and M5 import (`otpauth://` and Aegis JSON via the phone settings). M6 added the code screen and all 12 symbologies, encoded on the watch:
+> **Status: M7 (phone settings forms) done; next is M8, polish and release; M1 (settings spike) and the M7 phone check wait for you.** The plan below was approved on 2026-10-18. M0 built the Docker toolchain and pipeline, M2 the crypto and OTP core, M3 the encrypted vault ([docs/SECURITY.md](docs/SECURITY.md)), M4 the screens, M5 import (`otpauth://` and Aegis JSON via the phone settings) and M6 all 12 barcode symbologies, encoded on the watch. M7 added the rest of the phone settings:
>
-> - **Linear codes** are encoded directly.
-> - **QR, Data Matrix, PDF417 and Aztec** are encoded as resumable jobs and cached encrypted.
-> - **Checks:** each is compared with a reference encoder (zxing-cpp, segno, ppf.datamatrix, pdf417gen, aztec_code_generator) and decoded with zxing-cpp. Screenshots of five kinds of code decode on seven simulated watches.
+> - **Add OTP and Add code forms**, validated on the watch (codes by the real encoders), with a short result written back to each form.
+> - **Manage entry** by ID: edit, move, require or drop the PIN, replace the secret or contents, set a HOTP counter, delete. Changes to locked entries wait until you confirm them with the PIN on the watch.
+> - **Options** applied as soon as you save, and a read-only **About** group with the entry IDs.
+> - **Checks:** the resource XML validates against the SDK schema; the UI flow sends the forms the way the phone does and checks the new entries on screenshots.
>
-> The settings spike (`make spike`, [docs/SETTINGS_SPIKE.md](docs/SETTINGS_SPIKE.md)) waits for your test. The Phase 0 research, with sources, is in [docs/FEASIBILITY.md](docs/FEASIBILITY.md); the daily workflow is in [docs/DEVELOPER_GUIDE.md](docs/DEVELOPER_GUIDE.md).
+> The settings spike (`make spike`, [docs/SETTINGS_SPIKE.md](docs/SETTINGS_SPIKE.md)) and the M7 check with the Store beta wait for your phone. The Phase 0 research, with sources, is in [docs/FEASIBILITY.md](docs/FEASIBILITY.md); the daily workflow is in [docs/DEVELOPER_GUIDE.md](docs/DEVELOPER_GUIDE.md).
"OTP Wallet" is a working title.
@@ -207,7 +208,7 @@ Design rules:
| Key | Content | Protected by |
| --- | --- | --- |
-| `m` | Metadata: schema version, entry index (the order of IDs), pending IDs, hashes of applied forms (M7) | Not secret |
+| `m` | Metadata: schema version, entry index (the order of IDs), pending IDs | Not secret |
| `dk` | Device key, 32 random bytes | Stored as is ([7.4](#74-what-stays-readable)) |
| `w` | KDF salt, iteration count and the wrapped locked master key | The PIN key |
| `lk` | Wrong-PIN count and delay | Not secret |
@@ -215,7 +216,8 @@ Design rules:
| `x.<id>` | Cached barcode matrix for a code entry | The same key as its entry |
| `p.<id>` | Pending locked entry, waiting for your PIN | Device key ([7.7](#77-pending-locked-entries)) |
| `imp`, `imp.<n>` | Partial import text, kept between syncs, in chunks below 8 KB | Device key |
-| `res`, `fh`, `st` | Latest settings results; hashes of applied forms; date of the last self-test | Not secret |
+| `q` | Phone changes to locked entries, waiting for your PIN ([7.9](#79-integrity-of-changes-coming-from-the-phone)) | Device key |
+| `res`, `fh`, `cs`, `st` | Latest settings results; keyed hashes of applied forms; signature of the last About update; date of the last self-test | Not secret |
Limits: at most 8 KB per value and about 100 KB in total (the stricter of Garmin's two documented figures). M3 measured 239 bytes for a typical OTP record, so the entry cap stays at 150 (byte formats in [docs/SECURITY.md](docs/SECURITY.md)). A full store produces a clear message, never a crash.
@@ -304,7 +306,7 @@ A locked entry can arrive from settings or an import while the watch is locked,
Anyone who controls your phone or Garmin account can change the settings. So:
-- Actions on locked entries (edit, replace secret, unlock, delete) wait in a queue until you confirm them with the PIN on the watch.
+- Actions on locked entries (edit, replace secret, unlock, set the counter, delete) wait in a queue until you confirm them with the PIN on the watch, even if the watch happens to be unlocked. The menu lists them under "Phone changes", where you confirm (the PIN is always asked) or reject them. "Require PIN" waits too while the watch is locked, because it needs the master key.
- Deleting or editing *unlocked* entries applies directly, and the watch shows what changed.
- New entries always apply, and they're visible in the list.
@@ -423,8 +425,8 @@ Garmin's "array settings" (growable lists) are broken today. A failed save reset
### 10.3 Processing rules
1. **When**: from `onSettingsChanged` while the app runs, and at every app start. Processing runs *after* the first screen is drawn, so it never slows start-up.
-2. **Switches**: a form is processed only when its switch is on. Afterwards the watch turns the switch off and clears the form, secret fields first.
-3. **Idempotency**: Garmin doesn't document whether the phone shows those cleared values ([FEASIBILITY 3e](docs/FEASIBILITY.md#3e-writing-values-back-unknown)). So the watch also remembers a hash of each of the last 32 applied forms and ignores a form it has already applied. Re-sending the same form does nothing; changing anything makes it a new request. Manage actions use stable IDs and absolute positions, so applying one twice can't hit a different entry.
+2. **Switches**: a form is processed only when its switch is on. Afterwards the watch turns the switch off and clears the form, secret fields first. After a problem only the secret field is cleared, so the other fields can be corrected and sent again.
+3. **Idempotency**: Garmin doesn't document whether the phone shows those cleared values ([FEASIBILITY 3e](docs/FEASIBILITY.md#3e-writing-values-back-unknown)). So the watch also remembers a keyed hash of each of the last 32 applied forms and ignores a form it has already applied. Re-sending the same form does nothing; changing anything makes it a new request. Manage actions use stable IDs and absolute positions, so applying one twice can't hit a different entry.
4. **Results** go to the form's status field and to a "Settings results" screen on the watch. That screen opens by itself after processing if the app is open, and is always available from the menu.
5. **Status texts are short and specific**, for example:
- "Added K7F2 GitHub (alice)"
@@ -445,7 +447,7 @@ Code validation, per symbology, is in [section 12.1](#121-symbologies).
### 10.5 XML excerpt
-The full files are written in M7.
+The full files are in `resources/settings/` (written in M7). `make lint` validates them against the SDK's `resources.xsd` and checks that the form, the properties and the strings agree (`tools/check_resources.py`).
```xml
<!-- resources/settings/properties.xml (excerpt) -->
@@ -879,6 +881,7 @@ Done when: each symbology is either marked implemented with every check green, o
- Manage actions on unlocked and locked entries.
- End-to-end: a manually entered entry, set through a debug fixture that takes the same path as the phone, shows the right TOTP code or a barcode that decodes correctly, on screenshots.
- **Done when**: everything passes, the XML validates against the SDK schema, and you've confirmed it on your phone and watch with the beta.
+- **Status (2026-10-20)**: everything passes in Docker and the XML validates; the phone and watch check with the beta is yours ([docs/TESTING.md](docs/TESTING.md#real-watch-checklist)).
### M8: Polish, performance, release