feat(agent): v2 secure-session-core Task 6 - full key fidelity
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 7m1s
Build and Test / Build Server (Linux) (push) Successful in 11m32s
Build and Test / Security Audit (push) Successful in 4m31s
Build and Test / Build Summary (push) Successful in 11s

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:
2026-05-30 09:16:26 -07:00
parent d0de888dd1
commit bb73ba667f
8 changed files with 848 additions and 133 deletions

View File

@@ -5,6 +5,7 @@
mod keyboard;
mod mouse;
pub use keyboard::vk_is_extended;
pub use keyboard::KeyboardController;
pub use mouse::MouseController;
@@ -56,7 +57,8 @@ impl InputController {
self.mouse.scroll(delta_x, delta_y)
}
/// Press or release a key
/// Press or release a key by virtual-key code only (scan code derived from the VK).
#[allow(dead_code)]
pub fn key_event(&mut self, vk_code: u16, down: bool) -> Result<()> {
if down {
self.keyboard.key_down(vk_code)
@@ -65,6 +67,30 @@ impl InputController {
}
}
/// Inject a full-fidelity key event (VK + hardware scan code + extended-key flag).
///
/// This is the path used for relayed viewer keystrokes so that scan-code injection
/// (layout-independent) and the correct `KEYEVENTF_EXTENDEDKEY` flag are applied.
pub fn key_event_full(
&mut self,
vk_code: u16,
scan_code: u16,
is_extended: bool,
down: bool,
) -> Result<()> {
self.keyboard
.key_event_full(vk_code, scan_code, is_extended, down)
}
/// Release any modifier keys currently held down on the remote.
///
/// Invoked when the viewer loses focus or the session ends so a Ctrl/Alt/Shift/Win
/// whose key-up never arrived does not stay latched on the remote desktop.
#[allow(dead_code)]
pub fn release_all_modifiers(&mut self) -> Result<()> {
self.keyboard.release_all_modifiers()
}
/// Type a unicode character
#[allow(dead_code)]
pub fn type_unicode(&mut self, ch: char) -> Result<()> {