Add startup persistence for support sessions
- Added startup.rs module for Windows registry operations - Agent adds itself to HKCU\...\Run on session start - Agent removes itself from startup on session end - Works with user-level registry (no admin required) - Added Win32_System_Registry feature to windows crate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
146
agent/src/startup.rs
Normal file
146
agent/src/startup.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
//! Startup persistence for the agent
|
||||
//!
|
||||
//! Handles adding/removing the agent from Windows startup.
|
||||
|
||||
use anyhow::Result;
|
||||
use tracing::{info, warn, error};
|
||||
|
||||
#[cfg(windows)]
|
||||
use windows::Win32::System::Registry::{
|
||||
RegOpenKeyExW, RegSetValueExW, RegDeleteValueW, RegCloseKey,
|
||||
HKEY_CURRENT_USER, KEY_WRITE, REG_SZ,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use windows::core::PCWSTR;
|
||||
|
||||
const STARTUP_KEY: &str = r"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
const STARTUP_VALUE_NAME: &str = "GuruConnect";
|
||||
|
||||
/// Add the current executable to Windows startup
|
||||
#[cfg(windows)]
|
||||
pub fn add_to_startup() -> Result<()> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
|
||||
// Get the path to the current executable
|
||||
let exe_path = std::env::current_exe()?;
|
||||
let exe_path_str = exe_path.to_string_lossy();
|
||||
|
||||
info!("Adding to startup: {}", exe_path_str);
|
||||
|
||||
// Convert strings to wide strings
|
||||
let key_path: Vec<u16> = OsStr::new(STARTUP_KEY)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
let value_name: Vec<u16> = OsStr::new(STARTUP_VALUE_NAME)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
let value_data: Vec<u16> = OsStr::new(&*exe_path_str)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
|
||||
unsafe {
|
||||
let mut hkey = windows::Win32::Foundation::HANDLE::default();
|
||||
|
||||
// Open the Run key
|
||||
let result = RegOpenKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(key_path.as_ptr()),
|
||||
0,
|
||||
KEY_WRITE,
|
||||
&mut hkey as *mut _ as *mut _,
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
anyhow::bail!("Failed to open registry key: {:?}", result);
|
||||
}
|
||||
|
||||
let hkey_raw = std::mem::transmute::<_, windows::Win32::System::Registry::HKEY>(hkey);
|
||||
|
||||
// Set the value
|
||||
let data_bytes = std::slice::from_raw_parts(
|
||||
value_data.as_ptr() as *const u8,
|
||||
value_data.len() * 2,
|
||||
);
|
||||
|
||||
let set_result = RegSetValueExW(
|
||||
hkey_raw,
|
||||
PCWSTR(value_name.as_ptr()),
|
||||
0,
|
||||
REG_SZ,
|
||||
Some(data_bytes),
|
||||
);
|
||||
|
||||
let _ = RegCloseKey(hkey_raw);
|
||||
|
||||
if set_result.is_err() {
|
||||
anyhow::bail!("Failed to set registry value: {:?}", set_result);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Successfully added to startup");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the agent from Windows startup
|
||||
#[cfg(windows)]
|
||||
pub fn remove_from_startup() -> Result<()> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
|
||||
info!("Removing from startup");
|
||||
|
||||
let key_path: Vec<u16> = OsStr::new(STARTUP_KEY)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
let value_name: Vec<u16> = OsStr::new(STARTUP_VALUE_NAME)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
|
||||
unsafe {
|
||||
let mut hkey = windows::Win32::Foundation::HANDLE::default();
|
||||
|
||||
let result = RegOpenKeyExW(
|
||||
HKEY_CURRENT_USER,
|
||||
PCWSTR(key_path.as_ptr()),
|
||||
0,
|
||||
KEY_WRITE,
|
||||
&mut hkey as *mut _ as *mut _,
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
warn!("Failed to open registry key for removal: {:?}", result);
|
||||
return Ok(()); // Not an error if key doesn't exist
|
||||
}
|
||||
|
||||
let hkey_raw = std::mem::transmute::<_, windows::Win32::System::Registry::HKEY>(hkey);
|
||||
|
||||
let delete_result = RegDeleteValueW(hkey_raw, PCWSTR(value_name.as_ptr()));
|
||||
|
||||
let _ = RegCloseKey(hkey_raw);
|
||||
|
||||
if delete_result.is_err() {
|
||||
warn!("Registry value may not exist: {:?}", delete_result);
|
||||
} else {
|
||||
info!("Successfully removed from startup");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn add_to_startup() -> Result<()> {
|
||||
warn!("Startup persistence not implemented for this platform");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn remove_from_startup() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user