Skip to content

Print card: a one-page emergency sheet for encrypted text - #55

Merged
seQRets merged 2 commits into
seQRets:mainfrom
deanrie:feat/printable-card
Oct 9, 2026
Merged

seQRets merged 2 commits into
seQRets:mainfrom
deanrie:feat/printable-card

Conversation

@deanrie

@deanrie deanrie commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Stacked on #51 (it extends that PR's print rule). Item 4 from #53; a product call.

What

From the QR of an encrypted text, a third button, Print card, prints one page:

  • the QR at 8 cm (1024 px, scans from paper),
  • the Base64 in full, in a bordered monospace block (typeable if the scan fails),
  • the date, length and format line (IBTZ v1 · AES-256-GCM, PBKDF2 1,000,000),
  • three steps: open ittybitz.app — or the ittybitz-recovery.html kept beside the card, also at the GitHub address — choose Decrypt → Text, scan or type, enter the password (and the key file, named, if one was used),
  • and, in bold, that the password is not on this card.

So the card can sit in a safe, a drawer or with a notary and be lost or copied without harm; without the password it opens nothing. For a safe, a sheet that says how to open it is worth more than a QR alone.

What it refuses

Only encrypted text gets the button. A ciphertext is made to be kept on paper; a decrypted text or a seed phrase never is — #51's print rule keeps hiding those, and the button simply does not exist for them (qrState.kind === 'plain' && mode === 'encrypt').

The card is a print-only <section>, filled when the button is pressed and emptied on afterprint (with a 1.5 s fallback for browsers that never fire it), so the ciphertext does not linger in the document for a later Save Page As. In card mode body > :not(#card) is hidden, so the print is the card and nothing else.

Verified

Driven in Chrome with window.print stubbed and print media emulated: Encrypt → QR → Print card → the page is replaced by the card (screenshot in the PR thread); afterprint → card text empty, canvas 1×1, body class removed. Decrypt a seed fixture → its SeedQR modal has no print button. test:crypto 91/91.

…ng secret prints; reduced motion honoured

- The secret-text field had spellcheck=false but not autocomplete,
  autocapitalize and autocorrect off, which the sister projects set on
  every secret-bearing field: on iOS, predictive text LEARNS what is typed
  into a plain textarea, so a seed phrase entered here could surface as a
  keyboard suggestion later. Both pages' text fields now carry all four.
  The password field moves from autocomplete=off (ignored for password
  inputs by every browser) to new-password, which does suppress autofill.
- The status line is a live region (role=status, aria-live=polite): a
  screen reader now hears 'Weak password', 'Decrypted successfully' and
  'Decryption failed' instead of silence. Same for the recovery hint.
- @media print blanks every field that can hold a secret, the QR and the
  fingerprints: Print and Save as PDF write the screen to a file.
- prefers-reduced-motion: reduce stops the spinner and transitions.

Verified in Chrome with print media emulated: #t, #out, #p hidden,
status visible; attributes present. test:crypto 91/91.
From the QR of an encrypted text, 'Print card' prints one page: the QR
at 8 cm, the Base64 in full, and three steps to decrypt it — open
ittybitz.app or the recovery file kept beside the card, scan or type,
enter the password (and the key file, named, if one was used). The
password is never on it, so the card can sit in a safe or with a
notary and be lost or copied without harm. For a safe, a notary or a
drawer, a sheet that says how to open it is worth more than a QR alone.

Only ENCRYPTED text gets the button: a ciphertext is made to be kept on
paper, a decrypted text or a seed never is, and seQRets#51's print rule keeps
hiding those. The card is a print-only section filled when the button
is pressed and emptied on afterprint (with a fallback timer), so the
ciphertext does not linger in the document for a later Save Page As.

Verified in Chrome with print media emulated: the page is replaced by
the card; after afterprint the card is empty and the body class gone;
the button is absent for a decrypted seed's SeedQR. test:crypto 91/91.
@deanrie

deanrie commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

Also available merged with every other review PR, in dependency order and verified together, as #57 — merge that or the individual PRs, not both.

@seQRets
seQRets merged commit 840f232 into seQRets:main Oct 9, 2026
seQRets pushed a commit that referenced this pull request Oct 9, 2026
…, safer key files

Releases the merged review PRs (#45, #48, #50, #51, #54, #55, #59) so the
download links serve what the site will be running. Without a release, the
footer's "Download app" would keep handing out v3.0.11.

Version bumped in package.json, the app footer (scripts/build/head.html,
rebuilt), the Recovery tool's label (which tracks the app release since
v3.0.10), and the pinned recovery links in both READMEs.

Size claims corrected to 30 KB everywhere: the Recovery tool is 30,141
bytes after #50/#51/#55, while the READMEs said 28 KB and both pages said
27 KB. The edit is length-neutral, so the stated size is the shipped size.

Cryptography untouched: crypto.ts, bip39.ts, crypto-core.js and the fixture
corpus are byte-identical to v3.0.11, and the Recovery tool's decrypt core
still hashes 055983a4. Regression suite 91/91; build reproducible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants