CH-J Toolspamamahala ng server sa pamamagitan ng SSH
Menu
Nailathalang source

CH-J Tools

I-browse ang mga direktoryo at file ng isang partikular na release ng application.

I-download ang source ZIP
CH-J / Server Manager 1704 file
0.1.2-beta Idinagdag: · Binuo:
profiles.rs Idinagdag: Hindi naitala ang petsa 6.3 KB · 151 linya
Code I-download ang file
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 // No filter: a key file can have any name, and macOS merges a filter list and hides every other name.
49 &[],
50 )
51 .await;
52 Ok(json!({ "canceled": path.is_none(), "path": path.map(|p| p.to_string_lossy().to_string()) }))
55#[tauri::command]
56pub async fn core_profiles_export(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
57 let core = main_core(&webview, &slot)?;
58 let payload = super::payload(payload);
59 let result = async {
60 let generation = core.vault.unlocked_generation()?;
61 let format = payload.get("format").and_then(Value::as_str).filter(|f| !f.is_empty()).unwrap_or("json").to_string();
62 let profiles = core.profiles.list()?;
63 let selected: Vec<Value> = match payload.get("ids") {
64 None | Some(Value::Null) => profiles,
65 Some(Value::Array(ids)) => profiles.into_iter().filter(|p| ids.contains(&p["id"])).collect(),
66 Some(_) => Vec::new(),
67 };
68 if selected.is_empty() {
69 return Err(CoreError::plain("Select at least one server to export."));
70 }
71 let content = serialize_profiles(&selected, &format)?;
72 let window = dialogs::main_window(&core.app);
73 let upper = format.to_uppercase();
74 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 {
75 return Ok(json!({ "canceled": true }));
76 };
77 core.vault.with_generation(generation, || write_private(&path, content.as_bytes()))?;
78 Ok(json!({ "canceled": false, "count": selected.len() }))
79 }
80 .await;
81 logged(&core, "profiles:export", result)
84pub fn write_private(path: &std::path::Path, data: &[u8]) -> CoreResult<()> {
85 let mut options = std::fs::OpenOptions::new();
86 options.write(true).create(true).truncate(true);
87 #[cfg(unix)]
88 {
89 use std::os::unix::fs::OpenOptionsExt;
90 options.mode(0o600);
91 }
92 use std::io::Write;
93 options.open(path)?.write_all(data)?;
94 Ok(())
97#[tauri::command]
98pub async fn core_profiles_preview_import(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
99 let core = main_core(&webview, &slot)?;
100 let result = async {
101 let generation = core.vault.unlocked_generation()?;
102 core.profiles.list()?; // Require an unlocked vault before opening the picker.
103 core.profile_transfer.cancel();
104 let window = dialogs::main_window(&core.app);
105 let Some(path) = dialogs::pick_file(&core.app, window.as_ref(), None, &[Filter { name: &core.t("native.profiles.importFilter"), extensions: &["json", "csv"] }]).await else {
106 return Ok(json!({ "canceled": true }));
107 };
108 core.vault.assert_generation(generation)?;
109 let mut buffer = Vec::new();
110 std::fs::File::open(&path)?.take(MAX_BYTES as u64 + 1).read_to_end(&mut buffer)?;
111 if buffer.len() > MAX_BYTES {
112 return Err(CoreError::plain("Profile file exceeds the 5 MiB limit."));
113 }
114 let content = String::from_utf8(buffer).map_err(|_| CoreError::plain("The encoded data was not valid for encoding utf-8"))?;
115 let mut preview = core.profile_transfer.preview(&core.profiles, &content)?;
116 core.vault.assert_generation(generation)?;
117 preview["canceled"] = json!(false);
118 let mut ordered = serde_json::Map::new();
119 ordered.insert("canceled".into(), json!(false));
120 if let Value::Object(fields) = preview {
121 for (k, v) in fields {
122 if k != "canceled" {
123 ordered.insert(k, v);
124 }
125 }
126 }
127 Ok(Value::Object(ordered))
128 }
129 .await;
130 logged(&core, "profiles:previewImport", result)
133#[tauri::command]
134pub async fn core_profiles_commit_import(webview: Webview, slot: State<'_, CoreSlot>, payload: Option<Value>) -> CommandResult {
135 let core = main_core(&webview, &slot)?;
136 let payload = super::payload(payload);
137 let result: CoreResult<Value> = async {
138 core.services.biometrics.require_sensitive_action().await?;
139 core.profile_transfer.commit(&core.profiles, text(&payload, "token"), text(&payload, "policy"))
140 }
141 .await;
142 core.services.availability.changed();
143 logged(&core, "profiles:commitImport", result)
146#[tauri::command]
147pub async fn core_profiles_cancel_import(webview: Webview, slot: State<'_, CoreSlot>) -> CommandResult {
148 let core = main_core(&webview, &slot)?;
149 core.profile_transfer.cancel();
150 Ok(json!({ "canceled": true }))
SHA-256ace82260ae376d692b5831bf57c8505953b9ed32d841075e8e616946c0461c70

CH-J Proprietary Software License 1.14 · Ibinibigay ang source sa ilalim ng CH-J Proprietary Software License 1.14. Hindi binabago ng pagiging available nito ang mga tuntunin ng lisensya at hindi ito nagbibigay ng karagdagang karapatan.

SHA-256 ng archiveac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
Mga file