94 lines
2.8 KiB
Rust
94 lines
2.8 KiB
Rust
use std::fs;
|
|
use std::path::Path;
|
|
|
|
use serde_json::Value;
|
|
|
|
fn manifest_dir() -> &'static Path {
|
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
}
|
|
|
|
fn read_json(path: impl AsRef<Path>) -> Value {
|
|
let raw = fs::read_to_string(path.as_ref()).expect("read json file");
|
|
serde_json::from_str(&raw).expect("valid json")
|
|
}
|
|
|
|
#[test]
|
|
fn csp_keeps_loopback_narrow() {
|
|
let conf = read_json(manifest_dir().join("tauri.conf.json"));
|
|
let csp = conf
|
|
.pointer("/app/security/csp")
|
|
.and_then(Value::as_str)
|
|
.expect("csp string");
|
|
let connect_src = csp
|
|
.split(';')
|
|
.map(str::trim)
|
|
.find(|directive| directive.starts_with("connect-src "))
|
|
.expect("connect-src directive");
|
|
|
|
assert!(connect_src.contains("http://127.0.0.1:*"));
|
|
assert!(connect_src.contains("ws://127.0.0.1:*"));
|
|
assert!(!connect_src.contains("http://localhost:*"));
|
|
assert!(!connect_src.contains("ws://localhost:*"));
|
|
}
|
|
|
|
#[test]
|
|
fn updater_is_signed_or_absent() {
|
|
let conf = read_json(manifest_dir().join("tauri.conf.json"));
|
|
if let Some(updater) = conf.pointer("/plugins/updater") {
|
|
let pubkey = updater
|
|
.get("pubkey")
|
|
.and_then(Value::as_str)
|
|
.unwrap_or_default();
|
|
assert!(
|
|
!pubkey.trim().is_empty(),
|
|
"updater config must not ship with an empty pubkey"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn secondary_windows_do_not_get_high_risk_plugin_permissions() {
|
|
let denied = [
|
|
"dialog:",
|
|
"autostart:",
|
|
"global-shortcut:",
|
|
"opener:",
|
|
"updater:",
|
|
];
|
|
let capability_dir = manifest_dir().join("capabilities");
|
|
|
|
for entry in fs::read_dir(capability_dir).expect("capabilities dir") {
|
|
let path = entry.expect("capability entry").path();
|
|
if path.extension().and_then(|ext| ext.to_str()) != Some("json") {
|
|
continue;
|
|
}
|
|
let capability = read_json(&path);
|
|
let windows = capability
|
|
.get("windows")
|
|
.and_then(Value::as_array)
|
|
.cloned()
|
|
.unwrap_or_default();
|
|
let applies_to_secondary = windows.iter().any(|window| {
|
|
matches!(
|
|
window.as_str(),
|
|
Some("tasks-float" | "transcript-viewer" | "transcription-preview")
|
|
)
|
|
});
|
|
if !applies_to_secondary {
|
|
continue;
|
|
}
|
|
let permissions = capability
|
|
.get("permissions")
|
|
.and_then(Value::as_array)
|
|
.cloned()
|
|
.unwrap_or_default();
|
|
for permission in permissions.iter().filter_map(Value::as_str) {
|
|
assert!(
|
|
!denied.iter().any(|prefix| permission.starts_with(prefix)),
|
|
"{} grants high-risk permission {permission} to a secondary window",
|
|
path.display()
|
|
);
|
|
}
|
|
}
|
|
}
|