Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1fd3065
import: lock the Molto2 import behavior with golden tests (re #170)
framefilter Oct 10, 2026
45395fd
import: carry HOTP, any TOTP period and SHA-512 in a wide entry model…
framefilter Oct 10, 2026
66cb36f
import: classify dropped files and read every authenticator export th…
framefilter Oct 10, 2026
545bedc
import: bound the wide readers and harden file reading after review (…
framefilter Oct 10, 2026
153ad8d
import: read the counter only for HOTP entries in the wide readers (r…
framefilter Oct 10, 2026
2f0bdeb
import: plan an import per key — what fits, what's already there, wha…
framefilter Oct 10, 2026
d58a658
import: write planned codes one at a time and stop with a report on t…
framefilter Oct 10, 2026
4af8f2a
import: one Molto2 title rule, safer OATH names and clearer replace r…
framefilter Oct 10, 2026
e44def1
transport: OATH import adapter — exists, full and re-validation read …
framefilter Oct 10, 2026
63c7ae8
transport: Token2 OTP and Molto2 import adapters; 6983 stays "PIN blo…
framefilter Oct 10, 2026
be03310
OATH: codes use the name's period prefix; Solo 2 names capped at 127 …
framefilter Oct 10, 2026
e61e775
import adapters: fresh Molto2 clock per slot, no extra PIN attempts, …
framefilter Oct 10, 2026
02fdd47
CLI: oath import and otp import — preview, skip same-name codes, --re…
framefilter Oct 10, 2026
3056883
CLI: molto import --file-password (one name for an export's password)…
framefilter Oct 10, 2026
1f7a467
CLI imports: test the stdin line order on the readers the handlers us…
framefilter Oct 10, 2026
7eae416
gui: every dropped or picked file is read in turn and identified befo…
framefilter Oct 10, 2026
c7dfa6d
gui: one "Import authenticator codes" dialog for every key that store…
framefilter Oct 10, 2026
a70b196
gui: a dialog closed while its file password is checked stays closed
framefilter Oct 10, 2026
d77d529
import: unlock a password-protected Solo 2 again when it answers 6985…
framefilter Oct 10, 2026
7afcb63
gui: a Molto2 slot with a seed but no title counts as in use
framefilter Oct 10, 2026
ac18a7d
oath: refuse a name that starts another on YubiKey 4 firmware 4.0-4.3.4
framefilter Oct 10, 2026
1ef6ddf
import: one set of words for the CLI and the GUI; Molto2 dialog works…
framefilter Oct 10, 2026
a47b26a
import: read an export without leaving unwiped copies behind
framefilter Oct 10, 2026
c5ca644
transport: OATH import refuses a Solo 2 name past 127 bytes itself
framefilter Oct 10, 2026
b4bb3b9
import: mark the new enums that will grow as non-exhaustive
framefilter Oct 10, 2026
e8724fd
import: cite the research sources in plain text in a doc comment
framefilter Oct 10, 2026
2c0cbdd
import: fingerprint unlock proves no PIN; exists before the prefix rule
framefilter Oct 10, 2026
69c7ebc
resolve: select a Molto2 by the serials keyroost shows for it
framefilter Oct 10, 2026
f01b83c
molto import: plan, preview and write an export like the other imports
framefilter Oct 10, 2026
44852ab
molto import: one shared Molto2 plan, and a dry run that survives a s…
framefilter Oct 10, 2026
37a3315
docs: explain importing authenticator codes into every key (re #170)
framefilter Oct 10, 2026
87922bb
gui: a Molto2 import skips entries past #99 instead of blocking Add (…
framefilter Oct 10, 2026
5c27de9
docs: list only fixes to released behavior in the changelog (re #170)
framefilter Oct 10, 2026
59c92a0
molto import: a dry run no longer prints the token's serial and clock…
framefilter Oct 10, 2026
f944335
gui: say "connect a key" once in the import dialog (re #170)
framefilter Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tool. Workspace contains:
| Crate | Purpose | External deps |
|---|---|---|
| `keyroost-proto` | Pure-Rust protocol layer (SM4, SHA-1, APDU builders, MAC) | none |
| `keyroost-transport` | PC/SC reader discovery, Molto2 session, YubiKey CCID serial, OATH + OpenPGP applets | `pcsc`; `aes`/`des`/`cipher`/`getrandom`/`zeroize` (PIV mgmt-key auth); `hidapi` (non-Linux HID) |
| `keyroost-transport` | PC/SC reader discovery, Molto2 session, YubiKey CCID serial, OATH + OpenPGP applets, import writers for OATH / Token2 OTP / Molto2 (in-tree `keyroost-import`) | `pcsc`; `aes`/`des`/`cipher`/`getrandom`/`zeroize` (PIV mgmt-key auth); `hidapi` (non-Linux HID) |
| `keyroost-hid` | USB HID enumeration of FIDO devices via sysfs | `hidapi` (non-Linux only; Linux uses sysfs) |
| `keyroost-ctap` | FIDO2/CTAP-HID transport, CBOR, PIN protocols, credential mgmt, largeBlob (incl. the on-key name entry, `docs/PROTOCOL-device-label.md`) | RustCrypto (`sha2`/`hmac`/`aes`/`cbc`/`p256`/`aes-gcm`), `rand_core`, `zeroize`, `miniz_oxide` (largeBlob DEFLATE); `hidapi` (non-Linux HID) |
| `keyroost-oath` | Pure-Rust Yubico/Trussed OATH (TOTP/HOTP) byte layer (APDU + TLV) | `zeroize` |
Expand All @@ -41,7 +41,7 @@ tool. Workspace contains:
| `keyroost-resolve` | Shared key-identity resolution (USB + CCID serials, topology match) and naming (on-key names, first-seen records) | in-tree only (incl. `keyroost-ctap`) |
| `keyroost-rsakey` | Host-side RSA-2048 keygen + PKCS#1/PKCS#8 (PEM/DER) loading for OpenPGP import | `rsa`, `rand`, `zeroize` (scoped exception) |
| `keyroost-pivtest` | Host-side verification for the PIV slot self-test (`piv test`): fixed challenges checked against the slot certificate's public key | `rsa`, `p256`/`p384`/`p521` (ECDH), `ed25519-dalek`, `x25519-dalek`, `zeroize` (scoped exception) |
| `keyroost-import` | otpauth:// + Aegis / 2FAS / otpauth-list parsers | `zeroize`; `serde`/`serde_json` (behind `bulk`); `scrypt`/`aes-gcm`/`base64` (behind `encrypted`, for Aegis vaults) |
| `keyroost-import` | otpauth:// + Aegis / 2FAS / otpauth-list parsers, file classification, per-key import plan and write loop | `zeroize`; `serde`/`serde_json` (behind `bulk`); `scrypt`/`aes-gcm`/`base64` (behind `encrypted`, for Aegis vaults) |
| `keyroost-qr` | QR 2FA import from PNG/JPEG screenshots + Google Authenticator migration batches (always built; the GUI's separate `qr` feature gates *screen capture*, not this) | `rqrr`, `png`, `jpeg-decoder`, `zeroize` |
| `keyroost-screengrab` | Windows-only GDI screen capture for QR-from-screen; the sole `unsafe` FFI crate; inert on non-Windows | `windows-sys` (Windows only) |
| `keyroost-winwebauthn` | Windows-only non-admin FIDO2 helper: detect a FIDO key, open Windows' security-key settings, relaunch elevated; inert on non-Windows | `windows-sys` (Windows only) |
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

122 changes: 108 additions & 14 deletions README.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions changelog.d/added-170-import-codes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- **Import authenticator codes into any key that stores them.** `oath
import` adds every code in an Aegis (plain or encrypted), 2FAS,
`otpauth://` list or QR export to a YubiKey, Solo 2 or Nitrokey 3, and
`otp import` to a Token2 key's OTP storage. In the GUI, drop the file on
the window or click "Import file…" in the Authenticator, On-device OTP or
Molto2 view; the "Import authenticator codes" dialog works for every key
that stores codes. keyroost reads the key first and previews each entry:
a code whose name is already on the key is skipped (`--replace`
replaces it), and one the key can't store is listed with the reason.
`--dry-run` writes nothing. It asks once, writes one code at a time, and
stops at the first error with a report of what was added. ([#170])
7 changes: 7 additions & 0 deletions changelog.d/added-170-solo2-name-limit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- **Solo 2 names are capped at 127 bytes.** `oath add`, `oath import` and
the GUI refuse a longer Solo 2 name before sending it: a 128-byte name
made the key stop responding until it was unplugged. ([#170])
- **YubiKey 4 prefix names.** On YubiKey 4 firmware 4.0 to 4.3.4, `oath
add`, `oath import` and the GUI refuse a name that is the start of
another name already on the key, following the same rule as Yubico's
`ykman`. ([#170])
10 changes: 6 additions & 4 deletions changelog.d/changed-165-key-selection.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from (now on every platform); a script gets a refusal that lists the
`--device` value for each key. No command takes "the first key found"
any more. `--device` takes a name, a serial or a `list` number
(`name:`, `serial:` or `list:` forces which). `--device` with `--reader`
or `--path` is refused, and so is `--device` on commands that touch no
key. `--reader` and `--path` skip the capability check, and a value that
matches no detected key is used as typed. ([#165])
(`name:`, `serial:` or `list:` forces which); a Molto2 answers to either
serial keyroost shows for it, the one in `list` or the one `molto info`
prints. `--device` with `--reader` or `--path` is refused, and so is
`--device` on commands that touch no key. `--reader` and `--path` skip
the capability check, and a value that matches no detected key is used
as typed. ([#165])
5 changes: 5 additions & 0 deletions changelog.d/changed-170-file-password.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- **`molto import --file-password`.** An encrypted Aegis export's password
now comes from `--file-password env:NAME` or `--file-password stdin`, the
same flag `oath import` and `otp import` use (v0.12's `import-file
--password-env` / `--password-stdin` are refused with an error naming
it). ([#170])
5 changes: 5 additions & 0 deletions changelog.d/changed-170-import-dialog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- **The Molto2 "Bulk import" dialog is replaced.** "Import file…" in the
Molto2 view, or a file dropped on the window, opens the shared "Import
authenticator codes" dialog. Every dropped file is identified first: a
certificate or key file gets a note saying where to import it, and any
other file gets "keyroost can't import this file". ([#170])
8 changes: 8 additions & 0 deletions changelog.d/changed-170-molto-import-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- **`molto import --in` follows the shared import rules.** An entry the
Molto2 can't store (for example a SHA-512 code or a 45-second period) is
skipped with the reason instead of refusing the whole file, and entries
past slot #99 are skipped. An entry with no issuer or account no longer
takes a slot. The preview, the one question before writing (`--yes` in
a script), the report and `--json` are the same as `oath import`.
`--dry-run` shows which slots are in use when a Molto2 is connected
(`--device` picks which one). ([#170])
19 changes: 9 additions & 10 deletions changelog.d/fixed-170-bulk-import-dialog.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
- **The Molto2 bulk import dialog closes and says why "Program all" is
gray.** Close in the bulk import dialog, and Cancel in the "Import to
slot" dialog, did nothing; both now close the dialog, and closing
either dialog by any route wipes the typed vault password or pasted URI
and drops the parsed entries (which carry seeds).
When "Program all" can't run, one line under the buttons now says why:
the file is still loading, no Molto2 is selected, the Molto2 isn't
unlocked yet (with an Authenticate button right there, and a failed
attempt is reported in that line too), or the entries
don't all fit before slot #99 (with how many do). ([#170])
- **The Molto2 import dialog closes and says why adding is gray.** Close
in the import dialog, and Cancel in the "Import to slot" dialog, did
nothing; both now close the dialog, and closing either dialog by any
route wipes the typed file password or pasted URI and drops the parsed
entries (which carry seeds).
When adding can't start, one line under the buttons now says why: the
file is still loading, or the Molto2 isn't open or unlocked yet (with
an Authenticate button right there, and a failed attempt is reported in
that line too). ([#170])
4 changes: 4 additions & 0 deletions changelog.d/fixed-170-oath-period-codes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- **Codes for OATH entries named `60/…` use their period.** `oath code`
(without `--period`) and the GUI computed them at 30 seconds, so they
were wrong. `--period` now defaults to the name's `period/` prefix, and
the GUI shows the period next to the code. ([#170])
2 changes: 2 additions & 0 deletions changelog.d/fixed-170-oath-period-zero.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- **`oath code --period 0` is a usage error.** It crashed; it is now
refused with exit 2. ([#170])
Loading
Loading