mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-06-11 17:27:54 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 615d7b8c8a | |||
| 5c26ab5c33 | |||
| dccaf6c7de | |||
| bf5b2886f5 | |||
| bbc12bcc03 |
@@ -3,7 +3,6 @@ use directories::BaseDirs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs::{self, create_dir_all};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use sysinfo::{Pid, System};
|
||||
use tauri::Emitter;
|
||||
@@ -35,6 +34,7 @@ pub struct BrowserProfile {
|
||||
mod macos {
|
||||
use super::*;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn is_tor_or_mullvad_browser(exe_name: &str, cmd: &[OsString], browser_type: &str) -> bool {
|
||||
match browser_type {
|
||||
@@ -605,7 +605,10 @@ mod windows {
|
||||
|
||||
if !output.status.success() {
|
||||
// Fallback: try without -requestPending
|
||||
let mut fallback_cmd = Command::new(browser.get_executable_path(browser_dir)?);
|
||||
let executable_path = browser
|
||||
.get_executable_path(browser_dir)
|
||||
.map_err(|e| format!("Failed to get executable path: {}", e))?;
|
||||
let mut fallback_cmd = Command::new(executable_path);
|
||||
fallback_cmd.args(["-profile", &profile.profile_path, "-new-tab", url]);
|
||||
|
||||
if let Some(parent_dir) = browser_dir
|
||||
@@ -639,12 +642,12 @@ mod windows {
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// On Windows, TOR and Mullvad browsers can sometimes accept URLs via command line
|
||||
// even with -no-remote, by launching a new instance that hands off to existing one
|
||||
let browser = create_browser(browser_type);
|
||||
let browser = create_browser(browser_type.clone());
|
||||
let executable_path = browser
|
||||
.get_executable_path(browser_dir)
|
||||
.map_err(|e| format!("Failed to get executable path: {}", e))?;
|
||||
|
||||
let mut cmd = Command::new(executable_path);
|
||||
let mut cmd = Command::new(&executable_path);
|
||||
cmd.args(["-profile", &profile.profile_path, url]);
|
||||
|
||||
// Set working directory
|
||||
@@ -677,12 +680,12 @@ mod windows {
|
||||
browser_type: BrowserType,
|
||||
browser_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let browser = create_browser(browser_type);
|
||||
let browser = create_browser(browser_type.clone());
|
||||
let executable_path = browser
|
||||
.get_executable_path(browser_dir)
|
||||
.map_err(|e| format!("Failed to get executable path: {}", e))?;
|
||||
|
||||
let mut cmd = Command::new(executable_path);
|
||||
let mut cmd = Command::new(&executable_path);
|
||||
cmd.args([
|
||||
&format!("--user-data-dir={}", profile.profile_path),
|
||||
"--new-window",
|
||||
@@ -701,7 +704,7 @@ mod windows {
|
||||
|
||||
if !output.status.success() {
|
||||
// Try fallback without --new-window
|
||||
let mut fallback_cmd = Command::new(executable_path);
|
||||
let mut fallback_cmd = Command::new(&executable_path);
|
||||
fallback_cmd.args([&format!("--user-data-dir={}", profile.profile_path), url]);
|
||||
|
||||
if let Some(parent_dir) = browser_dir
|
||||
@@ -772,6 +775,7 @@ mod windows {
|
||||
mod linux {
|
||||
use super::*;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn is_tor_or_mullvad_browser(
|
||||
_exe_name: &str,
|
||||
|
||||
@@ -70,7 +70,6 @@ mod windows {
|
||||
use winreg::RegKey;
|
||||
|
||||
const APP_NAME: &str = "DonutBrowser";
|
||||
const APP_EXECUTABLE: &str = "DonutBrowser.exe";
|
||||
const PROG_ID: &str = "DonutBrowser.HTML";
|
||||
|
||||
pub fn is_default_browser() -> Result<bool, String> {
|
||||
@@ -279,7 +278,7 @@ mod windows {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_html_file_association(exe_path: &str) -> Result<(), String> {
|
||||
fn register_html_file_association(_exe_path: &str) -> Result<(), String> {
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
|
||||
// Register .html and .htm file associations
|
||||
@@ -305,7 +304,6 @@ mod windows {
|
||||
// This helps refresh the system's understanding of the changes
|
||||
unsafe {
|
||||
use std::ffi::c_void;
|
||||
use std::ptr;
|
||||
|
||||
// Declare the Windows API functions
|
||||
type UINT = u32;
|
||||
|
||||
+64
-60
@@ -453,8 +453,6 @@ impl Extractor {
|
||||
zip_path: &Path,
|
||||
dest_dir: &Path,
|
||||
) -> Result<PathBuf, Box<dyn std::error::Error + Send + Sync>> {
|
||||
use std::io::Read;
|
||||
|
||||
println!("Extracting ZIP archive on Windows: {}", zip_path.display());
|
||||
|
||||
// Create destination directory if it doesn't exist
|
||||
@@ -500,8 +498,6 @@ impl Extractor {
|
||||
zip_path: &Path,
|
||||
dest_dir: &Path,
|
||||
) -> Result<PathBuf, Box<dyn std::error::Error + Send + Sync>> {
|
||||
use std::io::Read;
|
||||
|
||||
println!("Using Rust zip crate for extraction (Windows 7+ compatibility)");
|
||||
|
||||
let file = fs::File::open(zip_path)?;
|
||||
@@ -1022,78 +1018,86 @@ impl Extractor {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn find_windows_executable_recursive(
|
||||
&self,
|
||||
dir: &Path,
|
||||
fn find_windows_executable_recursive<'a>(
|
||||
&'a self,
|
||||
dir: &'a Path,
|
||||
depth: usize,
|
||||
max_depth: usize,
|
||||
) -> Result<PathBuf, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if depth > max_depth {
|
||||
return Err("Maximum search depth reached".into());
|
||||
}
|
||||
|
||||
if let Ok(entries) = fs::read_dir(dir) {
|
||||
let mut dirs_to_search = Vec::new();
|
||||
|
||||
// First pass: look for .exe files in current directory
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file()
|
||||
&& path
|
||||
.extension()
|
||||
.is_some_and(|ext| ext.to_string_lossy().to_lowercase() == "exe")
|
||||
{
|
||||
let file_name = path
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("")
|
||||
.to_lowercase();
|
||||
|
||||
// Check if it's a browser executable
|
||||
if file_name.contains("firefox")
|
||||
|| file_name.contains("chrome")
|
||||
|| file_name.contains("chromium")
|
||||
|| file_name.contains("zen")
|
||||
|| file_name.contains("brave")
|
||||
|| file_name.contains("tor")
|
||||
|| file_name.contains("mullvad")
|
||||
|| file_name.contains("browser")
|
||||
{
|
||||
return Ok(path);
|
||||
}
|
||||
} else if path.is_dir() {
|
||||
// Collect directories for later search
|
||||
dirs_to_search.push(path);
|
||||
}
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<Output = Result<PathBuf, Box<dyn std::error::Error + Send + Sync>>>
|
||||
+ Send
|
||||
+ 'a,
|
||||
>,
|
||||
> {
|
||||
Box::pin(async move {
|
||||
if depth > max_depth {
|
||||
return Err("Maximum search depth reached".into());
|
||||
}
|
||||
|
||||
// Second pass: search subdirectories
|
||||
for subdir in dirs_to_search {
|
||||
if let Ok(result) = self
|
||||
.find_windows_executable_recursive(&subdir, depth + 1, max_depth)
|
||||
.await
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass: if no browser-specific executable found, return any .exe
|
||||
if let Ok(entries) = fs::read_dir(dir) {
|
||||
let mut dirs_to_search = Vec::new();
|
||||
|
||||
// First pass: look for .exe files in current directory
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file()
|
||||
&& path
|
||||
.extension()
|
||||
.is_some_and(|ext| ext.to_string_lossy().to_lowercase() == "exe")
|
||||
{
|
||||
return Ok(path);
|
||||
let file_name = path
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("")
|
||||
.to_lowercase();
|
||||
|
||||
// Check if it's a browser executable
|
||||
if file_name.contains("firefox")
|
||||
|| file_name.contains("chrome")
|
||||
|| file_name.contains("chromium")
|
||||
|| file_name.contains("zen")
|
||||
|| file_name.contains("brave")
|
||||
|| file_name.contains("tor")
|
||||
|| file_name.contains("mullvad")
|
||||
|| file_name.contains("browser")
|
||||
{
|
||||
return Ok(path);
|
||||
}
|
||||
} else if path.is_dir() {
|
||||
// Collect directories for later search
|
||||
dirs_to_search.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: search subdirectories
|
||||
for subdir in dirs_to_search {
|
||||
if let Ok(result) = self
|
||||
.find_windows_executable_recursive(&subdir, depth + 1, max_depth)
|
||||
.await
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass: if no browser-specific executable found, return any .exe
|
||||
if let Ok(entries) = fs::read_dir(dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_file()
|
||||
&& path
|
||||
.extension()
|
||||
.is_some_and(|ext| ext.to_string_lossy().to_lowercase() == "exe")
|
||||
{
|
||||
return Ok(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err("No executable found".into())
|
||||
Err("No executable found".into())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
||||
@@ -84,17 +84,15 @@ impl ProfileImporter {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// Primary location in AppData\Roaming
|
||||
if let Some(app_data) = self.base_dirs.data_dir() {
|
||||
let firefox_dir = app_data.join("Mozilla/Firefox/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_dir, "firefox")?);
|
||||
}
|
||||
let app_data = self.base_dirs.data_dir();
|
||||
let firefox_dir = app_data.join("Mozilla/Firefox/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_dir, "firefox")?);
|
||||
|
||||
// Also check AppData\Local for portable installations
|
||||
if let Some(local_app_data) = self.base_dirs.data_local_dir() {
|
||||
let firefox_local_dir = local_app_data.join("Mozilla/Firefox/Profiles");
|
||||
if firefox_local_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_local_dir, "firefox")?);
|
||||
}
|
||||
let local_app_data = self.base_dirs.data_local_dir();
|
||||
let firefox_local_dir = local_app_data.join("Mozilla/Firefox/Profiles");
|
||||
if firefox_local_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_local_dir, "firefox")?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,12 +127,11 @@ impl ProfileImporter {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(app_data) = self.base_dirs.data_dir() {
|
||||
// Firefox Developer Edition on Windows typically uses separate directories
|
||||
let firefox_dev_dir = app_data.join("Mozilla/Firefox Developer Edition/Profiles");
|
||||
if firefox_dev_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_dev_dir, "firefox-developer")?);
|
||||
}
|
||||
let app_data = self.base_dirs.data_dir();
|
||||
// Firefox Developer Edition on Windows typically uses separate directories
|
||||
let firefox_dev_dir = app_data.join("Mozilla/Firefox Developer Edition/Profiles");
|
||||
if firefox_dev_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&firefox_dev_dir, "firefox-developer")?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,10 +165,9 @@ impl ProfileImporter {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(local_app_data) = self.base_dirs.data_local_dir() {
|
||||
let chrome_dir = local_app_data.join("Google/Chrome/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&chrome_dir, "chromium")?);
|
||||
}
|
||||
let local_app_data = self.base_dirs.data_local_dir();
|
||||
let chrome_dir = local_app_data.join("Google/Chrome/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&chrome_dir, "chromium")?);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -198,10 +194,9 @@ impl ProfileImporter {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(local_app_data) = self.base_dirs.data_local_dir() {
|
||||
let chromium_dir = local_app_data.join("Chromium/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&chromium_dir, "chromium")?);
|
||||
}
|
||||
let local_app_data = self.base_dirs.data_local_dir();
|
||||
let chromium_dir = local_app_data.join("Chromium/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&chromium_dir, "chromium")?);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -228,10 +223,9 @@ impl ProfileImporter {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(local_app_data) = self.base_dirs.data_local_dir() {
|
||||
let brave_dir = local_app_data.join("BraveSoftware/Brave-Browser/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&brave_dir, "brave")?);
|
||||
}
|
||||
let local_app_data = self.base_dirs.data_local_dir();
|
||||
let brave_dir = local_app_data.join("BraveSoftware/Brave-Browser/User Data");
|
||||
profiles.extend(self.scan_chrome_profiles_dir(&brave_dir, "brave")?);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -264,17 +258,15 @@ impl ProfileImporter {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// Primary location in AppData\Roaming
|
||||
if let Some(app_data) = self.base_dirs.data_dir() {
|
||||
let mullvad_dir = app_data.join("MullvadBrowser/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&mullvad_dir, "mullvad-browser")?);
|
||||
}
|
||||
let app_data = self.base_dirs.data_dir();
|
||||
let mullvad_dir = app_data.join("MullvadBrowser/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&mullvad_dir, "mullvad-browser")?);
|
||||
|
||||
// Also check common installation locations
|
||||
if let Some(local_app_data) = self.base_dirs.data_local_dir() {
|
||||
let mullvad_local_dir = local_app_data.join("MullvadBrowser/Profiles");
|
||||
if mullvad_local_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&mullvad_local_dir, "mullvad-browser")?);
|
||||
}
|
||||
let local_app_data = self.base_dirs.data_local_dir();
|
||||
let mullvad_local_dir = local_app_data.join("MullvadBrowser/Profiles");
|
||||
if mullvad_local_dir.exists() {
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&mullvad_local_dir, "mullvad-browser")?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,10 +296,9 @@ impl ProfileImporter {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Some(app_data) = self.base_dirs.data_dir() {
|
||||
let zen_dir = app_data.join("Zen/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&zen_dir, "zen")?);
|
||||
}
|
||||
let app_data = self.base_dirs.data_dir();
|
||||
let zen_dir = app_data.join("Zen/Profiles");
|
||||
profiles.extend(self.scan_firefox_profiles_dir(&zen_dir, "zen")?);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -378,17 +369,16 @@ impl ProfileImporter {
|
||||
}
|
||||
|
||||
// Also check AppData directories if available
|
||||
if let Some(app_data) = self.base_dirs.data_dir() {
|
||||
let tor_app_data =
|
||||
app_data.join("TorBrowser/Browser/TorBrowser/Data/Browser/profile.default");
|
||||
if tor_app_data.exists() {
|
||||
profiles.push(DetectedProfile {
|
||||
browser: "tor-browser".to_string(),
|
||||
name: "TOR Browser - AppData Profile".to_string(),
|
||||
path: tor_app_data.to_string_lossy().to_string(),
|
||||
description: "TOR Browser profile from AppData".to_string(),
|
||||
});
|
||||
}
|
||||
let app_data = self.base_dirs.data_dir();
|
||||
let tor_app_data =
|
||||
app_data.join("TorBrowser/Browser/TorBrowser/Data/Browser/profile.default");
|
||||
if tor_app_data.exists() {
|
||||
profiles.push(DetectedProfile {
|
||||
browser: "tor-browser".to_string(),
|
||||
name: "TOR Browser - AppData Profile".to_string(),
|
||||
path: tor_app_data.to_string_lossy().to_string(),
|
||||
description: "TOR Browser profile from AppData".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user