pub const TEAMVIEWER_PATHS: &[&str] = &[
r"SOFTWARE\TeamViewer",
r"SYSTEM\CurrentControlSet\Services\TeamViewer",
r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TeamViewer",
];
pub const ANYDESK_PATHS: &[&str] = &[
r"SOFTWARE\Clients\Media\AnyDesk",
r"SYSTEM\CurrentControlSet\Services\AnyDesk",
r"SOFTWARE\Classes\.anydesk\shell\open\command",
r"SOFTWARE\Classes\AnyDesk\shell\open\command",
r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\AnyDesk",
r"DRIVERS\DriverDatabase\DeviceIds\USBPRINT\AnyDesk",
r"DRIVERS\DriverDatabase\DeviceIds\WSDPRINT\AnyDesk",
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\AnyDesk Printer",
];
pub const SPLASHTOP_PATHS: &[&str] = &[
r"SOFTWARE\WOW6432Node\Splashtop Inc.",
r"SYSTEM\CurrentControlSet\Services\SplashtopRemoteService",
r"SYSTEM\CurrentControlSet\Control\SafeBoot\Network\SplashtopRemoteService",
r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Splashtop Software Updater",
r"SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels\Splashtop-Splashtop Streamer-Remote Session/Operational",
r"SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels\Splashtop-Splashtop Streamer-Status/Operational",
r"Software\Splashtop Inc.",
];
pub const ATERA_PATHS: &[&str] = &[
r"SOFTWARE\ATERA Networks\AlphaAgent",
r"SOFTWARE\ATERA Networks",
r"SYSTEM\CurrentControlSet\Services\AteraAgent",
r"SYSTEM\ControlSet\Services\EventLog\Application\AlphaAgent",
r"SYSTEM\ControlSet\Services\EventLog\Application\AteraAgent",
r"SOFTWARE\Microsoft\Tracing\AteraAgent_RASAPI32",
r"SOFTWARE\Microsoft\Tracing\AteraAgent_RASMANCS",
];
pub const GOTOASSIST_PATHS: &[&str] = &[
r"SOFTWARE\GoTo Resolve Unattended",
r"SOFTWARE\Citrix\GoToMyPc",
r"WOW6432Node\Citrix\GoToMyPc",
];
pub const ACTION1_PATHS: &[&str] = &[
r"System\CurrentControlSet\Services\A1Agent",
r"SOFTWARE\WOW6432Node\Action1",
r"SOFTWARE\WOW6432Node\Microsoft\Windows\Windows Error Reporting\LocalDumps\action1_agent.exe",
];
pub const MANAGEENGINE_PATHS: &[&str] =
&[r"SOFTWARE\ManageEngine", r"SOFTWARE\AdventNet\ManageEngine"];
pub fn all_lolrmm_paths() -> impl Iterator<Item = &'static str> {
TEAMVIEWER_PATHS
.iter()
.chain(ANYDESK_PATHS.iter())
.chain(SPLASHTOP_PATHS.iter())
.chain(ATERA_PATHS.iter())
.chain(GOTOASSIST_PATHS.iter())
.chain(ACTION1_PATHS.iter())
.chain(MANAGEENGINE_PATHS.iter())
.copied()
}
pub fn is_remote_access_tool_path(path: &str) -> bool {
let lower = path.to_ascii_lowercase();
all_lolrmm_paths().any(|entry| lower.contains(&entry.to_ascii_lowercase()))
}
pub fn identify_remote_access_tool(path: &str) -> Option<&'static str> {
let lower = path.to_ascii_lowercase();
let matches = |entries: &[&str]| {
entries
.iter()
.any(|e| lower.contains(&e.to_ascii_lowercase()))
};
if matches(TEAMVIEWER_PATHS) {
Some("TeamViewer")
} else if matches(ANYDESK_PATHS) {
Some("AnyDesk")
} else if matches(SPLASHTOP_PATHS) {
Some("Splashtop")
} else if matches(ATERA_PATHS) {
Some("Atera")
} else if matches(GOTOASSIST_PATHS) {
Some("GoToAssist")
} else if matches(ACTION1_PATHS) {
Some("Action1")
} else if matches(MANAGEENGINE_PATHS) {
Some("ManageEngine")
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn teamviewer_paths_contains_hklm_key() {
assert!(TEAMVIEWER_PATHS.contains(&r"SOFTWARE\TeamViewer"));
}
#[test]
fn anydesk_paths_contains_service_key() {
assert!(ANYDESK_PATHS.contains(&r"SYSTEM\CurrentControlSet\Services\AnyDesk"));
}
#[test]
fn all_lolrmm_paths_not_empty() {
assert!(
all_lolrmm_paths().next().is_some(),
"all_lolrmm_paths() must yield at least one entry"
);
}
#[test]
fn all_lolrmm_paths_covers_all_tools() {
let all: Vec<_> = all_lolrmm_paths().collect();
for path in [
TEAMVIEWER_PATHS[0],
ANYDESK_PATHS[0],
SPLASHTOP_PATHS[0],
ATERA_PATHS[0],
GOTOASSIST_PATHS[0],
ACTION1_PATHS[0],
MANAGEENGINE_PATHS[0],
] {
assert!(
all.contains(&path),
"Missing path in all_lolrmm_paths: {path}"
);
}
}
#[test]
fn is_remote_access_tool_path_teamviewer_matches() {
assert!(
is_remote_access_tool_path(r"SOFTWARE\TeamViewer\ConnectionHistory"),
"TeamViewer path must match"
);
}
#[test]
fn is_remote_access_tool_path_case_insensitive() {
assert!(
is_remote_access_tool_path(r"software\teamviewer"),
"Match must be case-insensitive"
);
}
#[test]
fn is_remote_access_tool_path_unrelated_returns_false() {
assert!(
!is_remote_access_tool_path(r"SOFTWARE\Microsoft\Office"),
"Unrelated path must not match"
);
}
#[test]
fn identify_remote_access_tool_teamviewer() {
assert_eq!(
identify_remote_access_tool(r"SOFTWARE\TeamViewer\ConnectionHistory"),
Some("TeamViewer"),
"Should identify TeamViewer"
);
}
#[test]
fn identify_remote_access_tool_anydesk() {
assert_eq!(
identify_remote_access_tool(r"SYSTEM\CurrentControlSet\Services\AnyDesk"),
Some("AnyDesk"),
"Should identify AnyDesk"
);
}
#[test]
fn identify_remote_access_tool_unknown_returns_none() {
assert_eq!(
identify_remote_access_tool(r"SOFTWARE\Microsoft\Windows"),
None,
"Unknown path should return None"
);
}
}