mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-08 02:52:07 +08:00
fix(security): restrict external URL opening
Close: 7800
This commit is contained in:
@@ -23,11 +23,6 @@ pub async fn open_logs_dir() -> CmdResult<()> {
|
||||
open::that(log_dir).stringify_err()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_web_url(url: String) -> CmdResult<()> {
|
||||
open::that(url.as_str()).stringify_err()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_devtools(app_handle: AppHandle) {
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
|
||||
@@ -16,6 +16,17 @@ use tokio::fs;
|
||||
use reqwest_dav::re_exports::url::form_urlencoded;
|
||||
use tauri::Url;
|
||||
|
||||
pub(super) fn normalize_profile_home_url(raw: &str) -> Option<String> {
|
||||
let url = Url::parse(raw.trim()).ok()?;
|
||||
|
||||
if !matches!(url.scheme(), "http" | "https") {
|
||||
return None;
|
||||
}
|
||||
|
||||
url.host_str()?;
|
||||
Some(url.to_string().into())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||
pub struct PrfItem {
|
||||
pub uid: Option<String>,
|
||||
@@ -332,13 +343,10 @@ impl PrfItem {
|
||||
},
|
||||
};
|
||||
|
||||
let home = match header.get("profile-web-page-url") {
|
||||
Some(value) => {
|
||||
let str_value = value.to_str().unwrap_or("");
|
||||
Some(str_value.into())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let home = header
|
||||
.get("profile-web-page-url")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.and_then(normalize_profile_home_url);
|
||||
|
||||
let uid = help::get_uid("R").into();
|
||||
let file = format!("{uid}.yaml").into();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
PrfOption,
|
||||
prfitem::{PrfItem, PrfSelected},
|
||||
prfitem::{PrfItem, PrfSelected, normalize_profile_home_url},
|
||||
};
|
||||
use crate::{
|
||||
core::{handle, tray::Tray},
|
||||
@@ -106,6 +106,7 @@ impl IProfiles {
|
||||
match help::read_yaml::<Self>(&path).await {
|
||||
Ok(mut profiles) => {
|
||||
let items = profiles.items.get_or_insert_with(Vec::new);
|
||||
let mut home_changed = false;
|
||||
for item in items.iter_mut() {
|
||||
if item.uid.is_none() {
|
||||
item.uid = Some(help::get_uid("d").into());
|
||||
@@ -116,6 +117,19 @@ impl IProfiles {
|
||||
.allow_auto_update
|
||||
.get_or_insert(true);
|
||||
}
|
||||
|
||||
if item
|
||||
.home
|
||||
.as_deref()
|
||||
.is_some_and(|home| normalize_profile_home_url(home).is_none())
|
||||
{
|
||||
item.home = None;
|
||||
home_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if home_changed && let Err(err) = profiles.save_file().await {
|
||||
logging!(error, Type::Config, "无法保存已清理的 profiles.yaml: {err}");
|
||||
}
|
||||
profiles
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ mod app_init {
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(
|
||||
@@ -128,7 +129,6 @@ mod app_init {
|
||||
cmd::get_embedded_server_port,
|
||||
cmd::open_app_dir,
|
||||
cmd::open_logs_dir,
|
||||
cmd::open_web_url,
|
||||
cmd::open_core_dir,
|
||||
cmd::get_portable_flag,
|
||||
cmd::get_network_interfaces,
|
||||
|
||||
Reference in New Issue
Block a user