feat(keyman): 更新 README 和插件文档,统一命令格式并增强帮助信息

This commit is contained in:
XS 2026-04-02 13:10:05 +08:00
commit 7cc680d82c
2 changed files with 358 additions and 156 deletions

View file

@ -1,39 +1,89 @@
# keyman plugin # keyman plugin
Provides convenient commands for managing SSH and GPG keys from the terminal. Provides a unified `keyman` command for managing SSH and GPG keys from the terminal.
Works on macOS, Linux (X11/Wayland), and WSL. Works on macOS, Linux (X11/Wayland), and WSL.
> **Relationship to other plugins:** The [`ssh-agent`](../ssh-agent) and
> [`gpg-agent`](../gpg-agent) plugins manage agent *daemons* (auto-starting,
> identity loading, forwarding). `keyman` focuses on key *lifecycle* — creating,
> listing, copying, and deleting keys. They are complementary and can be used
> together.
To enable it, add `keyman` to your plugins: To enable it, add `keyman` to your plugins:
```zsh ```zsh
plugins=(... keyman) plugins=(... keyman)
``` ```
Then type `keyman` to see all available commands. Then type `keyman help` to see all available commands.
## Requirements
At least one of the following must be available:
- `ssh-keygen` — for SSH key commands
- `gpg` — for GPG key commands
### Clipboard support
For clipboard commands (`keyman ssh copy`, `keyman gpg copy`), one of the tools
below must be installed:
| Platform | Tool | Notes |
| --------------- | ---------- | -------------------------- |
| macOS | `pbcopy` | Built-in |
| Linux (X11) | `xclip` | `apt install xclip` |
| Linux (Wayland) | `wl-copy` | `apt install wl-clipboard` |
| WSL | `clip.exe` | Built-in (Windows side) |
## Commands ## Commands
### SSH ### SSH
| Command | Description | | Command | Description |
|---|---| | --------------------------------------------- | --------------------------------------- |
| `km-ssh-new [comment] [file] [type]` | Create a new SSH key (default: ed25519) | | `keyman ssh new [comment] [file] [type]` | Create a new SSH key (default: ed25519) |
| `km-ssh-ls` | List all SSH public keys in `~/.ssh` | | `keyman ssh ls` | List all SSH public keys in `~/.ssh` |
| `km-ssh-copy [pubkey_file]` | Copy a public key to clipboard | | `keyman ssh copy [pubkey_file]` | Copy a public key to clipboard |
| `km-ssh-rm <keyfile>` | Delete an SSH key pair | | `keyman ssh rm <keyfile>` | Delete an SSH key pair |
### GPG ### GPG
| Command | Description | | Command | Description |
|---|---| | -------------------------------------------------- | --------------------------------------------------------------- |
| `km-gpg-new` | Create a GPG key (interactive, via `gpg --full-generate-key`) | | `keyman gpg new` | Create a GPG key (interactive, via `gpg --full-generate-key`) |
| `km-gpg-quick-new "Name" "Email" [expiry]` | Create a GPG key non-interactively (ed25519, default 2y expiry) | | `keyman gpg quick-new "Name" "Email" [expiry]` | Create a GPG key non-interactively (ed25519, default 2y expiry) |
| `km-gpg-ls [-s\|--secret]` | List public keys, or secret keys with `-s` | | `keyman gpg ls [-s\|--secret]` | List public keys, or secret keys with `-s` |
| `km-gpg-pub <id>` | Export a GPG public key (armored) | | `keyman gpg pub <id>` | Export a GPG public key (armored) |
| `km-gpg-priv <id>` | Export a GPG secret key (armored, with confirmation) | | `keyman gpg priv <id>` | Export a GPG secret key (armored, with confirmation) |
| `km-gpg-copy <id>` | Copy a GPG public key to clipboard | | `keyman gpg copy <id>` | Copy a GPG public key to clipboard |
| `km-gpg-fp <id>` | Show a GPG key fingerprint | | `keyman gpg fp <id>` | Show a GPG key fingerprint |
| `km-gpg-rm <id>` | Delete a GPG key (secret + public) | | `keyman gpg rm <id>` | Delete a GPG key (secret + public) |
### General
| Command | Description |
| -------------- | ----------------- |
| `keyman help` | Show help message |
## Tab Completion
All commands support multi-level Zsh tab completion:
```
keyman <TAB> → ssh | gpg | help
keyman ssh <TAB> → new | ls | copy | rm
keyman gpg <TAB> → new | quick-new | ls | pub | priv | copy | fp | rm
```
At the argument level:
- **`keyman ssh new`** — completes key types (`ed25519`, `rsa`, `ecdsa`) and file paths
- **`keyman ssh copy`** — completes `~/.ssh/*.pub` files
- **`keyman ssh rm`** — completes private key files in `~/.ssh`
- **`keyman gpg ls`** — completes `--secret` / `-s` options
- **`keyman gpg quick-new`** — completes common expiry values (`1y`, `2y`, `3y`, `5y`, `0`)
- **`keyman gpg pub`**, **`priv`**, **`copy`**, **`fp`**, **`rm`** — complete GPG key IDs and emails from your keyring
## Settings ## Settings
@ -57,7 +107,7 @@ zstyle :omz:plugins:keyman debug true
### `default-ssh-type` ### `default-ssh-type`
Set the default SSH key type for `km-ssh-new`. Supported values: Set the default SSH key type for `keyman ssh new`. Supported values:
`ed25519` (default), `rsa`, `ecdsa`. `ed25519` (default), `rsa`, `ecdsa`.
```zsh ```zsh
@ -68,30 +118,32 @@ zstyle :omz:plugins:keyman default-ssh-type rsa
```zsh ```zsh
# Create a default ed25519 key # Create a default ed25519 key
km-ssh-new keyman ssh new
# Create an RSA key with a custom comment and path # Create an RSA key with a custom comment and path
km-ssh-new "me@work" ~/.ssh/work_key rsa keyman ssh new "me@work" ~/.ssh/work_key rsa
# List all SSH keys # List all SSH keys
km-ssh-ls keyman ssh ls
# Copy the default public key to clipboard # Copy the default public key to clipboard
km-ssh-copy keyman ssh copy
# Delete an SSH key
keyman ssh rm ~/.ssh/id_ed25519
# Create a GPG key interactively
keyman gpg new
# Create a GPG key quickly # Create a GPG key quickly
km-gpg-quick-new "John Doe" "john@example.com" 1y keyman gpg quick-new "John Doe" "john@example.com" 1y
# List GPG secret keys
keyman gpg ls --secret
# Export and copy a GPG public key # Export and copy a GPG public key
km-gpg-copy john@example.com keyman gpg copy john@example.com
# Show GPG key fingerprint
keyman gpg fp john@example.com
``` ```
## Requirements
At least one of the following must be available:
- `ssh-keygen` -- for SSH key commands
- `gpg` -- for GPG key commands
For clipboard support, one of: `pbcopy` (macOS), `xclip` (Linux X11),
`wl-copy` (Linux Wayland), or `clip.exe` (WSL).

View file

@ -1,7 +1,14 @@
#!/usr/bin/env zsh #!/usr/bin/env zsh
# keyman.plugin.zsh -- SSH & GPG key management plugin for oh-my-zsh # keyman.plugin.zsh -- SSH & GPG key management plugin for oh-my-zsh
# #
# Author: keyman contributors
# Version: 0.2.0
# License: MIT (same as oh-my-zsh)
#
# Usage: add 'keyman' to plugins in ~/.zshrc # Usage: add 'keyman' to plugins in ~/.zshrc
# keyman ssh <action> [args...]
# keyman gpg <action> [args...]
# keyman help
# #
# Configuration (in .zshrc, before plugins=(...)): # Configuration (in .zshrc, before plugins=(...)):
# zstyle ':omz:plugins:keyman' lang en # en (default) | zh # zstyle ':omz:plugins:keyman' lang en # en (default) | zh
@ -21,6 +28,7 @@ typeset -g _km_green=$'\033[0;32m'
typeset -g _km_yellow=$'\033[0;33m' typeset -g _km_yellow=$'\033[0;33m'
typeset -g _km_blue=$'\033[0;34m' typeset -g _km_blue=$'\033[0;34m'
typeset -g _km_cyan=$'\033[0;36m' typeset -g _km_cyan=$'\033[0;36m'
typeset -g _km_bold=$'\033[1m'
typeset -g _km_reset=$'\033[0m' typeset -g _km_reset=$'\033[0m'
_km_info() { print -r -- "${_km_blue}[keyman]${_km_reset} $*" } _km_info() { print -r -- "${_km_blue}[keyman]${_km_reset} $*" }
@ -69,7 +77,7 @@ function {
label_type "类型:" label_type "类型:"
label_fingerprint "指纹:" label_fingerprint "指纹:"
label_comment "注释:" label_comment "注释:"
# -- km-ssh-new -- # -- ssh new --
ssh_dir_created "已创建 ~/.ssh 目录" ssh_dir_created "已创建 ~/.ssh 目录"
file_exists "文件已存在" file_exists "文件已存在"
confirm_overwrite "是否覆盖?(y/N) " confirm_overwrite "是否覆盖?(y/N) "
@ -78,19 +86,19 @@ function {
key_created "密钥已创建" key_created "密钥已创建"
added_to_agent "已添加到 ssh-agent" added_to_agent "已添加到 ssh-agent"
key_creation_failed "密钥创建失败" key_creation_failed "密钥创建失败"
# -- km-ssh-ls -- # -- ssh ls --
ssh_dir_not_found "~/.ssh 目录不存在" ssh_dir_not_found "~/.ssh 目录不存在"
no_ssh_keys_found "未找到任何 SSH 公钥" no_ssh_keys_found "未找到任何 SSH 公钥"
# -- km-ssh-copy -- # -- ssh copy --
pubkey_not_found "公钥文件不存在" pubkey_not_found "公钥文件不存在"
available_pubkeys "可用的公钥:" available_pubkeys "可用的公钥:"
none "(无)" none "(无)"
pubkey_copied "公钥已复制到剪贴板" pubkey_copied "公钥已复制到剪贴板"
# -- km-ssh-rm -- # -- ssh rm --
usage_ssh_rm "用法: km-ssh-rm <keyfile>" usage_ssh_rm "用法: keyman ssh rm <keyfile>"
key_not_found "密钥不存在" key_not_found "密钥不存在"
# -- km-gpg-quick-new -- # -- gpg quick-new --
usage_gpg_quick_new "用法: km-gpg-quick-new \"姓名\" \"邮箱\" [过期时间]" usage_gpg_quick_new "用法: keyman gpg quick-new \"姓名\" \"邮箱\" [过期时间]"
email_has_gpg_key "该邮箱已有 GPG 密钥:" email_has_gpg_key "该邮箱已有 GPG 密钥:"
confirm_create_new "继续创建新密钥?(y/N) " confirm_create_new "继续创建新密钥?(y/N) "
creating_gpg_key "正在创建 GPG 密钥..." creating_gpg_key "正在创建 GPG 密钥..."
@ -99,54 +107,56 @@ function {
label_expiry " 过期:" label_expiry " 过期:"
gpg_key_created "GPG 密钥已创建" gpg_key_created "GPG 密钥已创建"
gpg_key_creation_failed "GPG 密钥创建失败" gpg_key_creation_failed "GPG 密钥创建失败"
# -- km-gpg-ls -- # -- gpg ls --
gpg_secret_key_list "GPG 私钥列表:" gpg_secret_key_list "GPG 私钥列表:"
gpg_public_key_list "GPG 公钥列表:" gpg_public_key_list "GPG 公钥列表:"
# -- km-gpg-pub -- # -- gpg pub --
usage_gpg_pub "用法: km-gpg-pub <邮箱或KeyID>" usage_gpg_pub "用法: keyman gpg pub <邮箱或KeyID>"
gpg_key_not_found "未找到密钥" gpg_key_not_found "未找到密钥"
gpg_public_key "GPG 公钥" gpg_public_key "GPG 公钥"
# -- km-gpg-priv -- # -- gpg priv --
usage_gpg_priv "用法: km-gpg-priv <邮箱或KeyID>" usage_gpg_priv "用法: keyman gpg priv <邮箱或KeyID>"
gpg_secret_not_found "未找到私钥" gpg_secret_not_found "未找到私钥"
warn_export_secret "即将导出私钥!请确保在安全环境下操作" warn_export_secret "即将导出私钥!请确保在安全环境下操作"
confirm_export "确认导出?(y/N) " confirm_export "确认导出?(y/N) "
# -- km-gpg-copy -- # -- gpg copy --
usage_gpg_copy "用法: km-gpg-copy <邮箱或KeyID>" usage_gpg_copy "用法: keyman gpg copy <邮箱或KeyID>"
gpg_pubkey_copied "GPG 公钥已复制到剪贴板" gpg_pubkey_copied "GPG 公钥已复制到剪贴板"
# -- km-gpg-fp -- # -- gpg fp --
usage_gpg_fp "用法: km-gpg-fp <邮箱或KeyID>" usage_gpg_fp "用法: keyman gpg fp <邮箱或KeyID>"
# -- km-gpg-rm -- # -- gpg rm --
usage_gpg_rm "用法: km-gpg-rm <邮箱或KeyID>" usage_gpg_rm "用法: keyman gpg rm <邮箱或KeyID>"
about_to_delete_gpg "即将删除 GPG 密钥" about_to_delete_gpg "即将删除 GPG 密钥"
key_info "密钥信息:" key_info "密钥信息:"
# -- errors --
unknown_group "未知命令组: %s (可用: ssh, gpg)"
unknown_ssh_action "未知 SSH 操作: %s (可用: new, ls, copy, rm)"
unknown_gpg_action "未知 GPG 操作: %s (可用: new, quick-new, ls, pub, priv, copy, fp, rm)"
# -- debug -- # -- debug --
loaded "已加载,输入 keyman 查看帮助" loaded "已加载,输入 keyman help 查看帮助"
# -- help -- # -- help --
help_text \ help_text \
"╔═══════════════════════════════════════════════════════════════╗ "${_km_bold}keyman${_km_reset} — SSH & GPG 密钥管理
║ keyman 密钥管理 ║
╠═══════════════════════════════════════════════════════════════╣ ${_km_cyan}用法:${_km_reset}
║ ║ keyman <命令组> <操作> [参数...]
║ SSH 命令: ║ keyman help
║ ────────────────────────────────────────────────────── ║
║ km-ssh-new [comment] [file] [type] 创建 SSH 密钥 ║ ${_km_cyan}SSH 命令:${_km_reset}
║ km-ssh-ls 列出所有 SSH 公钥 ║ keyman ssh new [comment] [file] [type] 创建 SSH 密钥
║ km-ssh-copy [pubkey_file] 复制公钥到剪贴板 ║ keyman ssh ls 列出所有 SSH 公钥
║ km-ssh-rm <keyfile> 删除 SSH 密钥对 ║ keyman ssh copy [pubkey_file] 复制公钥到剪贴板
║ ║ keyman ssh rm <keyfile> 删除 SSH 密钥对
║ GPG 命令: ║
║ ────────────────────────────────────────────────────── ║ ${_km_cyan}GPG 命令:${_km_reset}
║ km-gpg-new 创建密钥(交互式) ║ keyman gpg new 创建密钥(交互式)
║ km-gpg-quick-new \"姓名\" \"邮箱\" [期限] 创建密钥(快速) ║ keyman gpg quick-new \"姓名\" \"邮箱\" [期限] 创建密钥(快速)
║ km-gpg-ls [-s|--secret] 列出密钥 ║ keyman gpg ls [-s|--secret] 列出密钥
║ km-gpg-pub <id> 导出公钥 ║ keyman gpg pub <id> 导出公钥
║ km-gpg-priv <id> 导出私钥 ║ keyman gpg priv <id> 导出私钥
║ km-gpg-copy <id> 复制公钥到剪贴板 ║ keyman gpg copy <id> 复制公钥到剪贴板
║ km-gpg-fp <id> 查看指纹 ║ keyman gpg fp <id> 查看指纹
║ km-gpg-rm <id> 删除密钥 ║ keyman gpg rm <id> 删除密钥"
║ ║
╚═══════════════════════════════════════════════════════════════╝"
) )
;; ;;
*) *)
@ -165,7 +175,7 @@ function {
label_type "Type:" label_type "Type:"
label_fingerprint "Fingerprint:" label_fingerprint "Fingerprint:"
label_comment "Comment:" label_comment "Comment:"
# -- km-ssh-new -- # -- ssh new --
ssh_dir_created "Created ~/.ssh directory" ssh_dir_created "Created ~/.ssh directory"
file_exists "File already exists" file_exists "File already exists"
confirm_overwrite "Overwrite? (y/N) " confirm_overwrite "Overwrite? (y/N) "
@ -174,19 +184,19 @@ function {
key_created "Key created" key_created "Key created"
added_to_agent "Added to ssh-agent" added_to_agent "Added to ssh-agent"
key_creation_failed "Key creation failed" key_creation_failed "Key creation failed"
# -- km-ssh-ls -- # -- ssh ls --
ssh_dir_not_found "~/.ssh directory does not exist" ssh_dir_not_found "~/.ssh directory does not exist"
no_ssh_keys_found "No SSH public keys found" no_ssh_keys_found "No SSH public keys found"
# -- km-ssh-copy -- # -- ssh copy --
pubkey_not_found "Public key file not found" pubkey_not_found "Public key file not found"
available_pubkeys "Available public keys:" available_pubkeys "Available public keys:"
none "(none)" none "(none)"
pubkey_copied "Public key copied to clipboard" pubkey_copied "Public key copied to clipboard"
# -- km-ssh-rm -- # -- ssh rm --
usage_ssh_rm "Usage: km-ssh-rm <keyfile>" usage_ssh_rm "Usage: keyman ssh rm <keyfile>"
key_not_found "Key not found" key_not_found "Key not found"
# -- km-gpg-quick-new -- # -- gpg quick-new --
usage_gpg_quick_new "Usage: km-gpg-quick-new \"Name\" \"Email\" [expiry]" usage_gpg_quick_new "Usage: keyman gpg quick-new \"Name\" \"Email\" [expiry]"
email_has_gpg_key "This email already has a GPG key:" email_has_gpg_key "This email already has a GPG key:"
confirm_create_new "Continue creating new key? (y/N) " confirm_create_new "Continue creating new key? (y/N) "
creating_gpg_key "Creating GPG key..." creating_gpg_key "Creating GPG key..."
@ -195,54 +205,56 @@ function {
label_expiry " Expiry:" label_expiry " Expiry:"
gpg_key_created "GPG key created" gpg_key_created "GPG key created"
gpg_key_creation_failed "GPG key creation failed" gpg_key_creation_failed "GPG key creation failed"
# -- km-gpg-ls -- # -- gpg ls --
gpg_secret_key_list "GPG secret key list:" gpg_secret_key_list "GPG secret key list:"
gpg_public_key_list "GPG public key list:" gpg_public_key_list "GPG public key list:"
# -- km-gpg-pub -- # -- gpg pub --
usage_gpg_pub "Usage: km-gpg-pub <email-or-KeyID>" usage_gpg_pub "Usage: keyman gpg pub <email-or-KeyID>"
gpg_key_not_found "Key not found" gpg_key_not_found "Key not found"
gpg_public_key "GPG public key" gpg_public_key "GPG public key"
# -- km-gpg-priv -- # -- gpg priv --
usage_gpg_priv "Usage: km-gpg-priv <email-or-KeyID>" usage_gpg_priv "Usage: keyman gpg priv <email-or-KeyID>"
gpg_secret_not_found "Secret key not found" gpg_secret_not_found "Secret key not found"
warn_export_secret "About to export secret key! Make sure you are in a secure environment" warn_export_secret "About to export secret key! Make sure you are in a secure environment"
confirm_export "Confirm export? (y/N) " confirm_export "Confirm export? (y/N) "
# -- km-gpg-copy -- # -- gpg copy --
usage_gpg_copy "Usage: km-gpg-copy <email-or-KeyID>" usage_gpg_copy "Usage: keyman gpg copy <email-or-KeyID>"
gpg_pubkey_copied "GPG public key copied to clipboard" gpg_pubkey_copied "GPG public key copied to clipboard"
# -- km-gpg-fp -- # -- gpg fp --
usage_gpg_fp "Usage: km-gpg-fp <email-or-KeyID>" usage_gpg_fp "Usage: keyman gpg fp <email-or-KeyID>"
# -- km-gpg-rm -- # -- gpg rm --
usage_gpg_rm "Usage: km-gpg-rm <email-or-KeyID>" usage_gpg_rm "Usage: keyman gpg rm <email-or-KeyID>"
about_to_delete_gpg "About to delete GPG key" about_to_delete_gpg "About to delete GPG key"
key_info "Key info:" key_info "Key info:"
# -- errors --
unknown_group "Unknown command group: %s (available: ssh, gpg)"
unknown_ssh_action "Unknown SSH action: %s (available: new, ls, copy, rm)"
unknown_gpg_action "Unknown GPG action: %s (available: new, quick-new, ls, pub, priv, copy, fp, rm)"
# -- debug -- # -- debug --
loaded "Loaded. Type 'keyman' for help" loaded "Loaded. Type 'keyman help' for help"
# -- help -- # -- help --
help_text \ help_text \
"╔═══════════════════════════════════════════════════════════════╗ "${_km_bold}keyman${_km_reset} — SSH & GPG Key Manager
║ keyman - Key Manager ║
╠═══════════════════════════════════════════════════════════════╣ ${_km_cyan}Usage:${_km_reset}
║ ║ keyman <group> <action> [args...]
║ SSH Commands: ║ keyman help
║ ────────────────────────────────────────────────────── ║
║ km-ssh-new [comment] [file] [type] Create SSH key ║ ${_km_cyan}SSH Commands:${_km_reset}
║ km-ssh-ls List SSH public keys ║ keyman ssh new [comment] [file] [type] Create SSH key
║ km-ssh-copy [pubkey_file] Copy pubkey to clipboard║ keyman ssh ls List SSH public keys
║ km-ssh-rm <keyfile> Delete SSH key pair ║ keyman ssh copy [pubkey_file] Copy pubkey to clipboard
║ ║ keyman ssh rm <keyfile> Delete SSH key pair
║ GPG Commands: ║
║ ────────────────────────────────────────────────────── ║ ${_km_cyan}GPG Commands:${_km_reset}
║ km-gpg-new Create key (interactive) keyman gpg new Create key (interactive)
║ km-gpg-quick-new \"Name\" \"Email\" [exp] Create key (quick) keyman gpg quick-new \"Name\" \"Email\" [exp] Create key (quick)
║ km-gpg-ls [-s|--secret] List keys ║ keyman gpg ls [-s|--secret] List keys
║ km-gpg-pub <id> Export public key ║ keyman gpg pub <id> Export public key
║ km-gpg-priv <id> Export secret key ║ keyman gpg priv <id> Export secret key
║ km-gpg-copy <id> Copy pubkey to clipboard║ keyman gpg copy <id> Copy pubkey to clipboard
║ km-gpg-fp <id> Show fingerprint ║ keyman gpg fp <id> Show fingerprint
║ km-gpg-rm <id> Delete key ║ keyman gpg rm <id> Delete key"
║ ║
╚═══════════════════════════════════════════════════════════════╝"
) )
;; ;;
esac esac
@ -252,12 +264,11 @@ function {
} }
# ===================================================== # =====================================================
# SSH Commands # SSH Actions
# ===================================================== # =====================================================
# Create SSH key # keyman ssh new [comment] [keyfile] [type]
# Usage: km-ssh-new [comment] [keyfile] [type] _km_ssh_new() {
km-ssh-new() {
local comment="${1:-${USER:-$(whoami)}@${HOST:-$(hostname)}}" local comment="${1:-${USER:-$(whoami)}@${HOST:-$(hostname)}}"
local keyfile="${2:-}" local keyfile="${2:-}"
local keytype="${3:-}" local keytype="${3:-}"
@ -338,8 +349,8 @@ km-ssh-new() {
fi fi
} }
# List all SSH public keys # keyman ssh ls
km-ssh-ls() { _km_ssh_ls() {
local found=0 local found=0
if [[ ! -d "$HOME/.ssh" ]]; then if [[ ! -d "$HOME/.ssh" ]]; then
@ -373,9 +384,8 @@ km-ssh-ls() {
fi fi
} }
# Copy SSH public key to clipboard # keyman ssh copy [keyfile]
# Usage: km-ssh-copy [keyfile] _km_ssh_copy() {
km-ssh-copy() {
local pubkey="${1:-$HOME/.ssh/id_ed25519.pub}" local pubkey="${1:-$HOME/.ssh/id_ed25519.pub}"
[[ "$pubkey" != *.pub ]] && pubkey="${pubkey}.pub" [[ "$pubkey" != *.pub ]] && pubkey="${pubkey}.pub"
@ -393,9 +403,8 @@ km-ssh-copy() {
fi fi
} }
# Delete SSH key pair # keyman ssh rm <keyfile>
# Usage: km-ssh-rm <keyfile> _km_ssh_rm() {
km-ssh-rm() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_ssh_rm]}" _km_err "${_km_msg[usage_ssh_rm]}"
return 1 return 1
@ -426,15 +435,16 @@ km-ssh-rm() {
} }
# ===================================================== # =====================================================
# GPG Commands # GPG Actions
# ===================================================== # =====================================================
# Create GPG key (interactive) # keyman gpg new (interactive)
alias km-gpg-new='gpg --full-generate-key' _km_gpg_new() {
gpg --full-generate-key
}
# Create GPG key (non-interactive) # keyman gpg quick-new "Name" "Email" [expiry]
# Usage: km-gpg-quick-new "Name" "Email" [expiry] _km_gpg_quick_new() {
km-gpg-quick-new() {
if [[ -z "${1:-}" || -z "${2:-}" ]]; then if [[ -z "${1:-}" || -z "${2:-}" ]]; then
_km_err "${_km_msg[usage_gpg_quick_new]}" _km_err "${_km_msg[usage_gpg_quick_new]}"
return 1 return 1
@ -479,9 +489,8 @@ EOF
fi fi
} }
# List GPG keys # keyman gpg ls [--secret|-s]
# Usage: km-gpg-ls [--secret|-s] _km_gpg_ls() {
km-gpg-ls() {
if [[ "$1" == "--secret" || "$1" == "-s" ]]; then if [[ "$1" == "--secret" || "$1" == "-s" ]]; then
_km_info "${_km_msg[gpg_secret_key_list]}" _km_info "${_km_msg[gpg_secret_key_list]}"
echo "" echo ""
@ -493,9 +502,8 @@ km-gpg-ls() {
fi fi
} }
# Export GPG public key # keyman gpg pub <email-or-KeyID>
# Usage: km-gpg-pub <email-or-KeyID> _km_gpg_pub() {
km-gpg-pub() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_pub]}" _km_err "${_km_msg[usage_gpg_pub]}"
return 1 return 1
@ -512,9 +520,8 @@ km-gpg-pub() {
gpg --armor --export "$key_id" gpg --armor --export "$key_id"
} }
# Export GPG secret key # keyman gpg priv <email-or-KeyID>
# Usage: km-gpg-priv <email-or-KeyID> _km_gpg_priv() {
km-gpg-priv() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_priv]}" _km_err "${_km_msg[usage_gpg_priv]}"
return 1 return 1
@ -537,9 +544,8 @@ km-gpg-priv() {
fi fi
} }
# Copy GPG public key to clipboard # keyman gpg copy <email-or-KeyID>
# Usage: km-gpg-copy <email-or-KeyID> _km_gpg_copy() {
km-gpg-copy() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_copy]}" _km_err "${_km_msg[usage_gpg_copy]}"
return 1 return 1
@ -557,9 +563,8 @@ km-gpg-copy() {
fi fi
} }
# Show GPG key fingerprint # keyman gpg fp <email-or-KeyID>
# Usage: km-gpg-fp <email-or-KeyID> _km_gpg_fp() {
km-gpg-fp() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_fp]}" _km_err "${_km_msg[usage_gpg_fp]}"
return 1 return 1
@ -567,9 +572,8 @@ km-gpg-fp() {
gpg --fingerprint "$1" gpg --fingerprint "$1"
} }
# Delete GPG key # keyman gpg rm <email-or-KeyID>
# Usage: km-gpg-rm <email-or-KeyID> _km_gpg_rm() {
km-gpg-rm() {
if [[ -z "${1:-}" ]]; then if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_rm]}" _km_err "${_km_msg[usage_gpg_rm]}"
return 1 return 1
@ -593,8 +597,154 @@ km-gpg-rm() {
} }
# ===================================================== # =====================================================
# Help # Main dispatcher
# ===================================================== # =====================================================
keyman() { keyman() {
print -r -- "${_km_msg[help_text]}" local group="${1:-help}"
local action="${2:-}"
shift 2 2>/dev/null
case "$group" in
help|-h|--help)
print -r -- "${_km_msg[help_text]}"
;;
ssh)
case "$action" in
new) _km_ssh_new "$@" ;;
ls) _km_ssh_ls "$@" ;;
copy) _km_ssh_copy "$@" ;;
rm) _km_ssh_rm "$@" ;;
*)
_km_err "$(printf "${_km_msg[unknown_ssh_action]}" "$action")"
return 1
;;
esac
;;
gpg)
case "$action" in
new) _km_gpg_new "$@" ;;
quick-new) _km_gpg_quick_new "$@" ;;
ls) _km_gpg_ls "$@" ;;
pub) _km_gpg_pub "$@" ;;
priv) _km_gpg_priv "$@" ;;
copy) _km_gpg_copy "$@" ;;
fp) _km_gpg_fp "$@" ;;
rm) _km_gpg_rm "$@" ;;
*)
_km_err "$(printf "${_km_msg[unknown_gpg_action]}" "$action")"
return 1
;;
esac
;;
*)
_km_err "$(printf "${_km_msg[unknown_group]}" "$group")"
return 1
;;
esac
} }
# =====================================================
# Zsh Completions
# =====================================================
_keyman() {
local curcontext="$curcontext" state line
typeset -A opt_args
_arguments -C \
'1:command group:->group' \
'*::args:->args'
case "$state" in
group)
local -a groups=(
'ssh:Manage SSH keys'
'gpg:Manage GPG keys'
'help:Show help message'
)
_describe 'command group' groups
;;
args)
case "${line[1]}" in
ssh)
_arguments -C \
'1:ssh action:->ssh_action' \
'*::ssh_args:->ssh_args'
case "$state" in
ssh_action)
local -a actions=(
'new:Create SSH key'
'ls:List SSH public keys'
'copy:Copy public key to clipboard'
'rm:Delete SSH key pair'
)
_describe 'ssh action' actions
;;
ssh_args)
case "${line[1]}" in
new)
_arguments \
'1:comment:' \
'2:keyfile:_files -W "$HOME/.ssh"' \
'3:key type:(ed25519 rsa ecdsa)'
;;
copy)
_arguments '1:public key file:_files -W "$HOME/.ssh" -g "*.pub"'
;;
rm)
local -a keys
if [[ -d "$HOME/.ssh" ]]; then
keys=("$HOME"/.ssh/id_*(N:t))
keys=(${keys:#*.pub})
fi
_describe 'SSH key' keys
;;
esac
;;
esac
;;
gpg)
_arguments -C \
'1:gpg action:->gpg_action' \
'*::gpg_args:->gpg_args'
case "$state" in
gpg_action)
local -a actions=(
'new:Create GPG key (interactive)'
'quick-new:Create GPG key (quick)'
'ls:List GPG keys'
'pub:Export public key'
'priv:Export secret key'
'copy:Copy public key to clipboard'
'fp:Show fingerprint'
'rm:Delete GPG key'
)
_describe 'gpg action' actions
;;
gpg_args)
case "${line[1]}" in
ls)
_arguments '1:option:(--secret -s)'
;;
quick-new)
_arguments \
'1:name:' \
'2:email:' \
'3:expiry:(1y 2y 3y 5y 0)'
;;
pub|priv|copy|fp|rm)
local -a key_ids
key_ids=(${(f)"$(gpg --list-keys --with-colons 2>/dev/null \
| awk -F: '/^uid/{print $10}; /^pub/{print $5}')"})
_describe 'GPG key ID or email' key_ids
;;
esac
;;
esac
;;
esac
;;
esac
}
compdef _keyman keyman