feat(agent): v2 secure-session-core Task 6 - full key fidelity
All checks were successful
All checks were successful
SPEC-002 Phase 1 Task 6, code-reviewed APPROVED (2 rounds), locally verified (cargo fmt + clippy -D warnings exit 0 + cargo test --workspace 70 pass + build). - Viewer WH_KEYBOARD_LL hook diverts system combos (Win/Win+R, Alt+Tab, Alt+Esc, Ctrl+Esc) to the remote as a full KeyEvent (vk + scan + is_extended + modifiers) and suppresses local handling - GATED on the viewer window having focus AND a "send system keys" toggle (default on; Pause/Break host-key), so it never bricks the technician's local keyboard when unfocused. - Agent injection via SendInput KEYEVENTF_SCANCODE + correct KEYEVENTF_EXTENDEDKEY (right Ctrl/Alt, arrows, nav, Win, NumLock, numpad Divide) - layout-independent, extended-key-correct. - Ctrl+Alt+Del completes through the SAS helper (SYSTEM SendSAS); installer sets the SoftwareSASGeneration policy; 3-tier fail-loud (no false success). SAS named pipe DACL tightened from NULL/Everyone to Authenticated Users. - Modifier hygiene: viewer emits key-ups for held Ctrl/Alt/Shift/Win on focus loss / close so modifiers never stick on the remote. - proto: KeyEvent.is_extended = 7 (additive; older agents derive the flag). Closes Win+R / Ctrl+C-V / Ctrl+Alt+Del / arrows-vs-numpad fidelity. Live on-device testing is plan Task 8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -316,11 +316,69 @@ Reference: `specs/native-remote-control/plan.md` Task 5 (Consent primitive); pro
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Native viewer — full key fidelity
|
||||
## Task 6 [IMPLEMENTED 2026-05-30 — self-verified on a local Windows toolchain: `cargo fmt --all` clean, `cargo clippy --workspace --all-targets --all-features -- -D warnings` exit 0, `cargo test --workspace` 69 pass (19 agent + 50 server), `cargo build --workspace` ok; pending Code Review]: Native viewer — full key fidelity
|
||||
|
||||
Files touched: `agent/src/viewer/` (low-level hook + input capture), `agent/src/input/keyboard.rs`
|
||||
(extend — salvaged), `agent/src/input/mod.rs`, `agent/src/bin/sas_service.rs` (wire — salvaged),
|
||||
`proto/guruconnect.proto` (confirm `KeyEvent`/`SpecialKeyEvent` coverage).
|
||||
> [IMPLEMENTED] The four parts:
|
||||
>
|
||||
> 1. VIEWER CAPTURE (`agent/src/viewer/input.rs`): the `WH_KEYBOARD_LL` hook now
|
||||
> DIVERTS system combinations (Windows/Apps keys, Alt+Tab, Alt+Esc, Ctrl+Esc;
|
||||
> Win+R / Win+E compose on the remote because the diverted Win-down is forwarded)
|
||||
> and forwards them as full-fidelity `KeyEvent`s — VK + hardware scan code +
|
||||
> `is_extended` (read from `KBDLLHOOKSTRUCT.flags & LLKHF_EXTENDED`) + modifier
|
||||
> snapshot — returning `LRESULT(1)` to suppress local handling. The combo decision
|
||||
> is a pure `is_system_combo(vk, alt, ctrl)` so it is unit-tested. Ordinary keys are
|
||||
> NOT forwarded by the hook (they take the normal winit path — avoids double inject).
|
||||
> A "send system keys to remote" toggle (`AtomicBool`, default ON) gates the diversion;
|
||||
> when OFF the hook is transparent. Toggle API: `set_/toggle_/send_system_keys_enabled`.
|
||||
> Host key: Pause/Break flips it (handled in `render.rs`, intercepted locally, logged).
|
||||
> 2. AGENT INJECTION (`agent/src/input/keyboard.rs`): rewrote `send_key` to inject via
|
||||
> `SendInput` with `KEYEVENTF_SCANCODE` (layout-independent) and the correct
|
||||
> `KEYEVENTF_EXTENDEDKEY` (set when the viewer flagged extended, the VK is inherently
|
||||
> extended, or the VK→scan map carries the 0xE0 prefix). New `key_event_full(vk, scan,
|
||||
> is_extended, down)` consumes all `KeyEvent` fields (scan 0 ⇒ derive from VK for older
|
||||
> viewers); wired into `session/mod.rs` `KeyEvent` handling. `is_extended_key` delegates
|
||||
> to a platform-independent `vk_is_extended` (unit-tested) that also covers right Ctrl/Alt.
|
||||
> 3. CTRL+ALT+DEL: the existing `SpecialKey::CtrlAltDel` → `send_ctrl_alt_del` →
|
||||
> `send_sas` path is confirmed and hardened. `send_sas` now: Tier 1 SAS helper service
|
||||
> (SYSTEM, named pipe) → Tier 2 direct `sas.dll!SendSAS` → Tier 3 **fails with a clear,
|
||||
> actionable error** (no false success; plain SendInput can't reach the secure desktop).
|
||||
> The SAS installer (`bin/sas_service.rs install`) now sets the `SoftwareSASGeneration`
|
||||
> Winlogon policy (HKLM\...\Policies\System, DWORD 1 = services) via `set_software_sas_policy`,
|
||||
> with a `// TODO(installer)` noting the top-level managed installer should also ensure it.
|
||||
> 4. MODIFIER HYGIENE: viewer tracks held Ctrl/Alt/Shift/Win (`ViewerModifierState` in
|
||||
> `render.rs`) and emits explicit key-ups on FOCUS LOSS (`WindowEvent::Focused(false)`)
|
||||
> and on window close, so a modifier pressed-but-not-released across a blur doesn't stay
|
||||
> latched on the remote. Agent-side `KeyboardController` also tracks injected modifiers and
|
||||
> exposes `release_all_modifiers` (defensive complement; wired via `ModifierState`, the
|
||||
> scaffolding the cleanup kept). Both trackers unit-tested.
|
||||
>
|
||||
> PROTO: `KeyEvent` gained `bool is_extended = 7` (new field number, nothing renumbered)
|
||||
> — carries the viewer's `LLKHF_EXTENDED` capture so injection picks the right extended
|
||||
> flag; older agents that ignore it fall back to deriving from vk/scan. `SpecialKeyEvent`
|
||||
> already carried `CTRL_ALT_DEL`; unchanged.
|
||||
>
|
||||
> dead_code wired/removed: `InputEvent::SpecialKey` (now emitted/consumable),
|
||||
> `ModifierState` (agent keyboard — now tracks + drains held modifiers),
|
||||
> `type_char`/`type_string` kept with their allows (separate unicode-typing feature, not in
|
||||
> Task 6 scope). `sas_client::is_service_available`/`get_service_status` kept narrowly allowed
|
||||
> (status API not yet wired into a runtime path). `InputController::key_event` (vk-only) and
|
||||
> `release_all_modifiers` kept allowed as API surface (the relayed path uses `key_event_full`,
|
||||
> focus-loss re-sync is viewer-driven). New toggle accessors `set_/send_system_keys_enabled`
|
||||
> narrowly allowed (host-key uses `toggle_`; future viewer menu).
|
||||
>
|
||||
> TESTS ADDED (13): extended-key flag determination (extended + non-extended sets),
|
||||
> modifier-state transitions (record/down-up/ignore-non-modifier/drain-and-clear), the
|
||||
> system-combo classifier (Win/Alt+Tab/Alt+Esc/Ctrl+Esc divert; ordinary keys don't), and
|
||||
> the toggle state machine (default ON, flip, explicit set). Live hook/SendInput/SendSAS
|
||||
> behavior is plan Task 8 (needs a real desktop).
|
||||
|
||||
Files touched: `proto/guruconnect.proto` (KeyEvent `is_extended = 7`), `agent/src/viewer/input.rs`
|
||||
(rewritten hook + toggle), `agent/src/viewer/render.rs` (focus-loss modifier release, host-key
|
||||
toggle, is_extended on winit path), `agent/src/viewer/mod.rs` (unchanged SpecialKey forwarding),
|
||||
`agent/src/input/keyboard.rs` (scan-code injection + ModifierState + vk_is_extended + tests),
|
||||
`agent/src/input/mod.rs` (key_event_full / release_all_modifiers / vk_is_extended re-export),
|
||||
`agent/src/session/mod.rs` (KeyEvent → key_event_full), `agent/src/bin/sas_service.rs`
|
||||
(set_software_sas_policy + install wiring), `agent/src/input/keyboard.rs` (send_sas hardening).
|
||||
|
||||
- **Viewer capture:** install `WH_KEYBOARD_LL` while the viewer is in focused control; divert system
|
||||
combos (Win key, Win+R, Alt+Tab, Ctrl+Esc) and forward as `KeyEvent` (VK + scan code + extended flag)
|
||||
|
||||
Reference in New Issue
Block a user