CH-J Toolsmanagementul serverului peste SSH
Meniu
Sursă publicată

CH-J Tools

Navighează directoarele și fișierele pentru o anumită versiune a aplicației.

Descarcă sursa ZIP
CH-J / Server Manager 872 fișiere
core-20261030T220507Z-61e4558d889f Adăugat: · Construit:
platform.rs Adăugat: Data neînregistrată 5,9 KB · 108 linii
Cod Descarcă fișierul
1//! Remote OS detection from system facts (port of `sessions/platformDetect.js`):
2//! `uname -s` for POSIX, otherwise an encoded PowerShell probe; never prompts or host names.
4use crate::core::error::CoreResult;
5use crate::core::ssh::session::{SessionManager, SessionRecord};
6use crate::core::ssh::windows_exec::{encoded_command, parse_windows_output};
7use once_cell::sync::Lazy;
8use regex::Regex;
9use serde_json::{json, Value};
10use std::sync::Arc;
11use std::time::Duration;
13static POSIX_KERNELS: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(Linux|Darwin|FreeBSD|OpenBSD|NetBSD|DragonFly|SunOS|AIX)\b").unwrap());
15pub const WINDOWS_PROBE: &str = r#"$ProgressPreference='SilentlyContinue'
16try {
17 # Registry first: standard accounts on an SSH network logon are usually denied WMI/CIM access.
18 $nt = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue
19 $shell = (Get-ItemProperty 'HKLM:\SOFTWARE\OpenSSH' -ErrorAction SilentlyContinue).DefaultShell
20 $caption = [string]$nt.ProductName; $build = [string]$nt.CurrentBuildNumber
21 if ($caption -match '^Windows 10' -and [int]("0$build") -ge 22000) { $caption = $caption -replace '^Windows 10', 'Windows 11' }
22 $type = [string](Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\ProductOptions' -ErrorAction SilentlyContinue).ProductType
23 $productType = @{ 'WinNT' = 1; 'LanmanNT' = 2; 'ServerNT' = 3 }[$type]
24 $version = [Environment]::OSVersion.Version.ToString()
25 try { $os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop; $caption = $os.Caption; $version = $os.Version; $productType = [int]$os.ProductType } catch {}
26 $value = [ordered]@{ caption = $caption; version = $version; build = $build; productType = $productType
27 installationType = [string]$nt.InstallationType; defaultShell = [string]$shell; psVersion = $PSVersionTable.PSVersion.ToString()
28 is64BitProcess = [Environment]::Is64BitProcess; languageMode = [string]$ExecutionContext.SessionState.LanguageMode
29 localAccounts = [bool](Get-Command Get-LocalUser -ErrorAction SilentlyContinue); pwsh = [string](Get-Command pwsh.exe -ErrorAction SilentlyContinue).Source }
30 [Console]::Out.WriteLine('CHJ_RESULT:' + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(($value | ConvertTo-Json -Compress))))
31} catch { [Console]::Out.WriteLine('CHJ_ERR:PLATFORM_PROBE_FAILED:' + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($_.Exception.Message))) }"#;
33pub fn shell_name(default_shell: &str) -> String {
34 let value = default_shell.to_lowercase();
35 if value.is_empty() {
36 return "cmd.exe".into();
37 }
38 for (pattern, name) in [(r"pwsh(\.exe)?$", "pwsh"), (r"powershell(\.exe)?$", "powershell"), (r"cmd(\.exe)?$", "cmd.exe"), (r"bash(\.exe)?$", "bash")] {
39 if Regex::new(pattern).unwrap().is_match(&value) {
40 return name.into();
41 }
42 }
43 value.rsplit(['\\', '/']).next().unwrap_or("").to_string()
46pub async fn detect_platform(manager: &SessionManager, record: &Arc<SessionRecord>, refresh: bool) -> CoreResult<Value> {
47 if !refresh {
48 if let Some(platform) = record.platform.lock().clone() {
49 return Ok(platform);
50 }
51 }
52 let uname = match manager.exec_channel(record, "uname -s", Duration::from_secs(15), 512 * 1024).await {
53 Ok(mut channel) => {
54 channel.eof().await;
55 channel.finish().await.ok()
56 }
57 Err(error) if error.code == "SESSION_NOT_CONNECTED" => return Err(error),
58 Err(_) => None,
59 };
60 let kernel = uname.as_ref().map(|r| r.stdout.trim().lines().next().unwrap_or("").to_string()).unwrap_or_default();
61 if uname.as_ref().map(|r| r.code == Some(0)).unwrap_or(false) && POSIX_KERNELS.is_match(&kernel) {
62 let platform = json!({ "os": if kernel.starts_with("Linux") { "linux" } else { "posix" }, "kernel": kernel, "detectedBy": "uname" });
63 *record.platform.lock() = Some(platform.clone());
64 return Ok(platform);
65 }
66 let mut channel = manager.exec_channel(record, &encoded_command(WINDOWS_PROBE), Duration::from_secs(60), 512 * 1024).await?;
67 channel.eof().await;
68 let probe = channel.finish().await?;
69 let platform = match parse_windows_output(&probe.stdout, &probe.stderr, probe.code, "PLATFORM_") {
70 Err(error) => json!({ "os": "unknown", "kernel": kernel, "detectedBy": "none", "reason": error.message }),
71 Ok(info) => {
72 let text = |k: &str| info.get(k).map(|v| v.as_str().map(str::to_string).unwrap_or_else(|| if v.is_null() { String::new() } else { v.to_string() })).unwrap_or_default();
73 json!({
74 "os": "windows",
75 "detectedBy": "Win32_OperatingSystem",
76 "caption": text("caption"),
77 "version": text("version"),
78 "build": text("build"),
79 "server": info.get("productType").and_then(Value::as_f64) != Some(1.0),
80 "serverCore": Regex::new(r"(?i)server core").unwrap().is_match(&text("installationType")),
81 "installationType": text("installationType"),
82 "defaultShell": shell_name(&text("defaultShell")),
83 "defaultShellPath": text("defaultShell"),
84 "powershell": text("psVersion"),
85 "is64BitProcess": info.get("is64BitProcess") == Some(&Value::Bool(true)),
86 "languageMode": text("languageMode"),
87 "localAccounts": info.get("localAccounts") == Some(&Value::Bool(true)),
88 "pwsh": text("pwsh"),
89 "unameOutput": kernel
90 })
91 }
92 };
93 *record.platform.lock() = Some(platform.clone());
94 Ok(platform)
97#[cfg(test)]
98mod tests {
99 use super::*;
101 #[test]
102 fn shells() {
103 assert_eq!(shell_name(""), "cmd.exe");
104 assert_eq!(shell_name("C:\\Program Files\\PowerShell\\7\\pwsh.exe"), "pwsh");
105 assert_eq!(shell_name("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"), "powershell");
106 assert_eq!(shell_name("C:\\tools\\fish.exe"), "fish.exe");
107 }
SHA-256a9cb33677591db4e34857559eae3df235aa095cd4cb4220c33d0023d1cee8d3a

CH-J Proprietary Software License 1.14 · Sursa este furnizată în cadrul CH-J Proprietary Software License 1.14. Disponibilitatea sa nu modifică termenii licenţei sau nu acordă drepturi suplimentare.

Archive SHA-25677380d4805485ffa4027fbe7858b5836f197a4aa9d52358a43e2d12d018744df
Fișiere