Clipboard: clear when you come back to TouchPass #20

Merged
claude-bot merged 5 commits from clipboard-clear into main 2026-10-13 21:12:42 +00:00
Collaborator

Closes #8.

What

Lomiri suspends TouchPass as soon as you switch away to paste, so the 45 s timer never fired. The phone's Qt platform plugin also drops every clipboard write from a window without focus, including Clipboard.clear(), which it never forwards at all. The flow is copy, paste elsewhere, come back, so:

  • The clipboard is wiped 300 ms after the TouchPass window gets focus back. The wipe overwrites the clipboard with nothing; clear() is never forwarded.
  • No wipe is attempted without focus. A dropped write is detected by reading the clipboard back, and the wipe stays pending.
  • Only our own text is wiped (matched by MD5). Text, links or images copied since are left alone.
  • The 45 s timer stays for copy-and-stay-in-TouchPass. The toast now says "clears when you're back".

Blast radius

Tier: leaf
Trunk paths touched: none. qml/Main.qml is unchanged.
Gate / rollback: revert the merge, or reinstall the previous .click.

Proof

  • On the phone: the log shows the wipe running with focus. The empty write left 0 chars, and content-hub logged a CreatePaste (23:03:42). The user checked that build (8596448e): the password no longer pastes after coming back.
    • The earlier failure, from the journal, for the record: wiping, window active: false app state: 0. Both the empty write and the space write were dropped, and no CreatePaste was logged.
    • Not re-checked by hand: the final build with the review fixes (76156a4d, installed on the phone, hash checked).
  • QML suite: cargo make qml-test gives Totals: 96 passed, 0 failed. tst_ClipboardGuard.qml fakes window focus. Covered:
    • clears on time while in front
    • clears at once on return
    • doesn't clear while away (the timer fires without focus)
    • newer text left alone
    • newer link (non-text) left alone
    • nothing copied means nothing cleared
    • clears only once
  • Not run: the Rust CI (cargo make), since no Rust changed.
  • No screenshot: the only visible change is the toast wording.

Review

Reviewer: fresh-context Sonnet review at medium, then a code-review pass. Results:

  • Fixed:
    • Non-text copied since (e.g. an image) read as empty text and was wiped as ours.
    • A dropped write still reported "Clipboard cleared"; now it stays pending.
    • Names of local variables.
  • Accepted:
    • Any focus flicker (e.g. pulling the notification shade) after a copy counts as coming back and wipes. Copying again is cheap.
    • active binds to Window.active, so the guard has to sit in a window. It does, in Main.qml.
    • The tests drive active directly. The real transition is covered by the device check above.
  • Not a regression, left for later: no wipe on Lock or exit, because a write without focus is dropped anyway.

Review-Confidence: not audited (leaf)

Confidence by part

  • ClipboardGuard.qml logic: high (unit tests, device check).
  • The focus-flicker trade-off: a deliberate choice; easy to change if it annoys in use.

🤖 Generated with Claude Code

Closes #8. ## What Lomiri suspends TouchPass as soon as you switch away to paste, so the 45 s timer never fired. The phone's Qt platform plugin also drops every clipboard write from a window without focus, including `Clipboard.clear()`, which it never forwards at all. The flow is copy, paste elsewhere, come back, so: - The clipboard is wiped 300 ms after the TouchPass window gets focus back. The wipe overwrites the clipboard with nothing; `clear()` is never forwarded. - No wipe is attempted without focus. A dropped write is detected by reading the clipboard back, and the wipe stays pending. - Only our own text is wiped (matched by MD5). Text, links or images copied since are left alone. - The 45 s timer stays for copy-and-stay-in-TouchPass. The toast now says "clears when you're back". ## Blast radius **Tier:** leaf **Trunk paths touched:** none. `qml/Main.qml` is unchanged. **Gate / rollback:** revert the merge, or reinstall the previous `.click`. ## Proof - **On the phone:** the log shows the wipe running with focus. The empty write left 0 chars, and content-hub logged a `CreatePaste` (23:03:42). The user checked that build (8596448e): the password no longer pastes after coming back. - The earlier failure, from the journal, for the record: `wiping, window active: false app state: 0`. Both the empty write and the space write were dropped, and no `CreatePaste` was logged. - Not re-checked by hand: the final build with the review fixes (76156a4d, installed on the phone, hash checked). - **QML suite:** `cargo make qml-test` gives `Totals: 96 passed, 0 failed`. `tst_ClipboardGuard.qml` fakes window focus. Covered: - clears on time while in front - clears at once on return - doesn't clear while away (the timer fires without focus) - newer text left alone - newer link (non-text) left alone - nothing copied means nothing cleared - clears only once - **Not run:** the Rust CI (`cargo make`), since no Rust changed. - **No screenshot:** the only visible change is the toast wording. ## Review **Reviewer:** fresh-context Sonnet review at medium, then a code-review pass. Results: - **Fixed:** - Non-text copied since (e.g. an image) read as empty text and was wiped as ours. - A dropped write still reported "Clipboard cleared"; now it stays pending. - Names of local variables. - **Accepted:** - Any focus flicker (e.g. pulling the notification shade) after a copy counts as coming back and wipes. Copying again is cheap. - `active` binds to `Window.active`, so the guard has to sit in a window. It does, in `Main.qml`. - The tests drive `active` directly. The real transition is covered by the device check above. - **Not a regression, left for later:** no wipe on Lock or exit, because a write without focus is dropped anyway. **Review-Confidence:** not audited (leaf) ## Confidence by part - `ClipboardGuard.qml` logic: high (unit tests, device check). - The focus-flicker trade-off: a deliberate choice; easy to change if it annoys in use. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Lomiri suspends TouchPass as soon as you switch away to paste, so the
45 s timer never fired while you were gone and the password stayed
pasteable for as long as you stayed away. ClipboardGuard now keeps a
wall-clock deadline and clears at once when TouchPass is active again
past it; the timer still clears on time while TouchPass stays in front.

Nothing can run while TouchPass is suspended, so the README and the
"Copied" toast now say it clears once you are back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clipboard: leave alone what was copied since; shorter toast
All checks were successful
CI / ci (pull_request) Successful in 5m45s
CI / audit (pull_request) Successful in 16s
CI / qml (pull_request) Successful in 41s
1fabef1d24
A wipe on return is likelier than the old timer to find something you
copied in the other app meanwhile, so the guard only clears the clipboard
while it still holds our text (recognised by its MD5, so the password
isn't kept). The toast is shown for 3 s, so its text is shorter. The
README's device check stays open until it is done on the phone.

Review-Tier: leaf
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clipboard: overwrite with nothing, since clear() is dropped on the phone
All checks were successful
CI / ci (pull_request) Successful in 5m29s
CI / audit (pull_request) Successful in 16s
CI / qml (pull_request) Successful in 36s
b6d5ff20a2
On the device the "Clipboard cleared" toast came up but the password
still pasted. The Mir platform's setMimeData() skips a null paste, which
is what QClipboard::clear() sends, so it never reached content-hub.
Pushing an empty text does.

Review-Tier: leaf
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clipboard: wipe as soon as TouchPass has focus again
Some checks failed
CI / qml (pull_request) Has been cancelled
CI / audit (pull_request) Has been cancelled
CI / ci (pull_request) Has been cancelled
2671dee22d
The phone's platform drops every clipboard write from a window without
focus, so the wipe ran in the background (a suspended TouchPass woken for
a sync) and was lost. It now waits for focus, and does it on return
rather than after a deadline: the flow is copy, paste elsewhere, come
back, so return is the first moment a wipe can happen. The 45 s timer
stays for copying and staying in TouchPass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Tier: leaf
Clipboard: leave non-text alone; retry a wipe the phone dropped
All checks were successful
CI / ci (pull_request) Successful in 5m21s
CI / audit (pull_request) Successful in 16s
CI / qml (pull_request) Successful in 48s
357efe48fe
From review: an image copied since read as empty text and was wiped as
ours, and a dropped write still reported "Clipboard cleared". Now only
our own text is wiped, and a wipe that didn't take stays pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Tier: leaf
claude-bot changed title from WIP: Clipboard: clear on return once the 45 s are up to Clipboard: clear when you come back to TouchPass 2026-10-13 21:07:33 +00:00
schaefera approved these changes 2026-10-13 21:09:49 +00:00
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-10-13 21:10:47 +00:00
schaefera deleted branch clipboard-clear 2026-10-13 21:21:39 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
schaefera/TouchPass!20
No description provided.