chrome install support

This commit is contained in:
Robin Appelman 2025-10-12 13:58:19 +02:00
commit 41049a94d4
2 changed files with 117 additions and 27 deletions

81
src/install.rs Normal file
View file

@ -0,0 +1,81 @@
use std::path::PathBuf;
use std::str::FromStr;
pub enum Browser {
Firefox,
Chrome,
}
impl Browser {
pub fn manifest_path(&self, name: &str) -> PathBuf {
match self {
Browser::Firefox => firefox_user_manifest(name),
Browser::Chrome => chrome_user_manifest(name),
}
}
}
impl FromStr for Browser {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"firefox" => Ok(Browser::Firefox),
"chomrium" | "chrome" => Ok(Browser::Chrome),
_ => Err("unsupported browser"),
}
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn unix_home_dir() -> PathBuf {
std::env::var_os("HOME")
.map(PathBuf::from)
.expect("HOME not set")
}
fn chrome_user_manifest(name: &str) -> PathBuf {
#[cfg(target_os = "macos")]
{
unix_home_dir()
.join("Library/Application Support/Google/Chrome/NativeMessagingHosts")
.join(format!("{name}.json"))
}
#[cfg(target_os = "linux")]
{
unix_home_dir()
.join(".config/google-chrome/NativeMessagingHosts")
.join(format!("{name}.json"))
}
#[cfg(target_os = "windows")]
{
std::env::var_os("LOCALAPPDATA")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from(r"C:\Users\Default\AppData\Local"))
.join("NativeMessagingHosts")
.join(format!("{name}.json"))
}
}
fn firefox_user_manifest(name: &str) -> PathBuf {
#[cfg(target_os = "macos")]
{
unix_home_dir()
.join("Library/Application Support/Mozilla/NativeMessagingHosts")
.join(format!("{name}.json"))
}
#[cfg(target_os = "linux")]
{
unix_home_dir()
.join(".mozilla/native-messaging-hosts")
.join(format!("{name}.json"))
}
#[cfg(target_os = "windows")]
{
std::env::var_os("APPDATA")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from(r"C:\Users\Default\AppData\Roaming"))
.join("Mozilla\\NativeMessagingHosts")
.join(format!("{name}.json"))
}
}

View file

@ -1,29 +1,30 @@
mod install;
use main_error::MainResult; use main_error::MainResult;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::env::{args, current_exe, home_dir}; use std::env::{args, current_exe};
use std::fs::write; use std::fs::write;
use std::io::{stdin, stdout, Error as IoError, ErrorKind, IsTerminal, Read, Write}; use std::io::{Error as IoError, ErrorKind, IsTerminal, Read, Write, stdin, stdout};
use std::str::FromStr;
use crate::install::Browser;
fn main() -> MainResult { fn main() -> MainResult {
let mut args = args(); let mut args = args();
if let Some(arg) = args.nth(1) { if let Some(arg) = args.nth(1) {
match arg.as_str() { match arg.as_str() {
"--help" => { "--help" | "help" => {
help(); help();
return Ok(()); return Ok(());
} }
"--generate-manifest" => { "generate-manifest" => {
stdout().write_all(generate_manifest()?.as_bytes())?; stdout().write_all(generate_manifest()?.as_bytes())?;
return Ok(()); return Ok(());
} }
"--install-manifest" => { "install-manifest" => {
let home_dir = home_dir().expect("can't determine home directory"); let browser = Browser::from_str(&args.next().unwrap_or_default())?;
write( write(
format!( browser.manifest_path("originfox"),
"{}/.mozilla/native-messaging-hosts/originfox.json",
home_dir.display()
),
generate_manifest()?, generate_manifest()?,
)?; )?;
return Ok(()); return Ok(());
@ -57,17 +58,18 @@ fn help() {
"{} {} {}", "{} {} {}",
"Usage:".bright_yellow().bold(), "Usage:".bright_yellow().bold(),
"originfox".blue().bold(), "originfox".blue().bold(),
"[OPTION]".green() "[COMMAND]".green()
); );
println!(); println!();
println!("{}", "Options:".bright_yellow().bold()); println!("{}", "Commands:".bright_yellow().bold());
println!( println!(
" {} Generate and print a native messaging manifest", " {} Generate and print a native messaging manifest",
"--generate-manifest".blue().bold() "generate-manifest".blue().bold()
); );
println!( println!(
" {} Generate and install a native messaging manifest", " {} {} Generate and install a native messaging manifest",
"--install-manifest".blue().bold() "install-manifest".blue().bold(),
"[BROWSER]".green(),
); );
} }
@ -122,17 +124,24 @@ fn encode<T: Serialize>(message: T) -> Result<Vec<u8>, serde_json::Error> {
Ok(buff) Ok(buff)
} }
#[derive(Serialize)]
struct Manifest<'a> {
name: &'a str,
description: &'a str,
path: &'a str,
#[serde(rename = "type")]
ty: &'a str,
allowed_extensions: &'a [&'a str],
}
fn generate_manifest() -> Result<String, IoError> { fn generate_manifest() -> Result<String, IoError> {
let self_path = current_exe()?; let self_path = current_exe()?;
let self_path = self_path.to_str().ok_or(ErrorKind::InvalidFilename)?; let path = self_path.to_str().ok_or(ErrorKind::InvalidInput)?;
Ok(format!( Ok(serde_json::to_string_pretty(&Manifest {
r#"{{ name: "originfox",
"name": "originfox", description: "Save download origin data to extended attributes",
"description": "Save download origin data to extended attributes", path,
"path": "{}", ty: "stdio",
"type": "stdio", allowed_extensions: &["originfox@icewind.nl"],
"allowed_extensions": [ "originfox@icewind.nl" ] }).unwrap())
}}"#,
self_path
))
} }