Fix pipeline diagram and document backup habits and dedup behavior

Replace the misaligned box diagram with a clean vertical flow. Expand
the intro to explain bulk-loading one or many authenticators and how
duplicates are handled at each stage. Add a "Backing up your OTP keys"
section covering screenshotting QR codes to secure storage with a
filename convention, and saving one-time backup/recovery codes.
This commit is contained in:
2026-07-08 16:08:12 -07:00
parent 3560964188
commit 08c77e1124

View File

@@ -1,27 +1,87 @@
# otp-import
Move TOTP credentials from saved authenticator **QR-code screenshots** onto a
**VivoKey Apex** OTP applet (the ykneo-oath applet), by way of a plain,
human-editable **CSV**.
Bulk-load your saved authenticator **QR-code screenshots** onto a **VivoKey
Apex** OTP applet (the ykneo-oath applet) — or onto several implants at once — by
way of a plain, human-editable **CSV**.
Two small command-line tools:
If you screenshot your two-factor QR codes as you enroll them (see
[Backing up your OTP keys](#backing-up-your-otp-keys) below), these two tools
turn that pile of screenshots into working TOTP credentials on a new or
replacement authenticator, and can load the identical set onto multiple devices.
- `qr_to_sheet.py` — decode QR screenshots into the CSV (no hardware needed).
- `apex_otp_import.py` — write the CSV's credentials onto the applet over PC/SC.
**Duplicates are handled at both stages, so you can re-run freely:**
- **QR → CSV** deduplicates on the `otpauth://` data: re-scanning a folder only
appends codes that aren't already in the CSV; ones already present are silently
skipped. Two screenshots of the *same account with different secrets* (e.g. a
re-enrollment) are both kept — they are genuinely different credentials.
- **CSV → applet** keys credentials by name (`issuer:account`): if a name is
already on the applet you are asked to overwrite or skip it (or pass
`--overwrite-all` / `--skip-existing`). Loading the same CSV onto a second
implant just repeats the write. And before writing, the importer halts if two
rows would collide on the same name — so a re-enrollment with a new secret
can't silently clobber the old one; you relabel one of them first.
## Backing up your OTP keys
This utility is only useful if you saved your OTP keys in the first place. When
you turn on TOTP two-factor authentication somewhere, the site shows a QR code
(and usually a "can't scan it? enter this code instead" secret). That QR encodes
an `otpauth://` URI containing the shared secret — capture it **then**, because
you generally cannot retrieve it later without disabling and re-enrolling 2FA.
A good habit, every time you enable 2FA:
1. **Screenshot the QR code** and save the image to secure storage. The tools
read the `otpauth://` data inside the image, not the filename, so the naming
scheme is purely for your own organization — but a consistent one keeps the
folder browsable and sortable. A practical convention is
`YYYY-MM-DD-<relying-party>-<account>`:
```
2024-05-01-github-alice@example.com.png
2025-11-02-aws-root@example.com.png
```
Date first so the folder sorts chronologically, then the service (relying
party), then which account it is.
2. **Save the one-time backup/recovery codes too.** Most sites offer a set of
single-use recovery codes next to the QR — copy them into a text file beside
the screenshot (e.g. `2024-05-01-github-alice@example.com-backup-codes.txt`).
If you ever lose every authenticator, those codes are how you get back in.
(This tool doesn't process them; they're your independent recovery path.)
3. **Keep it all in secure storage.** These files contain live secrets — treat
them like passwords. Good homes: a password-manager vault, an encrypted
volume, or an end-to-end-encrypted cloud folder. Never commit them to a
repository (this repo's `.gitignore` deliberately excludes `*.png`, `*.csv`,
and backup-code text files).
With that habit in place, provisioning a new, replacement, or spare Apex is just
pointing these tools at the folder.
---
## The pipeline
```
QR screenshots otp-keys.csv Apex OTP applet
┌───────────────┐ ┌──────────────┐ ┌───────────────┐
│ *.png / *.jpg │──(1)──▶ │ issuer │──(3)───────▶ │ TOTP creds │
│ otpauth://... │ │ account │ PUT/auth │ (ykneo-oath) │
└───────────────┘ │ otpauth_uri │ └───────────────┘
source_file
(2) edit labels here
└──────────────┘
QR screenshots (*.png / *.jpg, each holding an otpauth:// URI)
|
| (1) qr_to_sheet.py
| decode each QR; append only NEW otpauth:// data to the CSV
v
otp-keys.csv columns: issuer | account | otpauth_uri | source_file
|
| (2) optional: edit the issuer / account labels (never otpauth_uri)
|
| (3) apex_otp_import.py
| validate the CSV, authenticate if needed, PUT each credential
v
Apex OTP applet (ykneo-oath) one TOTP credential per row
```
1. **QR → CSV** (`qr_to_sheet.py`): decode each screenshot and append any