summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--locales/help_docs/en.yml16
-rw-r--r--locales/help_docs/zh-CN.yml16
-rw-r--r--[-rwxr-xr-x]scripts/completion_jv.sh15
-rw-r--r--src/bin/jv.rs101
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,