aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md9
1 files changed, 5 insertions, 4 deletions
diff --git a/README.md b/README.md
index 266919b..5d3dff3 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
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: M4 (UI core) done; 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 added the crypto and OTP core, verified against official test vectors. M3 added the encrypted vault ([docs/SECURITY.md](docs/SECURITY.md)). M4 added the screens: the list with live codes, OTP detail with countdown ring, PIN entry (keypad or button selector) with lockout, menu, info screens and the glance, tested by a scripted UI flow with screenshots on seven simulated watches. Next is M5, import. 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).
+> **Status: M5 (import) done; 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)) and M4 the screens. M5 added import: `otpauth://` links and unencrypted Aegis JSON pasted into the new Import group of the phone settings, parsed on the watch with a streaming JSON tokenizer. It also detects duplicates, supports multi-part pastes and shows a results screen. It's tested with fixtures, a seeded fuzz corpus, and a 100-entry import through the settings path on seven simulated watches. Google Authenticator exports are deferred. Next is M6, barcodes. 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).
"OTP Wallet" is a working title.
@@ -208,7 +208,8 @@ Design rules:
| `e.<id>` | One entry record | Device key, or the locked master key for locked entries |
| `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` | Partial import text, kept between syncs | Device key |
+| `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 |
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.
@@ -501,12 +502,12 @@ The full files are written in M7.
- **`otpauth://` URIs** for `totp`, `hotp` and `steam`. Paste one or many, separated by spaces or line breaks, or simply run together: a new URI starts at every `otpauth://`.
- **Aegis unencrypted JSON export**: vault format version 1, database versions 1, 2 and 3. Detected by a leading `{`.
-- **Stretch goal**: Google Authenticator `otpauth-migration://offline?data=...` exports. The format is reverse-engineered (Base64 and protobuf). It's built in M5 if time allows; otherwise it's listed as deferred.
+- **Deferred: Google Authenticator** `otpauth-migration://offline?data=...` exports. This was the stretch goal. M5 ran out of the time set aside for it: the format is reverse-engineered (Base64 and protobuf), and its fixtures would have to be built from scratch. The importer recognises these links and explains that they aren't supported yet. Exporting from Aegis (which imports Google Authenticator) works today.
### 11.2 Getting the text into settings
- **Fields**: the eight import fields are joined in order. If the text is longer than one field accepts, continue in the next one.
-- **Several syncs**: if the JSON is still incomplete after joining, the watch keeps what it got (encrypted under the device key) and reports: "Waiting for more: received 3,214 characters. Paste the next part into the import fields and turn 'Import now' on again." "Cancel pending import" discards it. The buffer is capped (initially 32 KB, set after measurements) and expires after 24 hours.
+- **Several syncs**: if the JSON is still incomplete after joining, the watch keeps what it got (encrypted under the device key) and reports: "Waiting for more: received 3,214 characters. Paste the next part into the import fields and turn 'Import now' on again." "Cancel pending import" discards it. The buffer is capped at 32 KB and expires after 24 hours. M5 measured an Aegis export at about 190 bytes per entry compact, and 400 to 500 pretty-printed. Exports larger than the cap need to be split into several imports.
- **Size reality**: pretty-printed Aegis JSON takes about 400 to 500 characters per entry without icons. Icons add several KB each and are the main reason a paste might not fit. An `otpauth://` URI takes about 80 to 200 characters.
- **iPhone**: Garmin Connect on iOS reportedly rejects `&` (present in every URI with parameters) and `\` (used in JSON escapes). The settings spike checks this. If it's confirmed, the parser also accepts `;` in place of `&`, and the user guide explains the workaround.