CH-J Toolsspráva serverů přes SSH
Menu
Vydané zdroje

CH-J Tools

Procházejte adresáře a soubory konkrétního vydání aplikace.

Stáhnout zdroje ZIP
CH-J / Server Manager 872 souborů
core-20261030T220507Z-61e4558d889f Přidáno: · Sestaveno:
profiles.rs Přidáno: Datum není evidováno 6,1 KB · 146 řádků
Kód Stáhnout soubor
1//! Server profiles, portable import/export and private-key selection.
3use super::{logged, main_core, text, CommandResult};
4use crate::core::app::CoreSlot;
5use crate::core::error::{CoreError, CoreResult};
6use crate::core::profile_transfer::{serialize_profiles, MAX_BYTES};
7use crate::dialogs::{self, Filter};
8use serde_json::{json, Value};
9use std::io::Read;
10use tauri::{State, Webview};
12#[tauri::command]
13pub async fn core_profiles_list(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
14 let core = main_core(&webview, &slot)?;
15 logged(&core, "profiles:list", core.profiles.list().map(Value::Array))
18#[tauri::command]
19pub async fn core_profiles_save(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
20 let core = main_core(&webview, &slot)?;
21 let payload = super::payload(payload);
22 let result = core.profiles.save(&payload);
23 core.services.availability.changed();
24 logged(&core, "profiles:save", result)
27#[tauri::command]
28pub async fn core_profiles_delete(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
29 let core = main_core(&webview, &slot)?;
30 let payload = super::payload(payload);
31 let result = async {
32 core.services.biometrics.require_sensitive_action().await?;
33 core.profiles.delete(text(&payload, "id"))
34 }
35 .await;
36 core.services.availability.changed();
37 logged(&core, "profiles:delete", result)
40#[tauri::command]
41pub async fn core_profiles_select_private_key(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
42 let core = main_core(&webview, &slot)?;
43 let window = dialogs::main_window(&core.app);
44 let path = dialogs::pick_file(
45 &core.app,
46 window.as_ref(),
47 Some(&core.t("native.privateKey.title")),
48 &[Filter { name: &core.t("native.privateKey.keys"), extensions: &["pem", "key", "ppk"] }, Filter { name: &core.t("native.privateKey.all"), extensions: &["*"] }],
49 )
50 .await;
51 Ok(json!({ "canceled": path.is_none(), "path": path.map(|p| p.to_string_lossy().to_string()) }))
54#[tauri::command]
55pub async fn core_profiles_export(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
56 let core = main_core(&webview, &slot)?;
57 let payload = super::payload(payload);
58 let result = async {
59 let format = payload.get("format").and_then(Value::as_str).filter(|f| !f.is_empty()).unwrap_or("json").to_string();
60 let profiles = core.profiles.list()?;
61 let selected: Vec<Value> = match payload.get("ids") {
62 None | Some(Value::Null) => profiles,
63 Some(Value::Array(ids)) => profiles.into_iter().filter(|p| ids.contains(&p["id"])).collect(),
64 Some(_) => Vec::new(),
65 };
66 if selected.is_empty() {
67 return Err(CoreError::plain("Select at least one server to export."));
68 }
69 let content = serialize_profiles(&selected, &format)?;
70 let window = dialogs::main_window(&core.app);
71 let upper = format.to_uppercase();
72 let Some(path) = dialogs::save_file(&core.app, window.as_ref(), None, &format!("chj-server-profiles.{format}"), &[Filter { name: &upper, extensions: &[format.as_str()] }]).await else {
73 return Ok(json!({ "canceled": true }));
74 };
75 write_private(&path, content.as_bytes())?;
76 Ok(json!({ "canceled": false, "count": selected.len() }))
77 }
78 .await;
79 logged(&core, "profiles:export", result)
82pub fn write_private(path: &std::path::Path, data: &[u8]) -> CoreResult<()> {
83 let mut options = std::fs::OpenOptions::new();
84 options.write(true).create(true).truncate(true);
85 #[cfg(unix)]
86 {
87 use std::os::unix::fs::OpenOptionsExt;
88 options.mode(0o600);
89 }
90 use std::io::Write;
91 options.open(path)?.write_all(data)?;
92 Ok(())
95#[tauri::command]
96pub async fn core_profiles_preview_import(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
97 let core = main_core(&webview, &slot)?;
98 let result = async {
99 core.profiles.list()?; // Require an unlocked vault before opening the picker.
100 core.profile_transfer.cancel();
101 let window = dialogs::main_window(&core.app);
102 let Some(path) = dialogs::pick_file(&core.app, window.as_ref(), None, &[Filter { name: &core.t("native.profiles.importFilter"), extensions: &["json", "csv"] }]).await else {
103 return Ok(json!({ "canceled": true }));
104 };
105 let mut buffer = Vec::new();
106 std::fs::File::open(&path)?.take(MAX_BYTES as u64 + 1).read_to_end(&mut buffer)?;
107 if buffer.len() > MAX_BYTES {
108 return Err(CoreError::plain("Profile file exceeds the 5 MiB limit."));
109 }
110 let content = String::from_utf8(buffer).map_err(|_| CoreError::plain("The encoded data was not valid for encoding utf-8"))?;
111 let mut preview = core.profile_transfer.preview(&core.profiles, &content)?;
112 preview["canceled"] = json!(false);
113 let mut ordered = serde_json::Map::new();
114 ordered.insert("canceled".into(), json!(false));
115 if let Value::Object(fields) = preview {
116 for (k, v) in fields {
117 if k != "canceled" {
118 ordered.insert(k, v);
119 }
120 }
121 }
122 Ok(Value::Object(ordered))
123 }
124 .await;
125 logged(&core, "profiles:previewImport", result)
128#[tauri::command]
129pub async fn core_profiles_commit_import(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
130 let core = main_core(&webview, &slot)?;
131 let payload = super::payload(payload);
132 let result: CoreResult<Value> = async {
133 core.services.biometrics.require_sensitive_action().await?;
134 core.profile_transfer.commit(&core.profiles, text(&payload, "token"), text(&payload, "policy"))
135 }
136 .await;
137 core.services.availability.changed();
138 logged(&core, "profiles:commitImport", result)
141#[tauri::command]
142pub async fn core_profiles_cancel_import(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
143 let core = main_core(&webview, &slot)?;
144 core.profile_transfer.cancel();
145 Ok(json!({ "canceled": true }))
SHA-256f9de07b02a3456c19e098b48a579bf00ff8c9368edcbaad9133557954783cc62

CH-J Proprietary Software License 1.14 · Zdroje jsou zveřejněny pod CH-J Proprietary Software License 1.14. Jejich dostupnost nemění licenční podmínky ani neposkytuje další oprávnění.

SHA-256 archivu77380d4805485ffa4027fbe7858b5836f197a4aa9d52358a43e2d12d018744df
Soubory