Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(clash): add default core secret and impl port checker before clash start #533

Merged
merged 4 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/Cargo.lock

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

1 change: 1 addition & 0 deletions backend/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ tracing-appender = { version = "0.2", features = ["parking_lot"] }
base64 = "0.21"
single-instance = "0.3.3"
tauri-plugin-deep-link = { path = "../tauri-plugin-deep-link", version = "0.1.2" }
uuid = "1.7.0"

[target.'cfg(windows)'.dependencies]
deelevate = "0.2.0"
Expand Down
6 changes: 3 additions & 3 deletions backend/tauri/src/cmds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
}

#[tauri::command]
pub async fn change_clash_core(clash_core: Option<ClashCore>) -> CmdResult {
pub async fn change_clash_core(clash_core: Option<nyanpasu::ClashCore>) -> CmdResult {
wrap_err!(CoreManager::global().change_core(clash_core).await)
}

Expand Down Expand Up @@ -272,7 +272,7 @@ pub async fn fetch_latest_core_versions() -> CmdResult<ManifestVersionLatest> {
}

#[tauri::command]
pub async fn get_core_version(core_type: ClashCore) -> CmdResult<String> {
pub async fn get_core_version(core_type: nyanpasu::ClashCore) -> CmdResult<String> {
match tokio::task::spawn_blocking(move || resolve::resolve_core_version(&core_type)).await {
Ok(Ok(version)) => Ok(version),
Ok(Err(err)) => Err(format!("{err}")),
Expand Down Expand Up @@ -305,7 +305,7 @@ pub async fn collect_logs() -> CmdResult {
}

#[tauri::command]
pub async fn update_core(core_type: ClashCore) -> CmdResult {
pub async fn update_core(core_type: nyanpasu::ClashCore) -> CmdResult {
wrap_err!(
updater::Updater::global()
.read()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use crate::utils::{dirs, help};
use crate::utils::{
dirs,
help::{self, get_clash_external_port},
};
use anyhow::Result;
use log::warn;
use serde::{Deserialize, Serialize};
use serde_yaml::{Mapping, Value};
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
str::FromStr,
};
use tracing_attributes::instrument;

use super::Config;

#[derive(Default, Debug, Clone)]
pub struct IClashTemp(pub Mapping);
Expand All @@ -32,7 +39,10 @@ impl IClashTemp {
map.insert("external-controller".into(), "127.0.0.1:9872".into());
#[cfg(not(debug_assertions))]
map.insert("external-controller".into(), "127.0.0.1:17650".into());
map.insert("secret".into(), "".into());
map.insert(
"secret".into(),
uuid::Uuid::new_v4().to_string().to_lowercase().into(), // generate a uuid v4 as default secret to secure the communication between clash and the client
);
#[cfg(feature = "default-meta")]
map.insert("unified-delay".into(), true.into());
#[cfg(feature = "default-meta")]
Expand Down Expand Up @@ -84,6 +94,35 @@ impl IClashTemp {
}
}

#[allow(dead_code)]
pub fn get_external_controller_port(&self) -> u16 {
let server = self.get_client_info().server;
let port = server.split(':').last().unwrap_or("9090");
port.parse().unwrap_or(9090)
}

#[instrument]
pub fn prepare_external_controller_port(&mut self) -> Result<()> {
let strategy = Config::verge()
.latest()
.get_external_controller_port_strategy();
let server = self.get_client_info().server;
let (server_ip, server_port) = server.split_once(':').unwrap_or(("127.0.0.1", "9090"));
let server_port = server_port.parse::<u16>().unwrap_or(9090);
let port = get_clash_external_port(&strategy, server_port)?;
if port != server_port {
let new_server = format!("{}:{}", server_ip, port);
warn!(
"The external controller port has been changed to {}",
new_server
);
let mut map = Mapping::new();
map.insert("external-controller".into(), new_server.into());
self.patch_config(map);
}
Ok(())
}

pub fn guard_mixed_port(config: &Mapping) -> u16 {
let mut port = config
.get("mixed-port")
Expand Down
6 changes: 4 additions & 2 deletions backend/tauri/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod clash;
mod core;
mod draft;
mod nyanpasu;
pub mod nyanpasu;
mod prfitem;
mod profiles;
mod runtime;

pub use self::{clash::*, core::*, draft::*, nyanpasu::*, prfitem::*, profiles::*, runtime::*};
pub use self::{clash::*, core::*, draft::*, prfitem::*, profiles::*, runtime::*};

pub use self::nyanpasu::IVerge;
25 changes: 25 additions & 0 deletions backend/tauri/src/config/nyanpasu/clash_strategy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct ClashStrategy {
pub external_controller_port_strategy: ExternalControllerPortStrategy,
}

#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ExternalControllerPortStrategy {
Fixed,
Random,
#[default]
AllowFallback,
}

impl super::IVerge {
pub fn get_external_controller_port_strategy(&self) -> ExternalControllerPortStrategy {
self.clash_strategy
.as_ref()
.unwrap_or(&ClashStrategy::default())
.external_controller_port_strategy
.to_owned()
}
}
16 changes: 12 additions & 4 deletions backend/tauri/src/config/nyanpasu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ use anyhow::Result;
// use log::LevelFilter;
use serde::{Deserialize, Serialize};

mod clash_strategy;
pub mod logging;

pub use self::clash_strategy::{ClashStrategy, ExternalControllerPortStrategy};
pub use logging::LoggingLevel;

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub enum ClashCore {
#[serde(rename = "clash", alias = "clash-premium")]
Expand Down Expand Up @@ -133,7 +137,7 @@ pub struct IVerge {

/// 日志清理
/// 分钟数; 0 为不清理
#[deprecated(note = "use `window_size_state` instead")]
#[deprecated(note = "use `max_log_files` instead")]
pub auto_log_clean: Option<i64>,
/// 日记轮转时间,单位:天
pub max_log_files: Option<usize>,
Expand All @@ -152,7 +156,10 @@ pub struct IVerge {
pub verge_mixed_port: Option<u16>,

/// Check update when app launch
pub disbale_auto_check_update: Option<bool>,
pub disable_auto_check_update: Option<bool>,

/// Clash 相关策略
pub clash_strategy: Option<ClashStrategy>,
}

#[derive(Default, Debug, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -219,7 +226,7 @@ impl IVerge {
page_transition_animation: Some("slide".into()),
// auto_log_clean: Some(60 * 24 * 7), // 7 days 自动清理日记
max_log_files: Some(7), // 7 days
disbale_auto_check_update: Some(true),
disable_auto_check_update: Some(true),
..Self::default()
}
}
Expand Down Expand Up @@ -247,7 +254,7 @@ impl IVerge {
patch!(traffic_graph);
patch!(enable_memory_usage);
patch!(page_transition_animation);
patch!(disbale_auto_check_update);
patch!(disable_auto_check_update);

patch!(enable_tun_mode);
patch!(enable_service_mode);
Expand All @@ -273,5 +280,6 @@ impl IVerge {

patch!(max_log_files);
patch!(window_size_state);
patch!(clash_strategy);
}
}
17 changes: 14 additions & 3 deletions backend/tauri/src/core/clash/core.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use super::api;
use crate::{config::*, core::logger::Logger, log_err, utils::dirs};
use crate::{
config::{nyanpasu::ClashCore, Config, ConfigType},
core::logger::Logger,
log_err,
utils::dirs,
};
use anyhow::{bail, Context, Result};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
Expand Down Expand Up @@ -83,8 +88,6 @@ impl CoreManager {

/// 启动核心
pub async fn run_core(&self) -> Result<()> {
let config_path = Config::generate_file(ConfigType::Run)?;

#[allow(unused_mut)]
let mut should_kill = match self.sidecar.lock().take() {
Some(child) => {
Expand All @@ -106,6 +109,14 @@ impl CoreManager {
if should_kill {
sleep(Duration::from_millis(500)).await;
}

// 检查端口是否可用
Config::clash()
.latest()
.prepare_external_controller_port()?;

let config_path = Config::generate_file(ConfigType::Run)?;

#[cfg(target_os = "macos")]
{
let enable_tun = Config::verge().latest().enable_tun_mode;
Expand Down
2 changes: 1 addition & 1 deletion backend/tauri/src/core/updater.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{collections::HashMap, io::Cursor, path::Path, sync::OnceLock};

use super::CoreManager;
use crate::config::ClashCore;
use crate::config::nyanpasu::ClashCore;
use anyhow::{anyhow, Result};
use gunzip::Decompressor;
use log::{debug, warn};
Expand Down
2 changes: 1 addition & 1 deletion backend/tauri/src/core/win_service.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(target_os = "windows")]

use crate::{
config::{ClashCore, Config},
config::{nyanpasu::ClashCore, Config},
utils::dirs,
};
use anyhow::{bail, Context, Result};
Expand Down
2 changes: 1 addition & 1 deletion backend/tauri/src/enhance/chain.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
config::{ClashCore, PrfItem},
config::{nyanpasu::ClashCore, PrfItem},
utils::{dirs, help},
};
use serde_yaml::Mapping;
Expand Down
16 changes: 15 additions & 1 deletion backend/tauri/src/feat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
config::*,
core::*,
log_err,
utils::{self, resolve},
utils::{self, help::get_clash_external_port, resolve},
};
use anyhow::{bail, Result};
use serde_yaml::{Mapping, Value};
Expand Down Expand Up @@ -211,6 +211,20 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
}
};

// 检测 external-controller port 是否修改
if let Some(external_controller) = patch.get("external-controller") {
let external_controller = external_controller.as_str().unwrap();
let changed = external_controller != Config::clash().data().get_client_info().server;
if changed {
let (_, port) = external_controller.split_once(':').unwrap();
let port = port.parse::<u16>()?;
let strategy = Config::verge()
.latest()
.get_external_controller_port_strategy();
get_clash_external_port(&strategy, port)?; // Do a check
}
}

// 激活配置
if mixed_port.is_some()
|| patch.get("secret").is_some()
Expand Down
26 changes: 26 additions & 0 deletions backend/tauri/src/utils/help.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::nyanpasu::ExternalControllerPortStrategy;
use anyhow::{anyhow, bail, Context, Result};
use nanoid::nanoid;
use serde::{de::DeserializeOwned, Serialize};
Expand All @@ -7,6 +8,7 @@ use tauri::{
api::shell::{open, Program},
Manager,
};

/// read data from yaml as struct T
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
if !path.exists() {
Expand Down Expand Up @@ -114,6 +116,30 @@ pub fn mapping_to_i18n_key(locale_key: &str) -> &'static str {
}
}

pub fn get_clash_external_port(
strategy: &ExternalControllerPortStrategy,
port: u16,
) -> anyhow::Result<u16> {
match strategy {
ExternalControllerPortStrategy::Fixed => {
if !port_scanner::local_port_available(port) {
bail!("Port {} is not available", port);
}
}
ExternalControllerPortStrategy::Random | ExternalControllerPortStrategy::AllowFallback => {
if ExternalControllerPortStrategy::AllowFallback == *strategy
&& port_scanner::local_port_available(port)
{
return Ok(port);
}
let new_port = port_scanner::request_open_port()
.ok_or_else(|| anyhow!("Can't find an open port"))?;
return Ok(new_port);
}
}
Ok(port)
}

#[macro_export]
macro_rules! error {
($result: expr) => {
Expand Down
2 changes: 1 addition & 1 deletion backend/tauri/src/utils/init/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use tracing_appender::{
};
use tracing_subscriber::{filter, fmt, layer::SubscriberExt, reload, EnvFilter};

pub type ReloadSignal = (Option<config::logging::LoggingLevel>, Option<usize>);
pub type ReloadSignal = (Option<config::nyanpasu::LoggingLevel>, Option<usize>);

struct Channel(Option<Sender<ReloadSignal>>);
impl Channel {
Expand Down
5 changes: 4 additions & 1 deletion backend/tauri/src/utils/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
config::{ClashCore, Config, IVerge, WindowState},
config::{
nyanpasu::{ClashCore, WindowState},
Config, IVerge,
},
core::{
tasks::{jobs::ProfilesJobGuard, JobsManager},
tray::proxies,
Expand Down
3 changes: 2 additions & 1 deletion renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
},
{
"matchManagers": ["cargo"],
"rangeStrategy": "update-lockfile"
"rangeStrategy": "update-lockfile",
"platformAutomerge": false
},
{
"groupName": "Bundler packages",
Expand Down
Loading
Loading