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

105
keyring-rs/src/main.rs Executable file
View File

@@ -0,0 +1,105 @@
#!/usr/bin/env runrs
//! ```cargo
//! [dependencies]
//! clap = { version = "4.5.48", features = ["derive"] }
//! keyring = { version = "3.6.3", features = ["apple-native"] }
//! rust_util = "0.6.50"
//! pinentry-util = "0.1.1"
//! serde = { version = "1.0.228", features = ["derive"] }
//! serde_json = "1.0.145"
//! zeroizing-alloc = "0.1.0"
//! ```
use clap::{Args, Parser, Subcommand};
use keyring::Entry;
use rust_util::{opt_result, success, XResult};
use std::collections::BTreeMap;
use zeroizing_alloc::ZeroAlloc;
#[global_allocator]
static ALLOC: ZeroAlloc<std::alloc::System> = ZeroAlloc(std::alloc::System);
#[derive(Debug, Parser)]
#[command(name = "keyring-rs", bin_name = "keyring.rs")]
#[command(about = "Keyring util", long_about = None)]
struct ConnectArgs {
#[command(subcommand)]
command: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
/// Connect
#[command(short_flag = 's')]
Set(CmdSet),
/// Disconnect
#[command(short_flag = 'g')]
Get(CmdGet),
}
#[derive(Debug, Args)]
pub struct CmdSet {
/// Service
#[arg(long, short = 'S')]
pub service: String,
/// User
#[arg(long, short = 'U')]
pub user: String,
/// Password
#[arg(long, short = 'P')]
pub password: Option<String>,
}
#[derive(Debug, Args)]
pub struct CmdGet {
/// Service
#[arg(long, short = 'S')]
pub service: String,
/// User
#[arg(long, short = 'U')]
pub user: String,
// JSON output
#[arg(long)]
pub json: bool,
}
fn main() -> XResult<()> {
let args = ConnectArgs::parse();
match args.command {
Commands::Set(cmd_set) => {
let entry = Entry::new(&cmd_set.service, &cmd_set.user)?;
let password = match cmd_set.password {
Some(password) => password,
None => opt_result!(
pinentry_util::read_pin(Some(""), Some("")),
"Read password failed: {}"
)
.get_pin()
.to_string(),
};
entry.set_password(&password)?;
success!("Set password successfully");
}
Commands::Get(cmd_get) => {
let entry = Entry::new(&cmd_get.service, &cmd_get.user)?;
let password = entry.get_password()?;
if cmd_get.json {
let mut result = BTreeMap::new();
result.insert("service", cmd_get.service.to_string());
result.insert("user", cmd_get.user.to_string());
result.insert("password", password.to_string());
println!("{}", serde_json::to_string_pretty(&result)?);
} else {
success!("Got password: {}", password);
}
}
}
Ok(())
}
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20251019T145514+08:00.MEUCIQDgJgYEeTPSuknNc6eR
// Ms8aT4vjloKezJUblkBPKiSDFQIgDfLdrgc4GgkjyKGe4YcjqSxTutaSAJ/KIitSvzpjg+U=