summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2025-11-22 20:16:14 +0800
committer魏曹先生 <1992414357@qq.com>2025-11-22 20:16:14 +0800
commit97089d19a4b339a622d78e48a41f1d67273752fd (patch)
treec149fb23c9d6ea6b4c54ad048891fc0f323ea345 /src
parent34abfcdc8e148c047ebb2e06539036e514df7046 (diff)
Add account key generation and public key export features
- Add `--keygen` flag to `account add` for automatic ED25519 key generation - Add `account genpub` command to export public keys - Update help documentation in both English and Chinese - Extend shell completion for new commands - Add error handling for OpenSSL operations
Diffstat (limited to 'src')
-rw-r--r--src/bin/jv.rs101
1 files changed, 100 insertions, 1 deletions
diff --git a/src/bin/jv.rs b/src/bin/jv.rs
index 0057cf9..4245e6a 100644
--- a/src/bin/jv.rs
+++ b/src/bin/jv.rs
@@ -69,7 +69,7 @@ use just_enough_vcs_cli::{
},
};
use rust_i18n::{set_locale, t};
-use tokio::{fs, net::TcpSocket, time::Instant};
+use tokio::{fs, net::TcpSocket, process::Command, time::Instant};
// Import i18n files
rust_i18n::i18n!("locales", fallback = "en");
@@ -227,6 +227,10 @@ enum AccountManage {
/// Move private key file to account
#[command(alias = "mvkey", alias = "mvk", alias = "movekey")]
MoveKey(MoveKeyToAccountArgs),
+
+ /// Output public key file to specified directory
+ #[command(alias = "genpub")]
+ GeneratePublicKey(GeneratePublicKeyArgs),
}
#[derive(Subcommand, Debug)]
@@ -377,6 +381,10 @@ struct AccountAddArgs {
/// Account name
account_name: String,
+
+ /// Auto generate ED25519 private key
+ #[arg(short = 'K', long = "keygen")]
+ keygen: bool,
}
#[derive(Parser, Debug)]
@@ -423,6 +431,19 @@ struct MoveKeyToAccountArgs {
key_path: PathBuf,
}
+#[derive(Parser, Debug)]
+struct GeneratePublicKeyArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+
+ /// Account name
+ account_name: String,
+
+ /// Private key file path
+ output_dir: Option<PathBuf>,
+}
+
#[derive(Parser, Debug, Clone)]
struct TrackFileArgs {
/// Show help information
@@ -736,6 +757,13 @@ async fn main() {
}
jv_account_move_key(user_dir, move_key_to_account_args).await;
}
+ AccountManage::GeneratePublicKey(generate_public_key_args) => {
+ if generate_public_key_args.help {
+ println!("{}", md(t!("jv.account")));
+ return;
+ }
+ jv_account_generate_pub_key(user_dir, generate_public_key_args).await;
+ }
}
}
JustEnoughVcsWorkspaceCommand::Create(create_workspace_args) => {
@@ -2248,6 +2276,40 @@ async fn jv_account_add(user_dir: UserDirectory, args: AccountAddArgs) {
}
Err(_) => {
eprintln!("{}", t!("jv.fail.account.add", account = args.account_name));
+ return;
+ }
+ }
+ if args.keygen {
+ let output_path = current_local_path().unwrap().join("tempkey.pem");
+
+ match Command::new("openssl")
+ .args([
+ "genpkey",
+ "-algorithm",
+ "ed25519",
+ "-out",
+ &output_path.to_string_lossy(),
+ ])
+ .status()
+ .await
+ {
+ Ok(status) if status.success() => {
+ jv_account_move_key(
+ user_dir,
+ MoveKeyToAccountArgs {
+ help: false,
+ account_name: args.account_name,
+ key_path: output_path,
+ },
+ )
+ .await
+ }
+ Ok(_) => {
+ eprintln!("{}", t!("jv.fail.account.keygen"));
+ }
+ Err(_) => {
+ eprintln!("{}", t!("jv.fail.account.keygen_exec"));
+ }
}
}
}
@@ -2373,6 +2435,43 @@ async fn jv_account_move_key(user_dir: UserDirectory, args: MoveKeyToAccountArgs
}
}
+async fn jv_account_generate_pub_key(user_dir: UserDirectory, args: GeneratePublicKeyArgs) {
+ let private_key_path = user_dir.account_private_key_path(&args.account_name);
+ let target_path = args
+ .output_dir
+ .unwrap_or(current_dir().unwrap())
+ .join(format!("{}.pem", args.account_name));
+
+ match Command::new("openssl")
+ .args([
+ "pkey",
+ "-in",
+ &private_key_path.to_string_lossy(),
+ "-pubout",
+ "-out",
+ &target_path.to_string_lossy(),
+ ])
+ .status()
+ .await
+ {
+ Ok(status) if status.success() => {
+ println!(
+ "{}",
+ t!(
+ "jv.success.account.generate_pub_key",
+ export = target_path.display()
+ )
+ );
+ }
+ Ok(_) => {
+ eprintln!("{}", t!("jv.fail.account.keygen"));
+ }
+ Err(_) => {
+ eprintln!("{}", t!("jv.fail.account.keygen_exec"));
+ }
+ }
+}
+
async fn jv_update(_update_file_args: UpdateArgs) {
let local_config = match precheck().await {
Some(config) => config,