manager.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. use std::borrow::Cow;
  2. /// 给clash内核的tun模式授权
  3. #[cfg(any(target_os = "macos", target_os = "linux"))]
  4. pub fn grant_permission(core: String) -> anyhow::Result<()> {
  5. use std::process::Command;
  6. use tauri::utils::platform::current_exe;
  7. let path = current_exe()?.with_file_name(core).canonicalize()?;
  8. let path = path.display().to_string();
  9. log::debug!("grant_permission path: {path}");
  10. #[cfg(target_os = "macos")]
  11. let output = {
  12. // the path of clash /Applications/Clash Verge.app/Contents/MacOS/clash
  13. // https://apple.stackexchange.com/questions/82967/problem-with-empty-spaces-when-executing-shell-commands-in-applescript
  14. let path = escape(&path);
  15. let shell = format!("chown root:admin {path}\nchmod +sx {path}");
  16. let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
  17. Command::new("osascript")
  18. .args(vec!["-e", &command])
  19. .output()?
  20. };
  21. #[cfg(target_os = "linux")]
  22. let output = {
  23. let path = path.replace(' ', "\\ "); // 避免路径中有空格
  24. let shell = format!("setcap cap_net_bind_service,cap_net_admin=+ep {path}");
  25. Command::new("sudo")
  26. .arg("sh")
  27. .arg("-c")
  28. .arg(shell)
  29. .output()?
  30. };
  31. if output.status.success() {
  32. Ok(())
  33. } else {
  34. let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
  35. anyhow::bail!("{stderr}");
  36. }
  37. }
  38. pub fn escape<'a>(text: &'a str) -> Cow<'a, str> {
  39. let bytes = text.as_bytes();
  40. let mut owned = None;
  41. for pos in 0..bytes.len() {
  42. let special = match bytes[pos] {
  43. b' ' => Some(b' '),
  44. _ => None,
  45. };
  46. if let Some(s) = special {
  47. if owned.is_none() {
  48. owned = Some(bytes[0..pos].to_owned());
  49. }
  50. owned.as_mut().unwrap().push(b'\\');
  51. owned.as_mut().unwrap().push(b'\\');
  52. owned.as_mut().unwrap().push(s);
  53. } else if let Some(owned) = owned.as_mut() {
  54. owned.push(bytes[pos]);
  55. }
  56. }
  57. if let Some(owned) = owned {
  58. unsafe { Cow::Owned(String::from_utf8_unchecked(owned)) }
  59. } else {
  60. unsafe { Cow::Borrowed(std::str::from_utf8_unchecked(bytes)) }
  61. }
  62. }