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)
+ );
+}