diff --git a/Cargo.toml b/Cargo.toml index b7deab3..91ad89f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,4 @@ indicatif = "0.17" tokio = { version = "1.34", features = ["full"] } truncatable = "0.1" anyhow = "1.0" +base64 = "0.22.1" diff --git a/src/mihoro.rs b/src/mihoro.rs index 64522f2..5a33593 100644 --- a/src/mihoro.rs +++ b/src/mihoro.rs @@ -2,7 +2,9 @@ use crate::cmd::ProxyCommands; use crate::config::{apply_mihomo_override, parse_config, Config}; use crate::proxy::{proxy_export_cmd, proxy_unset_cmd}; use crate::systemctl::Systemctl; -use crate::utils::{create_parent_dir, delete_file, download_file, extract_gzip}; +use crate::utils::{ + create_parent_dir, delete_file, download_file, extract_gzip, try_decode_base64_file_inplace, +}; use std::fs; use std::os::unix::prelude::PermissionsExt; @@ -83,6 +85,10 @@ impl Mihoro { &self.mihomo_target_config_path, ) .await?; + + // Try to decode base64 file in place if file is base64 encoding, otherwise do nothing + try_decode_base64_file_inplace(&self.mihomo_target_config_path)?; + apply_mihomo_override(&self.mihomo_target_config_path, &self.config.mihomo_config)?; // Download geodata @@ -109,6 +115,10 @@ impl Mihoro { &self.mihomo_target_config_path, ) .await?; + + // Try to decode base64 file in place if file is base64 encoding, otherwise do nothing + try_decode_base64_file_inplace(&self.mihomo_target_config_path)?; + apply_mihomo_override(&self.mihomo_target_config_path, &self.config.mihomo_config)?; println!( "{} Updated and applied config overrides", diff --git a/src/utils.rs b/src/utils.rs index 4e778a6..e441c0b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,11 +1,12 @@ use std::{ cmp::min, fs::{self, File}, - io::{self, Write}, + io::{self, BufWriter, Read, Seek, SeekFrom, Write}, path::Path, }; use anyhow::{Context, Result}; +use base64::{prelude::BASE64_STANDARD, Engine}; use colored::Colorize; use flate2::read::GzDecoder; use futures_util::StreamExt; @@ -126,3 +127,39 @@ pub fn extract_gzip(gzip_path: &str, filename: &str, prefix: &str) -> Result<()> ); Ok(()) } + +/// Try and decode a base64 encoded file in place. +/// +/// Decodes the base64 encoded content of a file in place and writes the decoded content back to the +/// file. If the file does not contain base64 encoded content, maintains the file as is. +/// +/// # Arguments +/// +/// * `filepath` - Path to the file to decode base64 content in place. +pub fn try_decode_base64_file_inplace(filepath: &str) -> Result<()> { + // Open the file for reading and writing + let mut file = File::options().read(true).write(true).open(filepath)?; + let mut base64_buf = Vec::new(); + + // Read the file content into the buffer + file.read_to_end(&mut base64_buf)?; + + // Try to decode the base64 content + match BASE64_STANDARD.decode(&base64_buf) { + Ok(decoded_bytes) => { + // Truncate the file and seek to the beginning + file.set_len(0)?; + file.seek(SeekFrom::Start(0))?; + + // Write the decoded bytes back to the file + let mut writer = BufWriter::new(&file); + writer.write_all(&decoded_bytes)?; + } + Err(_) => { + // If decoding fails, do nothing and return Ok + return Ok(()); + } + } + + Ok(()) +}