mirror of
https://codeberg.org/icewind/originfox.git
synced 2026-06-03 18:24:07 +02:00
initial version
This commit is contained in:
parent
907eab9601
commit
b6ac4f9f4b
5 changed files with 375 additions and 5 deletions
183
Cargo.lock
generated
183
Cargo.lock
generated
|
|
@ -2,6 +2,187 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "main_error"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "originfox"
|
name = "originfox"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"main_error",
|
||||||
|
"owo-colors",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "4.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.145"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.61.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xattr"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rustix",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
[package]
|
[package]
|
||||||
name = "originfox"
|
name = "originfox"
|
||||||
version = "0.1.0"
|
description = "Save download origin data to extended attributes"
|
||||||
|
version = "1.0.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = "1.0.145"
|
||||||
|
main_error = "0.1.2"
|
||||||
|
xattr = "1.6.1"
|
||||||
|
owo-colors = "4.2.3"
|
||||||
29
addon/background.js
Normal file
29
addon/background.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
function onResponse(response) {
|
||||||
|
if (!response.success) {
|
||||||
|
console.error("Error setting attributes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
console.log(`Error: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChanged(delta) {
|
||||||
|
if (delta.state && delta.state.current === "complete") {
|
||||||
|
browser.downloads
|
||||||
|
.search({
|
||||||
|
id: delta.id,
|
||||||
|
}).then(downloads => {
|
||||||
|
let download = downloads[0];
|
||||||
|
browser.runtime.sendNativeMessage("originfox", {
|
||||||
|
path: download.filename,
|
||||||
|
origin: download.url,
|
||||||
|
referrer: download.referrer,
|
||||||
|
}).then(onResponse, onError);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.downloads.onChanged.addListener(handleChanged);
|
||||||
19
addon/manifest.json
Normal file
19
addon/manifest.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"description": "Save download origin data to extended attributes",
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "originfox",
|
||||||
|
"version": "1.0",
|
||||||
|
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "originfox@icewind.nl",
|
||||||
|
"strict_min_version": "50.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": ["nativeMessaging", "downloads"]
|
||||||
|
}
|
||||||
139
src/main.rs
139
src/main.rs
|
|
@ -1,3 +1,138 @@
|
||||||
fn main() {
|
use main_error::MainResult;
|
||||||
println!("Hello, world!");
|
use owo_colors::OwoColorize;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::env::{args, current_exe, home_dir};
|
||||||
|
use std::fs::write;
|
||||||
|
use std::io::{stdin, stdout, Error as IoError, ErrorKind, IsTerminal, Read, Write};
|
||||||
|
|
||||||
|
fn main() -> MainResult {
|
||||||
|
let mut args = args();
|
||||||
|
if let Some(arg) = args.nth(1) {
|
||||||
|
match arg.as_str() {
|
||||||
|
"--help" => {
|
||||||
|
help();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
"--generate-manifest" => {
|
||||||
|
stdout().write_all(generate_manifest()?.as_bytes())?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
"--install-manifest" => {
|
||||||
|
let home_dir = home_dir().expect("can't determine home directory");
|
||||||
|
write(
|
||||||
|
format!(
|
||||||
|
"{}/.mozilla/native-messaging-hosts/originfox.json",
|
||||||
|
home_dir.display()
|
||||||
|
),
|
||||||
|
generate_manifest()?,
|
||||||
|
)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = stdin();
|
||||||
|
|
||||||
|
if input.is_terminal() {
|
||||||
|
help();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut input = input.lock();
|
||||||
|
let packet_bytes = read_packet_bytes(&mut input)?;
|
||||||
|
let packet: Packet = serde_json::from_slice(&packet_bytes)?;
|
||||||
|
|
||||||
|
let success = set_attr(packet).is_ok();
|
||||||
|
|
||||||
|
let response = encode(&Response { success })?;
|
||||||
|
|
||||||
|
stdout().write_all(&response)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help() {
|
||||||
|
println!(
|
||||||
|
"{} {} {}",
|
||||||
|
"Usage:".bright_yellow().bold(),
|
||||||
|
"originfox".blue().bold(),
|
||||||
|
"[OPTION]".green()
|
||||||
|
);
|
||||||
|
println!();
|
||||||
|
println!("{}", "Options:".bright_yellow().bold());
|
||||||
|
println!(
|
||||||
|
" {} Generate and print a native messaging manifest",
|
||||||
|
"--generate-manifest".blue().bold()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" {} Generate and install a native messaging manifest",
|
||||||
|
"--install-manifest".blue().bold()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Packet {
|
||||||
|
path: String,
|
||||||
|
origin: String,
|
||||||
|
referrer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct Response {
|
||||||
|
success: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_attr(packet: Packet) -> Result<(), IoError> {
|
||||||
|
xattr::set(
|
||||||
|
&packet.path,
|
||||||
|
"user.xdg.origin.url",
|
||||||
|
packet.origin.as_bytes(),
|
||||||
|
)?;
|
||||||
|
xattr::set(
|
||||||
|
&packet.path,
|
||||||
|
"user.xdg.referrer.url",
|
||||||
|
packet.referrer.as_bytes(),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a packet consisting of an u32 size followed by the data
|
||||||
|
fn read_packet_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>, IoError> {
|
||||||
|
let mut size_bits = [0u8; 4];
|
||||||
|
reader.read_exact(&mut size_bits)?;
|
||||||
|
let size = u32::from_ne_bytes(size_bits);
|
||||||
|
|
||||||
|
if size > 1024 * 1024 {
|
||||||
|
return Err(ErrorKind::FileTooLarge.into());
|
||||||
|
}
|
||||||
|
let mut buff = vec![0; size as usize];
|
||||||
|
reader.read_exact(&mut buff)?;
|
||||||
|
Ok(buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a packet consisting of an u32 size followed by the data
|
||||||
|
fn encode<T: Serialize>(message: T) -> Result<Vec<u8>, serde_json::Error> {
|
||||||
|
let mut buff = Vec::with_capacity(128);
|
||||||
|
|
||||||
|
buff.resize(4, 0);
|
||||||
|
serde_json::to_writer(&mut buff, &message)?;
|
||||||
|
let len = buff.len() - 4;
|
||||||
|
buff[0..4].copy_from_slice(&(len as u32).to_ne_bytes());
|
||||||
|
Ok(buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_manifest() -> Result<String, IoError> {
|
||||||
|
let self_path = current_exe()?;
|
||||||
|
let self_path = self_path.to_str().ok_or(ErrorKind::InvalidFilename)?;
|
||||||
|
Ok(format!(
|
||||||
|
r#"{{
|
||||||
|
"name": "originfox",
|
||||||
|
"description": "Save download origin data to extended attributes",
|
||||||
|
"path": "{}",
|
||||||
|
"type": "stdio",
|
||||||
|
"allowed_extensions": [ "originfox@icewind.nl" ]
|
||||||
|
}}"#,
|
||||||
|
self_path
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue