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:
url_policy.rs Hinzugefügt: Datum nicht erfasst 3,7 KB · 77 Zeilen
Code Datei herunterladen
1//! HTTPS allowlist for update and module catalogs (port of `security/urlPolicy.js`).
3use crate::core::error::{CoreError, CoreResult};
4use url::Url;
6pub fn normalize_base_url(value: &str) -> CoreResult<Url> {
7 let mut url = Url::parse(value).map_err(|_| CoreError::plain("Invalid update base URL."))?;
8 if url.scheme() != "https" {
9 return Err(CoreError::plain("Update URL must use HTTPS."));
10 }
11 if !url.username().is_empty() || url.password().is_some() || url.fragment().is_some() || url.query().is_some() {
12 return Err(CoreError::plain("Invalid update base URL."));
13 }
14 let path = format!("{}/", url.path().trim_end_matches('/'));
15 url.set_path(&path);
16 Ok(url)
19#[derive(Default)]
20pub struct AllowOptions<'a> {
21 pub base_url: Option<&'a str>,
22 pub path_segment: Option<&'a str>,
25pub fn assert_allowed_url(candidate: &str, allowed: &[String], options: &AllowOptions<'_>) -> CoreResult<Url> {
26 let raw = candidate.trim();
27 if raw.is_empty() {
28 return Err(CoreError::plain("Missing URL."));
29 }
30 let bases = allowed.iter().map(|b| normalize_base_url(b)).collect::<CoreResult<Vec<_>>>()?;
31 if raw.starts_with('/') {
32 let base = normalize_base_url(options.base_url.ok_or_else(|| CoreError::plain("Relative URL requires a base URL."))?)?;
33 let joined = base.join(raw.trim_start_matches('/')).map_err(|_| CoreError::plain("Invalid URL."))?;
34 return assert_allowed_url(joined.as_str(), allowed, options);
35 }
36 let url = Url::parse(raw).map_err(|_| CoreError::plain("Invalid URL."))?;
37 if !url.username().is_empty() || url.password().is_some() || url.fragment().is_some() {
38 return Err(CoreError::plain("URL credentials and fragments are not allowed."));
39 }
40 let matched = bases
41 .iter()
42 .find(|base| url.scheme() == base.scheme() && url.host_str() == base.host_str() && url.port() == base.port() && url.path().starts_with(base.path()))
43 .ok_or_else(|| CoreError::plain("URL is outside the update allowlist."))?;
44 if let Some(segment) = options.path_segment {
45 if !url.path().starts_with(&format!("{}{}", matched.path(), segment)) {
46 return Err(CoreError::plain("URL path is outside the allowed update area."));
47 }
48 }
49 Ok(url)
52/// External links the main window may open in the system browser (same rule as 0.1.0).
53pub fn is_allowed_external_url(value: &str) -> bool {
54 Url::parse(value).map(|u| u.scheme() == "https" && u.host_str() == Some("ch-j.de")).unwrap_or(false)
57#[cfg(test)]
58mod tests {
59 use super::*;
61 #[test]
62 fn allowlist() {
63 let allowed = vec!["https://sm.ch-j.de/".to_string()];
64 assert!(assert_allowed_url("https://sm.ch-j.de/files/a.dmg", &allowed, &AllowOptions { path_segment: Some("files/"), ..Default::default() }).is_ok());
65 assert!(assert_allowed_url("https://sm.ch-j.de/api/x", &allowed, &AllowOptions { path_segment: Some("files/"), ..Default::default() }).is_err());
66 assert!(assert_allowed_url("https://evil.example/files/a", &allowed, &AllowOptions::default()).is_err());
67 assert!(assert_allowed_url("https://u:p@sm.ch-j.de/x", &allowed, &AllowOptions::default()).is_err());
68 assert!(assert_allowed_url("http://sm.ch-j.de/x", &allowed, &AllowOptions::default()).is_err());
69 assert!(assert_allowed_url("https://sm.ch-j.de:444/x", &allowed, &AllowOptions::default()).is_err());
70 assert_eq!(
71 assert_allowed_url("/files/b.deb", &allowed, &AllowOptions { base_url: Some("https://sm.ch-j.de"), ..Default::default() }).unwrap().as_str(),
72 "https://sm.ch-j.de/files/b.deb"
73 );
74 assert!(is_allowed_external_url("https://ch-j.de/x"));
75 assert!(!is_allowed_external_url("http://ch-j.de/x"));
76 }
SHA-2567a388a16d70c648cf3475620249f973b3a944509c527c66014cacb6b39ac505e

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