Vydané zdroje
Stáhnout zdroje ZIP
CH-J Tools
Procházejte adresáře a soubory konkrétního vydání aplikace.
CH-J / Server Manager
1704 souborů
0.1.2-beta
Přidáno: · Sestaveno:
1
//! Who is calling? Every command resolves the calling webview to a role before it does2
//! anything. Module windows are registered by the module runtime when it creates them;3
//! an unknown or closed window is rejected like `UNTRUSTED_PLUGIN_SENDER` in 0.1.0.5
use crate::core::error::{CoreError, CoreResult};6
use parking_lot::RwLock;7
use serde_json::Value;8
use std::collections::HashMap;9
use std::path::PathBuf;10
use std::sync::Arc;12
pub const MAIN_LABEL: &str = "main";13
pub const LICENSE_LABEL: &str = "license";14
/// Small window of a system quick action (verify/sign one file); see `core/quick.rs`.15
pub const QUICK_LABEL: &str = "quick";16
pub const MODULE_LABEL_PREFIX: &str = "module-";18
#[derive(Clone, Debug)]19
pub struct ModuleContext {20
pub id: String,21
pub label: String,22
pub manifest: Value,23
pub permissions: Vec<String>,24
pub root: PathBuf,25
}27
impl ModuleContext {28
pub fn require(&self, permission: &str) -> CoreResult<()> {29
if self.permissions.iter().any(|p| p == permission) {30
Ok(())31
} else {32
Err(CoreError::new("PLUGIN_PERMISSION_DENIED", format!("Plugin permission denied: {permission}")))33
}34
}35
}37
#[derive(Default)]38
pub struct WindowRegistry {39
modules: RwLock<HashMap<String, Arc<ModuleContext>>>,40
}42
impl WindowRegistry {43
pub fn register_module(&self, context: ModuleContext) -> Arc<ModuleContext> {44
let context = Arc::new(context);45
self.modules.write().insert(context.label.clone(), context.clone());46
context47
}49
pub fn unregister_module(&self, label: &str) -> Option<Arc<ModuleContext>> {50
self.modules.write().remove(label)51
}53
pub fn module_by_label(&self, label: &str) -> Option<Arc<ModuleContext>> {54
self.modules.read().get(label).cloned()55
}57
pub fn module_by_id(&self, id: &str) -> Option<Arc<ModuleContext>> {58
self.modules.read().values().find(|c| c.id == id).cloned()59
}61
pub fn modules(&self) -> Vec<Arc<ModuleContext>> {62
self.modules.read().values().cloned().collect()63
}64
}66
/// Origin checks: the main and license windows may only run the bundled app pages.67
pub fn is_app_url(url: &url::Url) -> bool {68
match url.scheme() {69
"tauri" => url.host_str() == Some("localhost"),70
"http" | "https" => url.host_str() == Some("tauri.localhost"),71
_ => false,72
}73
}75
pub fn require_main(label: &str, url: Option<url::Url>) -> CoreResult<()> {76
if label == MAIN_LABEL && url.as_ref().map(is_app_url).unwrap_or(false) {77
Ok(())78
} else {79
Err(CoreError::new("UNTRUSTED_IPC_SENDER", "Untrusted IPC sender."))80
}81
}83
pub fn require_license(label: &str, url: Option<url::Url>) -> CoreResult<()> {84
if label == LICENSE_LABEL && url.as_ref().map(is_app_url).unwrap_or(false) {85
Ok(())86
} else {87
Err(CoreError::plain("Untrusted license IPC sender."))88
}89
}91
pub fn require_quick(label: &str, url: Option<url::Url>) -> CoreResult<()> {92
if label == QUICK_LABEL && url.as_ref().map(is_app_url).unwrap_or(false) {93
Ok(())94
} else {95
Err(CoreError::new("UNTRUSTED_IPC_SENDER", "Untrusted IPC sender."))96
}97
}99
/// The page of a module window must still be the module's own entry origin.100
pub fn module_url_matches(url: &url::Url, module_id: &str) -> bool {101
match url.scheme() {102
"chj-module" => url.host_str() == Some(module_id),103
"http" | "https" => {104
url.host_str().is_some_and(|host| host.strip_prefix("chj-module.").and_then(|rest| rest.strip_suffix(".localhost")) == Some(module_id))105
}106
_ => false,107
}108
}110
pub fn require_module(registry: &WindowRegistry, label: &str, url: Option<url::Url>) -> CoreResult<Arc<ModuleContext>> {111
let untrusted = || CoreError::new("UNTRUSTED_PLUGIN_SENDER", "Untrusted plugin IPC sender.");112
if !label.starts_with(MODULE_LABEL_PREFIX) {113
return Err(untrusted());114
}115
let context = registry.module_by_label(label).ok_or_else(untrusted)?;116
match url {117
Some(url) if module_url_matches(&url, &context.id) => Ok(context),118
_ => Err(untrusted()),119
}120
}122
#[cfg(test)]123
mod tests {124
use super::*;125
use serde_json::json;127
#[test]128
fn module_identity_and_permissions() {129
let registry = WindowRegistry::default();130
registry.register_module(ModuleContext {131
id: "chj.users".into(),132
label: "module-1".into(),133
manifest: json!({}),134
permissions: vec!["users.read".into()],135
root: PathBuf::new(),136
});137
let ok = require_module(®istry, "module-1", url::Url::parse("chj-module://chj.users/ui/index.html").ok()).unwrap();138
assert!(ok.require("users.read").is_ok());139
assert_eq!(ok.require("users.manage").unwrap_err().code, "PLUGIN_PERMISSION_DENIED");140
assert!(require_module(®istry, "module-1", url::Url::parse("chj-module://chj.disks/ui/index.html").ok()).is_err());141
assert!(require_module(®istry, "module-2", url::Url::parse("chj-module://chj.users/").ok()).is_err());142
assert!(require_module(®istry, "module-1", url::Url::parse("http://chj-module.chj.users.localhost/ui/index.html").ok()).is_ok());143
assert!(require_main("main", url::Url::parse("tauri://localhost/index.html").ok()).is_ok());144
assert!(require_main("main", url::Url::parse("https://evil.example/").ok()).is_err());145
assert!(require_main("module-1", url::Url::parse("tauri://localhost/").ok()).is_err());146
}147
}SHA-256
e2bfa6eb4b60d48abb7aa8aa944a9db618452c0b18f5c9b96a3b639440babcffCH-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 archivu
ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f