CH-J ToolsSerververwaltung über SSH
Menü
Veröffentlichte Quellen

CH-J Tools

Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.

Quellen als ZIP herunterladen
CH-J / Server Manager 872 Dateien
core-20261030T220507Z-61e4558d889f Hinzugefügt: · Erstellt:
caller.rs Hinzugefügt: Datum nicht erfasst 5,0 KB · 137 Zeilen
Code Datei herunterladen
1//! Who is calling? Every command resolves the calling webview to a role before it does
2//! 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.
5use crate::core::error::{CoreError, CoreResult};
6use parking_lot::RwLock;
7use serde_json::Value;
8use std::collections::HashMap;
9use std::path::PathBuf;
10use std::sync::Arc;
12pub const MAIN_LABEL: &str = "main";
13pub const LICENSE_LABEL: &str = "license";
14pub const MODULE_LABEL_PREFIX: &str = "module-";
16#[derive(Clone, Debug)]
17pub struct ModuleContext {
18 pub id: String,
19 pub label: String,
20 pub manifest: Value,
21 pub permissions: Vec<String>,
22 pub root: PathBuf,
25impl 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 }
35#[derive(Default)]
36pub struct WindowRegistry {
37 modules: RwLock<HashMap<String, Arc<ModuleContext>>>,
40impl 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 context
45 }
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 }
64/// Origin checks: the main and license windows may only run the bundled app pages.
65pub 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 }
73pub 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 }
81pub 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 }
89/// The page of a module window must still be the module's own entry origin.
90pub 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 }
100pub 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 }
112#[cfg(test)]
113mod 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(&registry, "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(&registry, "module-1", url::Url::parse("chj-module://chj.disks/ui/index.html").ok()).is_err());
131 assert!(require_module(&registry, "module-2", url::Url::parse("chj-module://chj.users/").ok()).is_err());
132 assert!(require_module(&registry, "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 }
SHA-256843e66def97776515cb48e70fb57f3e60d64394f22143ad1f5b476a0a7a7986a

CH-J Proprietary Software License 1.14 · Die Quellen werden unter der CH-J Proprietary Software License 1.14 bereitgestellt. Ihre Verfügbarkeit ändert die Lizenzbedingungen nicht und gewährt keine zusätzlichen Rechte.

SHA-256 des Archivs77380d4805485ffa4027fbe7858b5836f197a4aa9d52358a43e2d12d018744df
Dateien