Add QR-to-CSV utility and switch canonical format to CSV
Add qr_to_sheet.py: decode saved OTP QR screenshots and append new credentials to the canonical CSV, deduplicated on the otpauth:// data. Add otpauth.py (parse_otpauth / canonical_key / build_otpauth), shared by both tools. The canonical format becomes a minimal CSV (issuer, account, otpauth_uri, source_file); load_credentials reads CSV or xlsx and derives crypto from the immutable otpauth_uri while taking issuer/account from their editable label columns.
This commit is contained in:
48
README.md
48
README.md
@@ -1,14 +1,40 @@
|
||||
# otp-import
|
||||
|
||||
Import TOTP credentials from an exported spreadsheet into a VivoKey Apex OTP
|
||||
(ykneo-oath) applet over PC/SC.
|
||||
Turn saved OTP QR-code screenshots into credentials on a VivoKey Apex OTP
|
||||
(ykneo-oath) applet, via a canonical CSV.
|
||||
|
||||
The importer reads the curated columns of an export spreadsheet
|
||||
(`otp-keys-export.xlsx`: Issuer, Account, Secret, Type, Algorithm, Digits,
|
||||
Period) and writes each credential to the applet using the standard YKOATH
|
||||
`PUT` command. It authenticates first if the applet is password-protected, asks
|
||||
before overwriting credentials that already exist, and can optionally profile
|
||||
per-credential on-chip memory consumption via the `javacard-memory` applet.
|
||||
## Pipeline
|
||||
|
||||
1. **QR -> CSV** (`qr_to_sheet.py`): decode QR screenshots and append new
|
||||
credentials to `otp-keys.csv`, deduplicated on the `otpauth://` data.
|
||||
2. **Edit labels (optional)**: adjust the `issuer` / `account` columns to taste.
|
||||
Never edit the `otpauth_uri` column - it is the immutable source of truth.
|
||||
3. **CSV -> applet** (`apex_otp_import.py`): write to the Apex, validating for
|
||||
anything you may have broken (duplicate names, invalid characters, overlength).
|
||||
|
||||
The CSV has four columns: `issuer`, `account` (editable labels), `otpauth_uri`
|
||||
(do not edit), and `source_file`. The secret and other crypto parameters live
|
||||
inside `otpauth_uri` and are always taken from there.
|
||||
|
||||
```
|
||||
# Populate/refresh the CSV from a folder of QR screenshots
|
||||
python qr_to_sheet.py --images /path/to/qr-screenshots --csv otp-keys.csv
|
||||
python qr_to_sheet.py --images ... --csv ... --dry-run # preview, no write
|
||||
```
|
||||
|
||||
Undecodable images (stylized/colored QRs, or text-only screenshots) are listed
|
||||
by filename so you can add them by hand.
|
||||
|
||||
## Importing
|
||||
|
||||
Import TOTP credentials from the CSV (or a legacy `.xlsx`) into the applet.
|
||||
|
||||
The importer reads `otp-keys.csv` (or a legacy `.xlsx`), takes the credential
|
||||
name from the `issuer`/`account` columns and the crypto from `otpauth_uri`, and
|
||||
writes each credential using the standard YKOATH `PUT` command. It authenticates
|
||||
first if the applet is password-protected, asks before overwriting credentials
|
||||
that already exist, and can optionally profile per-credential on-chip memory
|
||||
consumption via the `javacard-memory` applet.
|
||||
|
||||
The protocol layer is verified against the applet sources
|
||||
(`com.vivokey.otp.YkneoOath` / `OathObj`) and `doc/Protocol.txt`. See
|
||||
@@ -31,13 +57,13 @@ personal folder) and point the importer at it with `--input`.
|
||||
|
||||
```
|
||||
# 1. Validate the data and preview the APDUs (no card needed)
|
||||
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx --dry-run
|
||||
python apex_otp_import.py --input /path/to/otp-keys.csv --dry-run
|
||||
|
||||
# 2. Read-only: list what is already on the applet
|
||||
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx --list
|
||||
python apex_otp_import.py --input /path/to/otp-keys.csv --list
|
||||
|
||||
# 3. Import (asks before overwriting existing credentials)
|
||||
python apex_otp_import.py --input /path/to/otp-keys-export.xlsx
|
||||
python apex_otp_import.py --input /path/to/otp-keys.csv
|
||||
|
||||
# Non-interactive conflict handling
|
||||
python apex_otp_import.py --input ... --overwrite-all
|
||||
|
||||
Reference in New Issue
Block a user