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
872 souborů
core-20261030T220507Z-61e4558d889f
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
pub const MODULE_LABEL_PREFIX: &str = "module-";16
#[derive(Clone, Debug)]17
pub struct ModuleContext {18
pub id: String,19
pub label: String,20
pub manifest: Value,21
pub permissions: Vec<String>,22
pub root: PathBuf,23
}25
impl ModuleContext {26
pub fn require(&self, permission: &str) -> CoreResult<()> {27
if self.permissions.iter().any(|p| p == permission) {28
Ok(())29
} else {30
Err(CoreError::new("PLUGIN_PERMISSION_DENIED", format!("Plugin permission denied: {permission}")))31
}32
}33
}35
#[derive(Default)]36
pub struct WindowRegistry {37
modules: RwLock<HashMap<String, Arc<ModuleContext>>>,38
}40
impl WindowRegistry {41
pub fn register_module(&self, context: ModuleContext) -> Arc<ModuleContext> {42
let context = Arc::new(context);43
self.modules.write().insert(context.label.clone(), context.clone());44
context45
}47
pub fn unregister_module(&self, label: &str) -> Option<Arc<ModuleContext>> {48
self.modules.write().remove(label)49
}51
pub fn module_by_label(&self, label: &str) -> Option<Arc<ModuleContext>> {52
self.modules.read().get(label).cloned()53
}55
pub fn module_by_id(&self, id: &str) -> Option<Arc<ModuleContext>> {56
self.modules.read().values().find(|c| c.id == id).cloned()57
}59
pub fn modules(&self) -> Vec<Arc<ModuleContext>> {60
self.modules.read().values().cloned().collect()61
}62
}64
/// Origin checks: the main and license windows may only run the bundled app pages.65
pub fn is_app_url(url: &url::Url) -> bool {66
match url.scheme() {67
"tauri" => url.host_str() == Some("localhost"),68
"http" | "https" => url.host_str() == Some("tauri.localhost"),69
_ => false,70
}71
}73
pub fn require_main(label: &str, url: Option<url::Url>) -> CoreResult<()> {74
if label == MAIN_LABEL && url.as_ref().map(is_app_url).unwrap_or(false) {75
Ok(())76
} else {77
Err(CoreError::new("UNTRUSTED_IPC_SENDER", "Untrusted IPC sender."))78
}79
}81
pub fn require_license(label: &str, url: Option<url::Url>) -> CoreResult<()> {82
if label == LICENSE_LABEL && url.as_ref().map(is_app_url).unwrap_or(false) {83
Ok(())84
} else {85
Err(CoreError::plain("Untrusted license IPC sender."))86
}87
}89
/// The page of a module window must still be the module's own entry origin.90
pub fn module_url_matches(url: &url::Url, module_id: &str) -> bool {91
match url.scheme() {92
"chj-module" => url.host_str() == Some(module_id),93
"http" | "https" => {94
url.host_str() == Some("chj-module.localhost") && url.path_segments().and_then(|mut s| s.next()) == Some(module_id)95
}96
_ => false,97
}98
}100
pub fn require_module(registry: &WindowRegistry, label: &str, url: Option<url::Url>) -> CoreResult<Arc<ModuleContext>> {101
let untrusted = || CoreError::new("UNTRUSTED_PLUGIN_SENDER", "Untrusted plugin IPC sender.");102
if !label.starts_with(MODULE_LABEL_PREFIX) {103
return Err(untrusted());104
}105
let context = registry.module_by_label(label).ok_or_else(untrusted)?;106
match url {107
Some(url) if module_url_matches(&url, &context.id) => Ok(context),108
_ => Err(untrusted()),109
}110
}112
#[cfg(test)]113
mod tests {114
use super::*;115
use serde_json::json;117
#[test]118
fn module_identity_and_permissions() {119
let registry = WindowRegistry::default();120
registry.register_module(ModuleContext {121
id: "chj.users".into(),122
label: "module-1".into(),123
manifest: json!({}),124
permissions: vec!["users.read".into()],125
root: PathBuf::new(),126
});127
let ok = require_module(®istry, "module-1", url::Url::parse("chj-module://chj.users/ui/index.html").ok()).unwrap();128
assert!(ok.require("users.read").is_ok());129
assert_eq!(ok.require("users.manage").unwrap_err().code, "PLUGIN_PERMISSION_DENIED");130
assert!(require_module(®istry, "module-1", url::Url::parse("chj-module://chj.disks/ui/index.html").ok()).is_err());131
assert!(require_module(®istry, "module-2", url::Url::parse("chj-module://chj.users/").ok()).is_err());132
assert!(require_module(®istry, "module-1", url::Url::parse("http://chj-module.localhost/chj.users/ui/index.html").ok()).is_ok());133
assert!(require_main("main", url::Url::parse("tauri://localhost/index.html").ok()).is_ok());134
assert!(require_main("main", url::Url::parse("https://evil.example/").ok()).is_err());135
assert!(require_main("module-1", url::Url::parse("tauri://localhost/").ok()).is_err());136
}137
}SHA-256
843e66def97776515cb48e70fb57f3e60d64394f22143ad1f5b476a0a7a7986aCH-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
77380d4805485ffa4027fbe7858b5836f197a4aa9d52358a43e2d12d018744df