//! Users facade: chooses the Linux or Windows backend from system facts of the remote host //! (uname / Win32_OperatingSystem) and returns only IPC-safe data. use super::common::fail; use super::linux::LinuxUsers; use super::windows::WindowsUsers; use crate::core::error::CoreResult; use crate::core::ssh::platform::detect_platform; use crate::core::ssh::session::SessionManager; use serde_json::Value; use std::sync::Arc; pub struct UserAdmin { pub sessions: Arc, pub linux: LinuxUsers, pub windows: WindowsUsers, } impl UserAdmin { /// `Some(platform)` for Windows servers, `None` for Linux/POSIX. async fn windows(&self, session_id: &str) -> CoreResult> { let record = self.sessions.require_connected(session_id)?; let platform = detect_platform(&self.sessions, &record, false).await?; match platform["os"].as_str() { Some("windows") => Ok(Some(platform)), Some("unknown") => Err(fail( "USERS_PLATFORM_UNSUPPORTED", &format!("The remote operating system could not be identified: {}.", platform["reason"].as_str().filter(|s| !s.is_empty()).unwrap_or("no POSIX shell and no Windows PowerShell")), )), _ => Ok(None), } } pub async fn privileges(&self, session_id: &str, refresh: bool) -> CoreResult { if self.windows(session_id).await?.is_some() { return self.windows.privileges(session_id).await; } self.linux.privileges(session_id, refresh).await } pub async fn inventory(&self, session_id: &str, options: &Value) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { return self.windows.inventory(session_id, &platform).await; } Ok(self.linux.inventory(session_id, options).await?.public) } pub async fn list(&self, session_id: &str) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { let inventory = self.windows.inventory(session_id, &platform).await?; return Ok(Value::Array(inventory["users"].as_array().cloned().unwrap_or_default().into_iter().filter(|u| u["system"] != true).collect())); } self.linux.list_compat(session_id).await } pub async fn detail(&self, session_id: &str, options: &Value) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { return Ok(self.windows.detail(session_id, options, &platform).await?.public); } self.linux.detail_public(session_id, options).await } pub async fn manage(&self, session_id: &str, payload: &Value) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { return self.windows.manage(session_id, payload, &platform).await; } self.linux.manage(session_id, payload).await } pub async fn keys(&self, session_id: &str, payload: &Value) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { return self.windows.keys(session_id, payload, &platform).await; } self.linux.keys(session_id, payload).await } pub async fn ssh_policy(&self, session_id: &str, payload: &Value) -> CoreResult { if let Some(platform) = self.windows(session_id).await? { return self.windows.ssh_policy(session_id, payload, &platform).await; } self.linux.ssh_policy(session_id, payload).await } }