feat: update connect-rs, add keyring-rs

This commit is contained in:
2025-10-19 15:26:12 +08:00
parent 2ea46e6df2
commit 1b5db69a73
9 changed files with 1222 additions and 24 deletions

View File

@@ -3,12 +3,22 @@
//! ```cargo
//! [dependencies]
//! clap = { version = "4.5.48", features = ["derive"] }
//! reqwest = "0.12.23"
//! keyring = { version = "3.6.3", features = ["apple-native"] }
//! reqwest = { version = "0.12.23", features = ["blocking"] }
//! rust_util = "0.6.50"
//! serde_json = "1.0.145"
//! rust-crypto-hatter-fork = "0.2"
//! ```
use clap::{Args, Parser, Subcommand};
use rust_util::{failure, success, util_cmd};
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use keyring::Entry;
use rust_util::{
failure, information, opt_result, simple_error, success, util_cmd, util_file, XResult,
};
use serde_json::Value;
use std::fs;
use std::process::Command;
#[derive(Debug, Parser)]
@@ -47,7 +57,7 @@ fn main() {
match args.command {
Commands::Connect(cmd) => {
if cmd.update {
update_proxy();
update_pac_file_ignore_error();
}
turn_proxy_off();
run_command(
@@ -60,15 +70,48 @@ fn main() {
turn_proxy_off();
}
Commands::Update => {
update_proxy();
update_pac_file_ignore_error();
}
}
}
fn update_proxy() {
// TODO ...
// check file exists and digest: __proxy__.pac
// &digest=1 // get digest
fn update_pac_file_ignore_error() {
match update_pac_file() {
Ok(_) => success!("Update proxy successfully"),
Err(error) => failure!("Update proxy failed: {}", error),
}
}
fn update_pac_file() -> XResult<()> {
let digest = get_pac_digest()?;
let pac_file = "__proxy__.pac";
let pac_file_content = util_file::read_file_content(pac_file)?;
let mut sha256 = Sha256::new();
sha256.input(pac_file_content.as_bytes());
let pac_file_digest = format!("sha256-{}", sha256.result_str());
if digest == pac_file_digest {
success!("Pac file digest matches.");
return Ok(());
}
information!(
"Pac file digest mismatch, \n - remote: {}, \n - local : {}",
digest,
pac_file_digest
);
let pac_content = get_pac_content()?;
opt_result!(
fs::write(pac_file, pac_content),
"Write file {}, failed: {}",
pac_file
);
success!("Pac file updated successfully.");
Ok(())
}
fn turn_proxy_off() {
@@ -101,5 +144,75 @@ fn run_command(program: &str, args: &[&str], message: &str) {
}
}
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20251013T231311+08:00.MEYCIQCuJnrPEuafEEzqTyyW
// TkvJvXUUg9c2+OiVtcr1owBkEwIhALCq8vFJyJTb2ftplPN1Q3PzRZFNkfdWovo8DMiyaEc5
fn get_pac_content() -> XResult<String> {
let auth_token = get_pac_auth_token()?;
let url = format!(
"https://hatter.ink/pac/get_pac.action?__auth_token={}",
auth_token
);
let pac_content_response =
opt_result!(reqwest::blocking::get(&url), "Get pac content failed: {}");
if pac_content_response.status().as_u16() != 200 {
return simple_error!(
"Get pac content HTTP status error: {}",
pac_content_response.status().as_u16()
);
}
let pac_content_text = opt_result!(
pac_content_response.text(),
"Get pac digest response failed: {}"
);
Ok(pac_content_text)
}
fn get_pac_digest() -> XResult<String> {
let auth_token = get_pac_auth_token()?;
let url = format!(
"https://hatter.ink/pac/get_pac.action?digest=1&__auth_token={}",
auth_token
);
let pac_digest_response =
opt_result!(reqwest::blocking::get(&url), "Get pac digest failed: {}");
if pac_digest_response.status().as_u16() != 200 {
return simple_error!(
"Get pac digest HTTP status error: {}",
pac_digest_response.status().as_u16()
);
}
let pac_digest_text = opt_result!(
pac_digest_response.text(),
"Get pac digest response failed: {}"
);
let pac_digest_value: Value = opt_result!(
serde_json::from_str(&pac_digest_text),
"Parse pac digest failed: {}"
);
if let Some(data) = pac_digest_value.get("data") {
if let Some(digest) = data.get("digest") {
match digest {
Value::String(digest) => Ok(digest.to_string()),
_ => simple_error!("Cannot get pac digest data.digest not string"),
}
} else {
simple_error!("Cannot get pac digest data.digest")
}
} else {
simple_error!("Cannot get pac digest data")
}
}
fn get_pac_auth_token() -> XResult<String> {
let entry = opt_result!(
Entry::new("hatter.ink", "get_pac_auth_token"),
"New entry failed: {}"
);
Ok(opt_result!(
entry.get_password(),
"get password from keyring failed: {}"
))
}
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20251019T152450+08:00.MEUCIQDzZTpk54DYe9u/FrsQ
// 7OPRmEHLjUelAZUevqPHa7nFEgIgf/Xw73PwCE3miSNXmXawWh6CsrGfk1urRW0zpZOH30M=