//! Application info, legal documents, configuration, languages and window controls. use super::{logged, main_core, payload, text, CommandResult}; use crate::core::app::{CoreSlot, CORE_API_VERSION, COPYRIGHT, DATA_SCHEMA, MODULE_API_VERSION}; use crate::core::error::{CoreError, CoreResult}; use crate::core::legal::{LICENSE_NAME, LICENSE_VERSION}; use crate::security::caller::MAIN_LABEL; use crate::security::url_policy::is_allowed_external_url; use serde_json::{json, Value}; use tauri::{Manager, State, Webview}; use tauri_plugin_opener::OpenerExt; #[tauri::command] pub async fn core_get_info(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { let core = main_core(&webview, &slot)?; core.services.modules.install_close_guard(&core)?; let (platform, arch) = crate::core::diagnostics::http::node_platform_arch(); Ok(json!({ "name": "CH-J Server Manager", "version": core.build.version, "buildId": core.build.build_id, "platform": platform, "arch": arch, "coreApi": CORE_API_VERSION, "pluginApi": MODULE_API_VERSION, "moduleApi": MODULE_API_VERSION, "dataSchema": DATA_SCHEMA, "license": format!("{LICENSE_NAME} {LICENSE_VERSION}"), "copyright": COPYRIGHT, "runtime": "tauri" })) } #[tauri::command] pub async fn core_legal_open(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); let result = (|| -> CoreResult { let key = text(&payload, "document"); let path = match key { "documentation" => core.paths.docs().join("README.md"), "safetyCzech" => core.paths.docs().join("provozni-bezpecnost-a-zalohovani.md"), "safetyEnglish" => core.paths.docs().join("operational-safety-and-backup-guidance.md"), "safetyGerman" => core.paths.docs().join("betriebssicherheit-und-datensicherung.md"), "application" => core.paths.licenses().join("APPLICATION_LICENSE.txt"), "notice" => core.paths.licenses().join("NOTICE.txt"), // Electron/Chromium are no longer shipped; their former entries open the // third-party notices that now cover Tauri, WebView and Rust crates. "thirdParty" | "tauri" | "electron" | "chromium" => core.paths.licenses().join("THIRD_PARTY_NOTICES.txt"), "thirdPartyBundle" => core.paths.licenses().join("THIRD_PARTY_LICENSES.zip"), _ => return Err(CoreError::plain("Unknown legal document.")), }; core.app.opener().open_path(path.to_string_lossy(), None::<&str>).map_err(|e| CoreError::plain(format!("The legal document could not be opened: {e}")))?; Ok(json!({ "ok": true })) })(); logged(&core, "legal:open", result) } #[tauri::command] pub async fn core_open_external(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); let url = text(&payload, "url"); if !is_allowed_external_url(url) { return logged(&core, "core:openExternal", Err(CoreError::plain("The address is not an allowed external link."))); } core.app.opener().open_url(url, None::<&str>).map_err(|e| CoreError::plain(e.to_string()))?; Ok(json!({ "ok": true })) } #[tauri::command] pub async fn core_config_get(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { Ok(main_core(&webview, &slot)?.config.get()) } #[tauri::command] pub async fn core_config_update(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); let result = async { if payload.get("security").map(|s| !s.is_null()).unwrap_or(false) { core.vault.verify_password(text(&payload, "masterPassword")).await?; if payload["security"]["requireSystemAuthentication"] == true && core.services.biometrics.availability().await["available"] != true { return Err(CoreError::plain("BIOMETRIC_UNAVAILABLE")); } } let config = core.config.update(&payload)?; core.services.modules.notify_language(&core, &core.config.language()); Ok(config) } .await; core.services.availability.changed(); logged(&core, "config:update", result) } #[tauri::command] pub async fn core_i18n_languages(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { Ok(main_core(&webview, &slot)?.i18n.languages_json()) } /// Frameless window controls; every window may control only itself. #[tauri::command] pub async fn window_control(webview: Webview, payload: Option) -> CommandResult { let payload = payload_or_empty(payload); let window = webview.window(); if text(&payload, "action") == "closeQueryReply" { if let Some(core) = webview.app_handle().state::().try_get() { if let (Some(id), Some(dirty)) = (payload["queryId"].as_u64(), payload["dirty"].as_bool()) { core.services.modules.close_query_reply(window.label(), id, dirty); } } return Ok(json!({ "ok": true })); } let result = match text(&payload, "action") { "minimize" => window.minimize(), "toggleMaximize" => { if window.is_maximized().unwrap_or(false) { window.unmaximize() } else { window.maximize() } } "close" => window.close(), "startDrag" => window.start_dragging(), _ => return Err(CoreError::plain("Unknown window action.")), }; result.map_err(|e| CoreError::plain(e.to_string()))?; Ok(json!({ "ok": true })) } fn payload_or_empty(value: Option) -> Value { payload(value) } #[tauri::command] pub async fn window_is_maximized(webview: Webview) -> CommandResult { Ok(json!(webview.window().is_maximized().unwrap_or(false))) } /// User activity from any Core-owned window (vault auto-lock). #[tauri::command] pub fn window_activity(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { if let Some(core) = slot.try_get() { let label = webview.label(); if label == MAIN_LABEL || core.windows.module_by_label(label).is_some() { core.services.lock.activity(); } } let _ = webview.app_handle(); Ok(Value::Null) }