From f439beec17419ccbe0dc7643cc039079f15e04a0 Mon Sep 17 00:00:00 2001 From: cirakg Date: Wed, 21 Oct 2026 03:55:15 +0200 Subject: docs: user guide, known limitations and M8 results; bump to 0.8.0 0.8.0 is the release candidate: 1.0.0 is tagged after the on-watch checklist (docs/TESTING.md). Co-Authored-By: Claude Opus 5.5 --- docs/USER_GUIDE.md | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 docs/USER_GUIDE.md (limited to 'docs/USER_GUIDE.md') diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md new file mode 100644 index 0000000..f4fe5f8 --- /dev/null +++ b/docs/USER_GUIDE.md @@ -0,0 +1,194 @@ + +# OTP Wallet user guide + +OTP Wallet keeps one-time passwords (TOTP, HOTP and Steam Guard) and barcodes (loyalty cards, tickets, QR codes) on your Garmin watch, encrypted. Nothing leaves the watch: there is no account, no cloud and no network access. You add entries from the Garmin Connect app on your phone; the watch is the only place they are stored. + +## Contents + +- [Install](#install) +- [Where the settings are](#where-the-settings-are) +- [Add an authenticator code](#add-an-authenticator-code) +- [Import from Aegis or otpauth links](#import-from-aegis-or-otpauth-links) +- [Add a barcode or QR code](#add-a-barcode-or-qr-code) +- [Change, move or delete an entry](#change-move-or-delete-an-entry) +- [The PIN and locked entries](#the-pin-and-locked-entries) +- [Daily use on the watch](#daily-use-on-the-watch) +- [The glance](#the-glance) +- [Options](#options) +- [Moving to a new watch, and backups](#moving-to-a-new-watch-and-backups) +- [Troubleshooting](#troubleshooting) +- [Known limitations](#known-limitations) + +## Install + +Garmin's app settings only work for apps installed from the Connect IQ Store, so OTP Wallet is installed as a private beta that only your Garmin account can see: + +1. The developer uploads the signed package (`make package` builds `build/package/otp-wallet-.iq`) on Garmin's developer site as a beta app. +2. On your phone, open the Connect IQ Store app, find the beta under your apps, and install it on your watch. +3. Each new version is a new upload; the Store updates the watch, and your entries stay (check this once with the [real-watch checklist](TESTING.md#real-watch-checklist)). + +A sideloaded build (copied over USB) runs, but gets no phone settings, so you can't add entries to it. Sideloaded debug builds are for testing with fake demo entries only. + +## Where the settings are + +In the Garmin Connect app: your watch, then **Connect IQ apps**, then **OTP Wallet**, then **Settings**. The settings are a set of forms. Each form has a switch at the bottom ("Add this entry", "Import now", "Apply"); the watch acts on a form only when its switch is on, and only when it receives the settings: + +- If OTP Wallet is open on the watch, it applies the forms within seconds of saving. +- Otherwise it applies them the next time you open it. + +Each form has a **Result** field the watch writes back, and the watch shows the same lines on its **Settings results** screen (also in its menu). After a form is applied the watch turns its switch off and clears it, the secret field first. After a problem only the secret field is cleared, so you can correct the rest and send it again. Sending exactly the same form twice does nothing the second time. + +Your phone may or may not show the cleared fields and the Result text before you reopen the settings page; that depends on Garmin Connect (see [SETTINGS_SPIKE.md](SETTINGS_SPIKE.md)). + +## Add an authenticator code + +Use the **Add OTP** form with the details the website shows when you set up two-factor authentication (choose "can't scan the code?" or "enter the key manually" to see them): + +| Field | What to enter | +| --- | --- | +| Type | TOTP (almost every site), HOTP (counter based) or Steam | +| Issuer (service) and Account | For example "GitHub" and your user name. At least one of them | +| Secret | The key in Base32 (letters A–Z and digits 2–7). Spaces, hyphens and lower case are fine | +| Algorithm, Digits, Period | Leave SHA1, 6 and 30 unless the site says otherwise | +| Counter | HOTP only: the starting counter, usually 0 | +| Group | Optional, shown in the list | +| Require PIN to display | The code is only shown after you enter the app PIN | + +Turn on **Add this entry** and save. The result says, for example, "Added K7F2 GitHub (alice)", or exactly what to fix ("Secret: '1' is not a Base32 character (position 5)"). Check that the watch shows the same code as the website or your phone authenticator before you rely on it. + +## Import from Aegis or otpauth links + +The **Import** form takes the text of an **unencrypted Aegis export** (Aegis: Settings, Import & Export, Export, plain JSON) or any number of `otpauth://` links: + +1. Paste the text into **Text, part 1**. If it is longer than one field takes, continue in the next part; the watch joins parts 1 to 8 in order. +2. Choose the mode: **Add to my entries** (default), or **Replace imported entries** (removes entries that came from earlier imports first; entries you added by hand are never touched). +3. Turn on **Require PIN for these entries** if they should all be locked. +4. Turn on **Import now** and save. + +The report lists how many entries were imported and every one that wasn't, with the reason: duplicates of entries you already have, unsupported types (mOTP, Yandex), or bad values. Aegis favourites stay favourites (see [the glance](#the-glance)); icons and notes are not imported. + +**Long exports.** If the text is still incomplete after joining the fields, the watch keeps what it got (encrypted) and says "Waiting for more: received ... characters". Paste the next part into the fields, turn **Import now** on again, and save. The waiting part expires after 24 hours and is limited to 32 KB; choose the mode **Cancel waiting import** to discard it. A compact export takes about 190 characters per entry; remove icons from the export if it is much larger. + +**Afterwards**, delete the exported JSON file from your phone, and keep such files out of cloud-synced folders. The import fields are cleared on the phone by the watch. + +**iPhone:** if Garmin Connect refuses the `&` in a link, write `;` instead; the watch accepts both. + +Google Authenticator's export links (`otpauth-migration://`) are not supported. Import them into Aegis first and export from there. + +## Add a barcode or QR code + +Use the **Add code** form: + +| Field | What to enter | +| --- | --- | +| Card name | For example "Gym card" | +| Barcode type | QR, Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, ITF, Codabar, Data Matrix, PDF417 or Aztec | +| Contents | The text or digits the code holds (as printed under the code, or what a scanner app reads from it) | +| Error correction | 2D codes: Medium is right for most uses | +| Check digit | EAN, UPC and ITF: "Add or verify" checks the last digit; "Fix if wrong" corrects it | +| Show the text under the bars | The digits under linear codes | +| Group, Require PIN to display | As for OTP entries | + +The watch encodes the code to check it, and warns if it won't fit your screen at a scannable size. 2D codes are drawn the first time you open them ("Encoding… 40%"); after that they open at once. + +## Change, move or delete an entry + +Use the **Manage entry** form with the entry's **ID**: four characters such as `K7F2`, shown at the bottom of each entry on the watch, under **Entry IDs** in the watch menu, and in the **About** group of the settings (the catalog). Case doesn't matter. + +| Action | Fields used | +| --- | --- | +| Edit details | New name, account or group; blank keeps a field, `-` clears it | +| Move to position | The new position, 1 = top | +| Require PIN / Don't require PIN | — | +| Replace secret or contents | The new secret (Base32) or code contents | +| Set HOTP counter | The counter | +| Delete | — | +| Mark as favourite (glance) / Remove favourite | — | + +**Changes to locked entries wait for you.** Anything that would change or reveal a locked entry (everything except moving it) is not applied when it arrives. The watch shows "Phone changes: N to confirm" at the top of its menu and in the list title. Open it, check the list, and choose **Confirm all** (it asks for the PIN, even if the app is unlocked) or **Reject all**. This way, someone with access to your phone alone can't unlock or rewrite your locked entries. + +## The PIN and locked entries + +- **Set PIN** in the watch menu creates it (4 to 10 digits; the watch warns below 6). You are also asked for one the first time an entry needs it. +- Entering the PIN unlocks all locked entries until the app locks again: when you leave the app, after the auto-lock time (option), or with **Lock now** in the menu. +- **Wrong PINs:** after 5 wrong PINs the watch makes you wait, longer with each further mistake. With the option **Erase locked entries after 10 wrong PINs**, the tenth wrong PIN erases the locked entries (unlocked entries stay). +- **Change PIN** keeps your entries. **Reset PIN**, for a forgotten PIN, erases the locked entries and lets you set a new PIN; there is no other way back into them. +- Locked entries are encrypted with a key that only your PIN opens. A short PIN can still be guessed by someone who copies the watch's storage, so choose 6 or more digits for anything important. + +## Daily use on the watch + +- **List:** your entries in your order. Unlocked TOTP and HOTP entries show the current code and a small countdown; locked entries show a lock; barcodes show an icon. +- **Open an entry** (tap it, or START): the code in large digits with a countdown ring; in the last 5 seconds the next code is shown too. For HOTP, tap the code (or START) for the next one. +- **Barcodes** open black on white, at the largest size that fits. They are shown at full brightness for about a minute on AMOLED watches (the screen's own limit; tap to brighten it again), and with the backlight on MIP watches. You can turn this off under Options. +- **Menu** (hold MENU, or long-press the list on touch-only watches): Phone changes, Lock now, Set/Change/Reset PIN, Settings results, Entry IDs, Clock status, About (version, storage, self-test result). +- **BACK** on the list leaves the app and locks everything. + +## The glance + +In the watch's glance loop, OTP Wallet shows the number of entries. With the option **Show the favourite code in the glance** on, it shows instead the current code of your first **favourite** TOTP or Steam entry that doesn't require the PIN, with a bar for the seconds left: + +- Mark an entry as favourite with Manage entry, "Mark as favourite (glance)" (Aegis favourites already are). +- Locked entries and HOTP entries never appear in the glance. +- The glance updates the code once you've opened the app after changing your favourites; turning the option off hides the code at once. +- Anyone who can see your glance loop sees that code, so choose an entry for which that's acceptable ([SECURITY.md](SECURITY.md#glance-code)). + +## Options + +| Option | Default | Meaning | +| --- | --- | --- | +| Lock after | 1 min | How long locked entries stay open without input: immediately, 15 s, 30 s, 1, 2 or 5 minutes | +| Erase locked entries after 10 wrong PINs | Off | See [the PIN](#the-pin-and-locked-entries) | +| Time offset in seconds | 0 | Seconds added to the watch clock if your codes are consistently early or late (−120 to 120) | +| Code size | Large | Size of the digits on the detail screen | +| Theme | Dark | Dark or light screens (barcodes are always black on white) | +| Show groups | On | The group in front of the account in the list | +| Encrypt names on the watch | Off | Keeps names and accounts in the encrypted part too; locked entries then show only "Locked entry" and the About catalog only IDs | +| Show the favourite code in the glance | Off | See [the glance](#the-glance) | +| Full brightness while showing a barcode | On | See [daily use](#daily-use-on-the-watch) | + +## Moving to a new watch, and backups + +OTP Wallet never exports your secrets: they only flow into the watch. Your backup is your authenticator app or Aegis vault (and the recovery codes the websites gave you). To move to a new watch, install OTP Wallet there and import or add your entries again, then delete the app from the old watch (uninstalling removes all its data). + +## Troubleshooting + +| Problem | What to do | +| --- | --- | +| Codes are rejected | Open **Clock status** in the menu. The watch clock must be right to within a few seconds; sync the watch (GPS activity or phone sync). If it is always off by the same amount, set **Time offset** | +| Nothing happens after saving a form | Open OTP Wallet on the watch; forms are applied when the app runs. Check that the form's switch was on | +| "Already added" or "Already imported" | The watch has already applied exactly that form; change something to send a new one | +| "Waiting for more" after an import | The JSON was incomplete: paste the rest and send again, or choose the mode "Cancel waiting import" | +| "Damaged entry K7F2" | That entry's stored data can't be read. Delete it with Manage entry and add it again | +| A barcode says "Too large for this screen" | The contents are too long for a scannable code on this watch. Use a shorter text, or a 2D symbology for long text | +| A barcode doesn't scan | Turn brightness up (the option is on by default), hold the watch steady and flat, and try both closer and further away. Laser scanners at tills often can't read screens | +| "Data from a newer version" | The app was downgraded; install the newest version again | +| "Crypto self-test failed" | The watch's crypto didn't give the expected results; codes are hidden to be safe. Update the watch firmware and report it | + +## Known limitations + +- **Connect IQ limits** + - No unlocking with the watch's own passcode; the app has its own PIN. + - App settings only work with the Store version, which is why the app is a private beta rather than sideloaded. + - The phone may not show what the watch writes back (Result fields, cleared forms, the About catalog) until you reopen the settings. +- **Import** + - Encrypted Aegis exports can't be decrypted on a watch (it would need 32 MiB of memory); export unencrypted. + - Google Authenticator export links aren't supported; mOTP and Yandex entries are skipped. + - Icons and notes aren't imported. + - Pasted text is limited to the eight import fields per sync, and a waiting import to 32 KB. +- **Storage** + - At most 150 entries and about 100 KB in total. + - At most 16 phone changes can wait for the PIN at once. + - The About catalog shows up to 800 characters; the rest are under Entry IDs on the watch. +- **Security** + - Locked entries are only as strong as the PIN against someone who copies the watch's storage; unlocked entries rely on the watch keeping its storage private. + - Secrets and the import text pass through Garmin Connect's settings on your phone. + - See [SECURITY.md](SECURITY.md) and [README section 8](../README.md#8-threat-model). +- **Barcodes** + - Data Matrix uses ASCII and Base256 encoding only (no C40, Text, X12 or EDIFACT), and Aztec a simple mode choice. Their symbols are valid, but sometimes larger than another encoder's. + - PDF417 only fits short contents on small round screens (about 170 codewords on a 218-pixel screen). + - Large 2D codes take a while to encode the first time: seconds for typical cards, up to about a minute for the largest QR codes on the Forerunner 255 and 255S. After that they open from the cache. +- **Glance:** only the first favourite TOTP or Steam entry without the PIN. +- **No backup or export** from the watch, by design. -- cgit v1.2.3