Skip to content

Commit

Permalink
feat: add tun premission warning dialog and auto-granted premission i…
Browse files Browse the repository at this point in the history
…n unix os
  • Loading branch information
greenhat616 committed Sep 23, 2024
1 parent 76c3fa1 commit 38b2512
Show file tree
Hide file tree
Showing 11 changed files with 3,159 additions and 4,910 deletions.
2 changes: 2 additions & 0 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions backend/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,13 @@ objc2-app-kit = { version = "0.2.2", features = [
] }
objc2-foundation = { version = "0.2.2", features = ["NSGeometry"] }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.29.0", features = ["user", "fs"] }

[target.'cfg(windows)'.dependencies]
deelevate = "0.2.0"
winreg = { version = "0.52", features = ["transactions"] }
windows-registry = "0.2"
windows-sys = { version = "0.59", features = [
"Win32_System_LibraryLoader",
"Win32_System_SystemInformation",
Expand Down
7,905 changes: 3,011 additions & 4,894 deletions backend/tauri/gen/schemas/linux-schema.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions backend/tauri/src/core/manager.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::{config::nyanpasu::ClashCore, core::find_binary_path};
use std::borrow::Cow;

/// 给clash内核的tun模式授权
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn grant_permission(core: String) -> anyhow::Result<()> {
pub fn grant_permission(core: &ClashCore) -> anyhow::Result<()> {
use std::process::Command;
use tauri::utils::platform::current_exe;

let path = current_exe()?.with_file_name(core).canonicalize()?;
let path = path.display().to_string();
let path = find_binary_path(&core).map_err(|| anyhow::anyhow!("clash core not found"))?;

log::debug!("grant_permission path: {path}");

Expand Down
88 changes: 88 additions & 0 deletions backend/tauri/src/enhance/advice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::enhance::{script::runner::ProcessOutput, Logs, LogsExt};
use rust_i18n::t;
use serde_yaml::Mapping;

// TODO: add more advice for chain
pub fn chain_advice(config: &Mapping) -> ProcessOutput {
// FIXME: its clone is not necessary
let mut logs = Logs::default();
if config.get("tun").is_some_and(|val| {
val.is_mapping()
&& !val
.as_mapping()
.unwrap()
.get("enable")
.is_some_and(|val| val.as_bool().unwrap_or(false))
}) {
let service_state = crate::core::service::ipc::get_ipc_state();
// show a warning dialog if the user has no permission to enable tun
#[cfg(windows)]
{
use deelevate::{PrivilegeLevel, Token};
let level = {
match Token::with_current_process() {
Ok(token) => token
.privilege_level()
.unwrap_or(PrivilegeLevel::NotPrivileged),
Err(_) => PrivilegeLevel::NotPrivileged,
}
};
if level == PrivilegeLevel::NotPrivileged && !service_state.is_connected() {
let msg = t!("dialog.warning.enable_tun_with_no_permission");
logs.warn(msg.as_ref());
crate::utils::dialog::warning_dialog(msg.as_ref());
}
}
// If the core file is not granted the necessary permissions, grant it
#[cfg(any(target_os = "macos", target_os = "linux"))]
{
#[cfg(target_os = "macos")]
const ROOT_GROUP: &str = "admin";
#[cfg(target_os = "linux")]
const ROOT_GROUP: &str = "root";

use nix::unistd::{Gid, Group as NixGroup, Uid, User};
use std::os::unix::fs::MetadataExt;
if !service_state.is_connected() {
let core = {
crate::config::Config::verge()
.latest()
.clash_core
.as_ref()
.unwrap_or(&crate::config::nyanpasu::ClashCore::default())
};
let core_path = crate::core::clash::core::find_binary_path(&core);
if let Some(core_path) = core_path {
if let Some(metadata) = std::fs::metadata(&core_path).ok() {
let uid = metadata.uid();
let gid = metadata.gid();
let user = User::from_uid(Uid::from_raw(uid)).ok().flatten();
let group = NixGroup::from_gid(Gid::from_raw(gid)).ok().flatten();
if let (Some(user), Some(group)) = (user, group) {
if !*crate::consts::IS_APPIMAGE
&& (user.name() != "root" || group.name() != ROOT_GROUP)
{
tracing::warn!("The core file is not granted the necessary permissions, grant it");
let msg = t!("dialog.info.grant_core_permission");
if crate::utils::dialog::ask_dialog(&msg) {
if let Err(err) = crate::core::manager::grant_permission(&core)
{
tracing::error!(
"Failed to grant permission to the core file: {}",
err
);
crate::utils::dialog::error_dialog(&format!(
"failed to grant core permission:\n{:#?}",
err
));
}
}
}
}
}
}
}
}
}
(Ok(Mapping::new()), logs)
}
4 changes: 4 additions & 0 deletions backend/tauri/src/enhance/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod advice;
mod chain;
mod field;
mod merge;
Expand Down Expand Up @@ -143,6 +144,9 @@ pub async fn enhance() -> (Mapping, Vec<String>, IndexMap<String, Logs>) {
config = use_cache(config);
config = use_sort(config, enable_filter);

let (_, logs) = advice::chain_advice(&config);
result_map.insert("chain_advice".into(), logs);

let mut exists_set = HashSet::new();
exists_set.extend(exists_keys.into_iter().filter(|s| clash_fields.contains(s)));
exists_keys = exists_set.into_iter().collect();
Expand Down
16 changes: 8 additions & 8 deletions backend/tauri/src/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,14 @@ pub async fn restart_sidecar() -> CmdResult {
wrap_err!(CoreManager::global().run_core().await)
}

#[tauri::command]
pub fn grant_permission(_core: String) -> CmdResult {
#[cfg(any(target_os = "macos", target_os = "linux"))]
return wrap_err!(manager::grant_permission(_core));

#[cfg(not(any(target_os = "macos", target_os = "linux")))]
return Err("Unsupported target".into());
}
// #[tauri::command]
// pub fn grant_permission(_core: String) -> CmdResult {
// #[cfg(any(target_os = "macos", target_os = "linux"))]
// return wrap_err!(manager::grant_permission(_core));

// #[cfg(not(any(target_os = "macos", target_os = "linux")))]
// return Err("Unsupported target".into());
// }

/// get the system proxy
#[tauri::command]
Expand Down
3 changes: 2 additions & 1 deletion backend/tauri/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(auto_traits, negative_impls, let_chains)]
#![feature(std_internals)]
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
Expand Down Expand Up @@ -248,7 +249,7 @@ pub fn run() -> std::io::Result<()> {
ipc::open_core_dir,
// cmds::kill_sidecar,
ipc::restart_sidecar,
ipc::grant_permission,
// ipc::grant_permission,
// clash
ipc::get_clash_info,
ipc::get_clash_logs,
Expand Down
25 changes: 23 additions & 2 deletions backend/tauri/src/utils/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,32 @@ pub fn migrate_dialog(msg: &str) -> bool {
)
}

pub fn error_dialog(msg: String) {
pub fn error_dialog<T: Into<String>>(msg: T) {
MessageDialog::new()
.set_level(MessageLevel::Error)
.set_title("Clash Nyanpasu Error")
.set_description(msg.as_str())
.set_description(msg.into())
.set_buttons(MessageButtons::Ok)
.show();
}

pub fn warning_dialog<T: Into<String>>(msg: T) {
MessageDialog::new()
.set_level(MessageLevel::Warning)
.set_title("Clash Nyanpasu Warning")
.set_description(msg.into())
.set_buttons(MessageButtons::Ok)
.show();
}

pub fn ask_dialog<T: Into<String>>(msg: T) -> bool {
matches!(
MessageDialog::new()
.set_level(MessageLevel::Info)
.set_title("Clash Nyanpasu")
.set_buttons(MessageButtons::YesNo)
.set_description(msg.into())
.show(),
MessageDialogResult::Yes
)
}
8 changes: 7 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
"dialog": {
"panic": "Please report this issue to Github issue tracker.",
"migrate": "Old version config file detected\nMigrate to new version or not?\n WARNING: This will override your current config if exists",
"custom_app_dir_migrate": "You will set custom app dir to %{path}\n Shall we move the current app dir to the new one?"
"custom_app_dir_migrate": "You will set custom app dir to %{path}\n Shall we move the current app dir to the new one?",
"warning": {
"enable_tun_with_no_permission": "TUN mode requires admin permission or service mode, neither is enabled, TUN mode will not work properly."
},
"info": {
"grant_core_permission": "Clash core needs admin permission to make TUN mode work properly, grant it?\n\nPlease note: This operation requires password input."
}
}
}
8 changes: 7 additions & 1 deletion locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
"dialog": {
"panic": "请将此问题汇报到 Github 问题追踪器",
"migrate": "检测到旧版本配置文件\n是否迁移到新版本?\n警告: 此操作会覆盖掉现有配置文件",
"custom_app_dir_migrate": "你将要更改应用目录至 %{path}。\n需要将现有数据迁移到新目录吗?"
"custom_app_dir_migrate": "你将要更改应用目录至 %{path}。\n需要将现有数据迁移到新目录吗?",
"warning": {
"enable_tun_with_no_permission": "TUN 模式需要管理员权限,或服务模式,当前都未开启,因此 TUN 模式将无法正常工作"
},
"info": {
"grant_core_permission": "Clash 内核需要管理员权限才能使得 TUN 模式正常工作,是否授予?\n\n请注意:此操作需要输入密码。"
}
}
}

0 comments on commit 38b2512

Please sign in to comment.