diff options
| -rw-r--r-- | locales/help_docs/en.yml | 16 | ||||
| -rw-r--r-- | locales/help_docs/zh-CN.yml | 16 | ||||
| -rw-r--r--[-rwxr-xr-x] | scripts/completion_jv.sh | 15 | ||||
| -rw-r--r-- | src/bin/jv.rs | 101 |
4 files changed, 142 insertions, 6 deletions
diff --git a/locales/help_docs/en.yml b/locales/help_docs/en.yml index dde2672..f46b6ab 100644 --- a/locales/help_docs/en.yml +++ b/locales/help_docs/en.yml @@ -196,12 +196,13 @@ jv: update - Download latest information [REMOTE] **ACCOUNTS**: - account [list|as|add|remove|movekey] + account [list|as|add|remove|movekey|genpub] list - List accounts as <ACCOUNT_NAME> - Switch account in workspace add <ACCOUNT_NAME> - Add account to this computer remove <ACCOUNT_NAME> - Remove account from computer movekey <NAME> <KEY_FILE> - Move private key file to specified account + genpub <NAME> <DIRECTORY> - Output public key file to specified directory **SHEETS**: sheet [list|use|exit|make|drop|align] @@ -246,6 +247,10 @@ jv: jv account add <ACCOUNT_NAME> - Add an account to this computer jv account remove <ACCOUNT_NAME> - Delete this account jv account movekey <ACCOUNT_NAME> <PRIVATE_KEY_FILE> - Move private key to specified account + jv account genpub <ACCOUNT_NAME> <OUTPUT_DIR> - Output public key to specified directory, leave empty for current directory + + **Tip**: Use jv account add <ACCOUNT_NAME> --keygen to automatically generate ED25519 private key for your account + **Note**: Both `--keygen` and `genpub` require your computer to be able to directly call OpenSSL command-line tools Accounts are identity identifiers on the local computer, each account can be associated with different private keys. You need to set up accounts before interacting with upstream vaults. @@ -484,7 +489,15 @@ jv: remove: Failed to remove account `%{account}`, please check if the account exists. list: Failed to get account list! not_found: Cannot find account `%{account}`! + no_key_registered: Account `%{account}` has no registered private key! as: Failed to set current account, please ensure the current sheet has been exited + keygen: Failed to generate private key! Please try generating private key manually + keygen_exec: | + Failed to run OpenSSL! + Please check if OpenSSL is installed on your computer + generate_pub_key: | + Failed to generate public key! + Please check if OpenSSL is installed, or manually generate the public key init_create_dir_not_empty: | The current directory is not empty! @@ -555,6 +568,7 @@ jv: status_has_key: (REGISTERED) move_key: Successfully moved the private key to the account directory! + generate_pub_key: Successfully generated public key at `%{export}`, please give it to the upstream vault administrator! create: Successfully created local workspace! init: Successfully created workspace here! unstain: | diff --git a/locales/help_docs/zh-CN.yml b/locales/help_docs/zh-CN.yml index fd6bb64..4a7daf4 100644 --- a/locales/help_docs/zh-CN.yml +++ b/locales/help_docs/zh-CN.yml @@ -185,7 +185,7 @@ jv: update - 同步最新的信息 [远程] **账户**: - account [list|as|add|remove|movekey] + account [list|as|add|remove|movekey|genpub] list - 列出所有账户 as <账户名称> - 设置该工作区使用的账户 @@ -193,6 +193,7 @@ jv: remove <账户名称> - 从计算机删除账户 movekey <账户> <私钥> - 移动私钥文件到指定账户 + genpub <账户> <目录> - 输出公钥文件到指定目录 **表操作**: sheet [list|use|exit|make|drop|align] @@ -236,6 +237,10 @@ jv: jv account add <账户名称> - 为当前计算机添加账户 jv account remove <账户名称> - 删除该账户 jv account movekey <账户名称> <私钥文件> - 移动私钥到指定账户 + jv account genpub <账户名称> <输出目录> - 将公钥输出至某个目录,留空为当前 + + **提示**:使用 jv account add <账户名称> --keygen 可以自动为您的账户生成 ED25519 私钥 + **注意**:`--keygen` 和 `genpub` 都需要您的计算机能够直接调用 OpenSSL 命令行工具 账户是本地计算机上的身份标识,每个账户可以关联不同的私钥 您需要先设置账户才能与上游库进行交互 @@ -486,7 +491,15 @@ jv: list: 获取账户列表失败! move_key: 将该私钥移动至账户目录失败! not_found: 无法找到账户 `%{account}`! + no_key_registered: 账户 `%{account}` 没有注册私钥! as: 设置当前账户失败,请确保当前表已退出 + keygen: 生成私钥失败!请尝试手动生成私钥 + keygen_exec: | + 运行 OpenSSL 失败! + 请检查您的计算机中是否安装 OpenSSL + generate_pub_key: | + 生成公钥失败! + 请检查 OpenSSL 是否安装,或手动生成公钥 init_create_dir_not_empty: | 当前目录并不是空的! @@ -561,6 +574,7 @@ jv: status_has_key: (已注册私钥) move_key: 成功将该私钥移动至账户目录! + generate_pub_key: 成功在 `%{export}` 生成公钥,请将它交给上游库管理员! create: 成功创建本地工作区! init: 成功在此处创建工作区! unstain: | diff --git a/scripts/completion_jv.sh b/scripts/completion_jv.sh index 69614ce..43c8f70 100755..100644 --- a/scripts/completion_jv.sh +++ b/scripts/completion_jv.sh @@ -22,7 +22,7 @@ _jv_completion() { jump align" # Subcommands - Account - local account_commands="list as add remove movekey mvkey mvk help" + local account_commands="list as add remove movekey mvkey mvk genpub help" # Subcommands - Sheet local sheet_commands="list use exit make drop help" @@ -44,16 +44,25 @@ _jv_completion() { fi case "$subsubcmd" in - "as"|"remove"|"mvkey"|"mvk"|"movekey") + "as"|"remove"|"mvkey"|"mvk"|"movekey"|"genpub") if [[ $cword -eq 3 ]]; then # Use jv account list --raw local accounts accounts=$($cmd account list --raw 2>/dev/null) COMPREPLY=($(compgen -W "$accounts" -- "$cur")) - elif [[ $cword -eq 4 && ("$subsubcmd" == "mvkey" || "$subsubcmd" == "mvk" || "$subsubcmd" == "movekey") ]]; then + elif [[ $cword -eq 4 && ("$subsubcmd" == "mvkey" || "$subsubcmd" == "mvk" || "$subsubcmd" == "movekey" || "$subsubcmd" == "genpub") ]]; then COMPREPLY=($(compgen -f -- "$cur")) fi ;; + "add") + if [[ $cword -eq 3 ]]; then + # No completion for account name, let user type it + COMPREPLY=() + elif [[ $cword -eq 4 && "$cur" == -* ]]; then + # Complete --keygen option + COMPREPLY=($(compgen -W "--keygen" -- "$cur")) + fi + ;; "-"|"rm") if [[ $cword -eq 3 ]]; then local accounts 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, |
