Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
args: '--target x86_64-apple-darwin'
- platform: 'ubuntu-22.04'
args: ''
- platform: 'windows-latest'
args: ''

runs-on: ${{ matrix.platform }}
steps:
Expand Down
3 changes: 3 additions & 0 deletions src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
{
"path": "/etc/hosts"
},
{
"path": "C:\\Windows\\System32\\drivers\\etc\\hosts"
},
{
"path": "$APPDATA/*"
},
Expand Down
90 changes: 84 additions & 6 deletions src-tauri/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,38 @@ use tokio::fs;

use tauri::AppHandle;

const WINDOWS_HOSTS_PATH: &str = r"C:\Windows\System32\drivers\etc\hosts";
const LINUX_HOSTS_PATH: &str = "/etc/hosts";
const MACOS_HOSTS_PATH: &str = "/etc/hosts";

#[command]
pub fn get_hosts_path() -> String {
let platform = tauri_plugin_os::platform();
if platform == "windows" {
WINDOWS_HOSTS_PATH.to_string()
} else if platform == "linux" {
LINUX_HOSTS_PATH.to_string()
} else {
MACOS_HOSTS_PATH.to_string()
}
}

#[command]
pub async fn read_system_hosts() -> Result<String, String> {
let platform = tauri_plugin_os::platform();
let path = if platform == "windows" {
WINDOWS_HOSTS_PATH
} else if platform == "linux" {
LINUX_HOSTS_PATH
} else {
MACOS_HOSTS_PATH
};

tokio::fs::read_to_string(path)
.await
.map_err(|e| e.to_string())
}

#[command]
pub async fn write_file(
app_handle: tauri::AppHandle,
Expand Down Expand Up @@ -56,27 +88,73 @@ pub async fn write_system_hosts(app_handle: &AppHandle, content: String) -> Resu
if platform == "linux" {
return update_hosts_file_sudo(final_content).await;
} else if platform == "macos" {
return update_hosts_file(final_content).await;
return update_hosts_file_macos(final_content).await;
} else if platform == "windows" {
return update_hosts_file_windows(final_content).await;
} else {
return Err(format!("Unsupported platform: {}", platform));
}
}

pub async fn update_hosts_file(content: String) -> Result<(), String> {
std::fs::write("/etc/hosts", &content).map_err(|e| e.to_string())?;
pub async fn update_hosts_file_macos(content: String) -> Result<(), String> {
std::fs::write(MACOS_HOSTS_PATH, &content).map_err(|e| e.to_string())?;
Ok(())
}

pub async fn update_hosts_file_windows(content: String) -> Result<(), String> {
std::fs::write(WINDOWS_HOSTS_PATH, &content).map_err(|e| {
if e.kind() == std::io::ErrorKind::PermissionDenied {
return runas_elevation_windows(content);
}
e.to_string()
})?;

Ok(())
}

fn runas_elevation_windows(content: String) -> String {
let temp_path = std::env::temp_dir().join("hedit_hosts_update");
if let Err(e) = std::fs::write(&temp_path, &content) {
return format!("Failed to write temp file: {}", e);
}

let temp_path_str = temp_path.to_string_lossy();
let hosts_path = WINDOWS_HOSTS_PATH;

let output = Command::new("powershell")
.args([
"-Command",
&format!(
"Start-Process -FilePath 'cmd' -ArgumentList '/c copy /Y \"{}\" \"{}\"' -Verb RunAs -Wait",
temp_path_str, hosts_path
),
])
.output();

let _ = std::fs::remove_file(&temp_path);

match output {
Ok(output) => {
if output.status.success() {
String::new()
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
format!("Elevation failed: {} {}", stderr, stdout)
}
}
Err(e) => format!("Failed to run elevation: {}", e),
}
}

pub async fn update_hosts_file_sudo(content: String) -> Result<(), String> {
// Write content to temporary file first
let temp_path = "/tmp/hedit_hosts_update";
std::fs::write(temp_path, &content).map_err(|e| e.to_string())?;

// Use pkexec with cp to copy temp file to /etc/hosts
let output = Command::new("pkexec")
.arg("cp")
.arg(temp_path)
.arg("/etc/hosts")
.arg(LINUX_HOSTS_PATH)
.output()
.map_err(|e| e.to_string())?;

Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ pub fn run() {
license::activate,
license::get_build_date_command,
files::write_file,
files::get_hosts_path,
files::read_system_hosts,
remote_hosts::fetch_remote_hosts_file,
sync_remote_hosts::trigger_manual_sync,
telemetry::send_telemetry_event,
Expand Down
12 changes: 12 additions & 0 deletions src-tauri/src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ pub fn get_menu<R: Runtime>(app_handle: &AppHandle<R>) -> tauri::Result<Menu<R>>
&[
#[cfg(target_os = "macos")]
&PredefinedMenuItem::fullscreen(app_handle, None)?,
#[cfg(not(target_os = "macos"))]
&MenuItemBuilder::with_id("fullscreen".to_string(), "Fullscreen")
.accelerator("F11")
.build(app_handle)?,
#[cfg(target_os = "macos")]
&PredefinedMenuItem::separator(app_handle)?,
&MenuItemBuilder::with_id("zoom_reset".to_string(), "Reset Zoom")
Expand Down Expand Up @@ -195,6 +199,14 @@ pub fn handle_menu_event(app_handle: &tauri::AppHandle, event: &MenuEvent) {
eprintln!("Failed to emit zoom_out event: {}", e);
}
}
"fullscreen" => {
if let Some(window) = app_handle.get_webview_window("main") {
let is_fullscreen = window.is_fullscreen().unwrap_or(false);
if let Err(e) = window.set_fullscreen(!is_fullscreen) {
eprintln!("Failed to toggle fullscreen: {}", e);
}
}
}
"open_feedback" => {
if let Err(e) = app_handle.opener().open_url(FEEDBACK_URL, None::<&str>) {
eprintln!("Failed to open feedback URL: {}", e);
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"dmg",
"deb",
"appimage",
"rpm"
"rpm",
"nsis"
],
"icon": [
"icons/32x32.png",
Expand Down
4 changes: 2 additions & 2 deletions src/stores/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
exists,
mkdir,
readTextFile,
writeTextFile,
remove,
writeTextFile,
} from '@tauri-apps/plugin-fs'
import { load } from '@tauri-apps/plugin-store'
import { reactive } from 'vue'
Expand Down Expand Up @@ -132,7 +132,7 @@ export const hostsStore = reactive({
async init() {
await this.load()
if (this.files.length === 0) {
const content = await readTextFile('/etc/hosts')
const content = await invoke<string>('read_system_hosts')
await this.create('Original File', content, true)
}
},
Expand Down