diff --git a/scripts/check.mjs b/scripts/check.mjs index 32f1ae2..b6ddc31 100644 --- a/scripts/check.mjs +++ b/scripts/check.mjs @@ -325,6 +325,11 @@ const resolveGeoIP = () => file: "geoip.dat", downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`, }); +const resolveEnableLoopback = () => + resolveResource({ + file: "enableLoopback.exe", + downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`, + }); const tasks = [ // { name: "clash", func: resolveClash, retry: 5 }, @@ -336,6 +341,12 @@ const tasks = [ { name: "mmdb", func: resolveMmdb, retry: 5 }, { name: "geosite", func: resolveGeosite, retry: 5 }, { name: "geoip", func: resolveGeoIP, retry: 5 }, + { + name: "enableLoopback", + func: resolveEnableLoopback, + retry: 5, + winOnly: true, + }, ]; async function runTask() { diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 783d23e..2df5f99 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -229,6 +229,18 @@ pub fn open_web_url(url: String) -> CmdResult<()> { wrap_err!(open::that(url)) } + +#[cfg(windows)] +pub mod uwp { + use super::*; + use crate::core::win_uwp; + + #[tauri::command] + pub async fn invoke_uwp_tool() -> CmdResult { + wrap_err!(win_uwp::invoke_uwptools().await) + } +} + #[tauri::command] pub async fn clash_api_get_proxy_delay( name: String, @@ -278,3 +290,13 @@ pub mod service { Ok(()) } } + +#[cfg(not(windows))] +pub mod uwp { + use super::*; + + #[tauri::command] + pub async fn invoke_uwp_tool() -> CmdResult { + Ok(()) + } +} \ No newline at end of file diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs index 4221721..80378f5 100644 --- a/src-tauri/src/core/mod.rs +++ b/src-tauri/src/core/mod.rs @@ -8,5 +8,6 @@ pub mod sysopt; pub mod timer; pub mod tray; pub mod win_service; +pub mod win_uwp; pub use self::core::*; diff --git a/src-tauri/src/core/win_uwp.rs b/src-tauri/src/core/win_uwp.rs new file mode 100644 index 0000000..c34511f --- /dev/null +++ b/src-tauri/src/core/win_uwp.rs @@ -0,0 +1,27 @@ +#![cfg(target_os = "windows")] + +use crate::utils::dirs; +use anyhow::{bail, Result}; +use deelevate::{PrivilegeLevel, Token}; +use runas::Command as RunasCommand; +use std::process::Command as StdCommand; + +pub async fn invoke_uwptools() -> Result<()> { + let binary_path = dirs::service_path()?; + let tool_path = binary_path.with_file_name("enableLoopback.exe"); + + if !tool_path.exists() { + bail!("enableLoopback exe not found"); + } + + let token = Token::with_current_process()?; + let level = token.privilege_level()?; + + match level { + PrivilegeLevel::NotPrivileged => RunasCommand::new(tool_path).status()?, + _ => StdCommand::new(tool_path) + .status()?, + }; + + Ok(()) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0c20bec..aa95484 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -46,6 +46,7 @@ fn main() -> std::io::Result<()> { cmds::get_runtime_yaml, cmds::get_runtime_exists, cmds::get_runtime_logs, + cmds::uwp::invoke_uwp_tool, // verge cmds::get_verge_config, cmds::patch_verge_config, diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx index 19f77ca..c18373c 100644 --- a/src/components/setting/setting-clash.tsx +++ b/src/components/setting/setting-clash.tsx @@ -18,6 +18,10 @@ import { ClashPortViewer } from "./mods/clash-port-viewer"; import { ControllerViewer } from "./mods/controller-viewer"; import { SettingList, SettingItem } from "./mods/setting-comp"; import { ClashCoreViewer } from "./mods/clash-core-viewer"; +import { invoke_uwp_tool } from "@/services/cmds"; +import getSystem from "@/utils/get-system"; + +const isWIN = getSystem() === "windows"; interface Props { onError: (err: Error) => void; @@ -162,6 +166,19 @@ const SettingClash = ({ onError }: Props) => { > {version} + + {isWIN && ( + + + + + + )} ); }; diff --git a/src/locales/en.json b/src/locales/en.json index 6b35743..fb6d1f5 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -75,6 +75,7 @@ "Silent Start": "Silent Start", "System Proxy": "System Proxy", "System Proxy Setting": "System Proxy Setting", + "Open UWP tool": "Open UWP tool", "Proxy Guard": "Proxy Guard", "Guard Duration": "Guard Duration", "Proxy Bypass": "Proxy Bypass", diff --git a/src/locales/ru.json b/src/locales/ru.json index f8ea10b..1d20bf5 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -71,6 +71,7 @@ "Silent Start": "Тихий запуск", "System Proxy": "Системный прокси", "System Proxy Setting": "Настройка системного прокси", + "Open UWP tool": "Открыть UWP инструмент", "Proxy Guard": "Защита прокси", "Guard Duration": "Период защиты", "Proxy Bypass": "Игнорирование прокси", diff --git a/src/locales/zh.json b/src/locales/zh.json index 47cbaf2..3ed39ea 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -75,6 +75,7 @@ "Silent Start": "静默启动", "System Proxy": "系统代理", "System Proxy Setting": "系统代理设置", + "Open UWP tool": "UWP工具", "Proxy Guard": "系统代理守卫", "Guard Duration": "代理守卫间隔", "Proxy Bypass": "代理绕过", diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 02ee72a..5637db7 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -178,3 +178,9 @@ export async function installService() { export async function uninstallService() { return invoke("uninstall_service"); } + +export async function invoke_uwp_tool() { + return invoke("invoke_uwp_tool").catch((err) => + Notice.error(err?.message || err.toString(), 1500) + ); +}