`paste_text`, `paste_text_replacing`, and `copy_to_clipboard` previously
exposed asymmetric trust against the rest of the Tauri command surface:
no `ensure_main_window` guard and no payload-size cap. A compromised
webview could synthesise an arbitrary Ctrl+V into the foreground
application or write multi-megabyte payloads into the system clipboard
without restriction. `paste_text*` is particularly hot because it also
synthesises keystrokes into whatever app currently has focus.
This change:
- adds `ensure_main_window(&window)?` to all three commands. Each now
takes a `tauri::WebviewWindow` parameter that Tauri injects
automatically — frontend invoke call sites are unchanged in their
TypeScript signatures and `npm run check` is green;
- introduces a shared 1 MiB cap (`MAX_CLIPBOARD_BYTES` /
`MAX_PASTE_BYTES`) that both surfaces enforce identically. Drift
between the two caps would let an attacker copy a >1 MiB payload via
one command and paste it via the other; a unit test asserts the
constants stay in lock-step.
Tests added:
- `commands::clipboard::tests` — accepts normal payload, accepts
exactly-at-cap, rejects above-cap.
- `commands::paste::tests_paste_size_cap` — accepts typical dictation
payload, rejects above-cap, asserts paste cap matches clipboard cap.
Note: `copy_to_clipboard` is currently invoked from the preview
(`/preview`) and viewer (`/viewer`) routes (HistoryPage and DictationPage
too, but those run in the main window). After this change the preview
and viewer invocations will surface a "main window only" error at
runtime. `npm run check` cannot catch this — flagged for follow-up; the
fix is to refactor those routes to delegate the copy through the main
window via an event.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>