//! Vault and OS-protected unlocking commands. use super::{envelope, logged, main_core, payload, text, CommandResult}; use crate::core::app::CoreSlot; use crate::core::error::{CoreError, CoreResult}; use serde_json::{json, Value}; use tauri::{Manager, State, Webview}; fn status_value(status: crate::core::vault::VaultStatus) -> Value { serde_json::to_value(status).unwrap_or_else(|_| json!({})) } #[tauri::command] pub async fn core_vault_status(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { Ok(status_value(main_core(&webview, &slot)?.vault.status())) } #[tauri::command] pub async fn core_vault_create(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); let result = core.vault.create(text(&payload, "password")).await.map(status_value); if result.is_ok() { core.services.lock.activity(); } core.services.availability.changed(); logged(&core, "vault:create", result) } #[tauri::command] pub async fn core_vault_unlock(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); core.services.biometrics.cancel(); let result = core.vault.unlock(text(&payload, "password")).await.map(status_value); if result.is_ok() { core.services.biometrics.disarm_auto_unlock(); core.services.lock.activity(); } core.services.availability.changed(); logged(&core, "vault:unlock", result) } #[tauri::command] pub async fn core_vault_lock(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { let core = main_core(&webview, &slot)?; let status = core.services.lock.lock(&core, "manual").await; core.services.availability.changed(); Ok(status_value(status)) } #[tauri::command] pub async fn core_vault_reset(webview: Webview, slot: State<'_, CoreSlot>, payload: Option) -> CommandResult { let core = main_core(&webview, &slot)?; let payload = super::payload(payload); let result = async { let confirmation = text(&payload, "confirmation"); if confirmation != "SMAZAT" { return Err(CoreError::new("VAULT_RESET_CONFIRMATION_REQUIRED", "Vault reset confirmation is invalid.")); } if core.vault.is_unlocked() { core.services.biometrics.require_sensitive_action().await?; } core.services.biometrics.disable(true).await?; core.services.modules.close_all(&core); core.services.sessions.disconnect_all("vault-reset").await; let status = core.vault.reset(confirmation)?; core.logger.warn("Encrypted user vault was reset by the user.", json!({})); Ok(status_value(status)) } .await; logged(&core, "vault:reset", result) } async fn biometric(webview: Webview, slot: State<'_, CoreSlot>, work: impl FnOnce(std::sync::Arc) -> F) -> CommandResult where F: std::future::Future>, { let core = main_core(&webview, &slot)?; Ok(envelope(work(core).await, "SSH_OPERATION_FAILED", None)) } #[tauri::command] pub async fn core_biometrics_status(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { biometric(webview, slot, |core| async move { Ok(core.services.biometrics.status().await) }).await } #[tauri::command] pub async fn core_biometrics_enable(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { biometric(webview, slot, |core| async move { core.services.biometrics.enable().await }).await } #[tauri::command] pub async fn core_biometrics_disable(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { biometric(webview, slot, |core| async move { core.services.biometrics.disable(false).await }).await } #[tauri::command] pub async fn core_biometrics_unlock(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { biometric(webview, slot, |core| async move { let status = core.services.biometrics.unlock().await?; core.services.lock.activity(); Ok(status) }) .await } #[tauri::command] pub async fn core_biometrics_auto_unlock(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { let window = webview.window(); let ready = window.is_visible().unwrap_or(false) && !window.is_minimized().unwrap_or(true); let _ = window.app_handle(); biometric(webview, slot, move |core| async move { if !ready { return Ok(json!({ "attempted": false, "reason": "WINDOW_NOT_READY" })); } let result = core.services.biometrics.auto_unlock().await; if result["status"]["unlocked"] == true { core.services.lock.activity(); } Ok(result) }) .await } #[tauri::command] pub async fn core_biometrics_authenticate(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult { biometric(webview, slot, |core| async move { core.services.biometrics.authenticate_sensitive_action().await }).await } pub fn _unused(value: Option) -> Value { payload(value) }