1
0
mirror of https://github.com/ohmyzsh/ohmyzsh.git synced 2026-04-10 16:32:00 +00:00
Files
ohmyzsh-mirror/plugins/keyman/keyman.plugin.zsh

766 lines
24 KiB
Bash

#!/usr/bin/env 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
# keyman ssh <action> [args...]
# keyman gpg <action> [args...]
# keyman help
#
# Configuration (in .zshrc, before plugins=(...)):
# zstyle ':omz:plugins:keyman' lang en # en (default) | zh
# zstyle ':omz:plugins:keyman' debug true # show load message (default: false)
# zstyle ':omz:plugins:keyman' default-ssh-type ed25519 # ed25519 | rsa | ecdsa
# Require at least one of ssh-keygen or gpg
(( $+commands[ssh-keygen] + $+commands[gpg] )) || return
# =====================================================
# Persistent globals
# =====================================================
typeset -gA _km_msg
typeset -g _km_red=$'\033[0;31m'
typeset -g _km_green=$'\033[0;32m'
typeset -g _km_yellow=$'\033[0;33m'
typeset -g _km_blue=$'\033[0;34m'
typeset -g _km_cyan=$'\033[0;36m'
typeset -g _km_bold=$'\033[1m'
typeset -g _km_reset=$'\033[0m'
_km_info() { print -r -- "${_km_blue}[keyman]${_km_reset} $*" }
_km_ok() { print -r -- "${_km_green}[keyman] ✅${_km_reset} $*" }
_km_warn() { print -r -- "${_km_yellow}[keyman] ⚠️${_km_reset} $*" }
_km_err() { print -r -- "${_km_red}[keyman] ❌${_km_reset} $*" }
# Cross-platform clipboard
_km_copy_to_clipboard() {
local content="$1"
if command -v pbcopy &>/dev/null; then
printf '%s' "$content" | pbcopy
elif command -v xclip &>/dev/null; then
printf '%s' "$content" | xclip -selection clipboard
elif command -v wl-copy &>/dev/null; then
printf '%s' "$content" | wl-copy
elif command -v clip.exe &>/dev/null; then
printf '%s' "$content" | clip.exe
else
_km_warn "${_km_msg[clipboard_not_found]}"
return 1
fi
}
# =====================================================
# Initialization (scoped via anonymous function)
# =====================================================
function {
local lang
zstyle -s ':omz:plugins:keyman' lang lang || lang=en
case "$lang" in
zh)
_km_msg=(
# -- clipboard --
clipboard_not_found "未找到剪贴板工具 (pbcopy/xclip/wl-copy/clip.exe)"
# -- general --
cancelled "已取消"
deleted "已删除"
confirm_delete "确认删除?(y/N) "
about_to_delete "即将删除:"
label_private_key "私钥:"
label_public_key "公钥:"
label_pubkey_content "公钥内容:"
label_file "文件:"
label_type "类型:"
label_fingerprint "指纹:"
label_comment "注释:"
# -- ssh new --
ssh_dir_created "已创建 ~/.ssh 目录"
file_exists "文件已存在"
confirm_overwrite "是否覆盖?(y/N) "
creating_key "正在创建 %s 密钥..."
unsupported_key_type "不支持的密钥类型: %s (可选: ed25519, rsa, ecdsa)"
key_created "密钥已创建"
added_to_agent "已添加到 ssh-agent"
key_creation_failed "密钥创建失败"
# -- ssh ls --
ssh_dir_not_found "~/.ssh 目录不存在"
no_ssh_keys_found "未找到任何 SSH 公钥"
# -- ssh copy --
pubkey_not_found "公钥文件不存在"
available_pubkeys "可用的公钥:"
none "(无)"
pubkey_copied "公钥已复制到剪贴板"
# -- ssh rm --
usage_ssh_rm "用法: keyman ssh rm <keyfile>"
key_not_found "密钥不存在"
# -- gpg quick-new --
usage_gpg_quick_new "用法: keyman gpg quick-new \"姓名\" \"邮箱\" [过期时间]"
email_has_gpg_key "该邮箱已有 GPG 密钥:"
confirm_create_new "继续创建新密钥?(y/N) "
creating_gpg_key "正在创建 GPG 密钥..."
label_name " 姓名:"
label_email " 邮箱:"
label_expiry " 过期:"
gpg_key_created "GPG 密钥已创建"
gpg_key_creation_failed "GPG 密钥创建失败"
# -- gpg ls --
gpg_secret_key_list "GPG 私钥列表:"
gpg_public_key_list "GPG 公钥列表:"
# -- gpg pub --
usage_gpg_pub "用法: keyman gpg pub <邮箱或KeyID>"
gpg_key_not_found "未找到密钥"
gpg_public_key "GPG 公钥"
# -- gpg priv --
usage_gpg_priv "用法: keyman gpg priv <邮箱或KeyID>"
gpg_secret_not_found "未找到私钥"
warn_export_secret "即将导出私钥!请确保在安全环境下操作"
confirm_export "确认导出?(y/N) "
# -- gpg copy --
usage_gpg_copy "用法: keyman gpg copy <邮箱或KeyID>"
gpg_pubkey_copied "GPG 公钥已复制到剪贴板"
# -- gpg fp --
usage_gpg_fp "用法: keyman gpg fp <邮箱或KeyID>"
# -- gpg rm --
usage_gpg_rm "用法: keyman gpg rm <邮箱或KeyID>"
about_to_delete_gpg "即将删除 GPG 密钥"
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 --
loaded "已加载,输入 keyman help 查看帮助"
# -- help --
help_text \
"${_km_bold}keyman${_km_reset} — SSH & GPG 密钥管理
${_km_cyan}用法:${_km_reset}
keyman <命令组> <操作> [参数...]
keyman help
${_km_cyan}SSH 命令:${_km_reset}
keyman ssh new [comment] [file] [type] 创建 SSH 密钥
keyman ssh ls 列出所有 SSH 公钥
keyman ssh copy [pubkey_file] 复制公钥到剪贴板
keyman ssh rm <keyfile> 删除 SSH 密钥对
${_km_cyan}GPG 命令:${_km_reset}
keyman gpg new 创建密钥(交互式)
keyman gpg quick-new \"姓名\" \"邮箱\" [期限] 创建密钥(快速)
keyman gpg ls [-s|--secret] 列出密钥
keyman gpg pub <id> 导出公钥
keyman gpg priv <id> 导出私钥
keyman gpg copy <id> 复制公钥到剪贴板
keyman gpg fp <id> 查看指纹
keyman gpg rm <id> 删除密钥"
)
;;
*)
_km_msg=(
# -- clipboard --
clipboard_not_found "Clipboard tool not found (pbcopy/xclip/wl-copy/clip.exe)"
# -- general --
cancelled "Cancelled"
deleted "Deleted"
confirm_delete "Confirm deletion? (y/N) "
about_to_delete "About to delete:"
label_private_key "Private key:"
label_public_key "Public key:"
label_pubkey_content "Public key content:"
label_file "File:"
label_type "Type:"
label_fingerprint "Fingerprint:"
label_comment "Comment:"
# -- ssh new --
ssh_dir_created "Created ~/.ssh directory"
file_exists "File already exists"
confirm_overwrite "Overwrite? (y/N) "
creating_key "Creating %s key..."
unsupported_key_type "Unsupported key type: %s (supported: ed25519, rsa, ecdsa)"
key_created "Key created"
added_to_agent "Added to ssh-agent"
key_creation_failed "Key creation failed"
# -- ssh ls --
ssh_dir_not_found "~/.ssh directory does not exist"
no_ssh_keys_found "No SSH public keys found"
# -- ssh copy --
pubkey_not_found "Public key file not found"
available_pubkeys "Available public keys:"
none "(none)"
pubkey_copied "Public key copied to clipboard"
# -- ssh rm --
usage_ssh_rm "Usage: keyman ssh rm <keyfile>"
key_not_found "Key not found"
# -- gpg quick-new --
usage_gpg_quick_new "Usage: keyman gpg quick-new \"Name\" \"Email\" [exp]"
email_has_gpg_key "This email already has a GPG key:"
confirm_create_new "Continue creating new key? (y/N) "
creating_gpg_key "Creating GPG key..."
label_name " Name:"
label_email " Email:"
label_expiry " Expiry:"
gpg_key_created "GPG key created"
gpg_key_creation_failed "GPG key creation failed"
# -- gpg ls --
gpg_secret_key_list "GPG secret key list:"
gpg_public_key_list "GPG public key list:"
# -- gpg pub --
usage_gpg_pub "Usage: keyman gpg pub <email-or-KeyID>"
gpg_key_not_found "Key not found"
gpg_public_key "GPG public key"
# -- gpg priv --
usage_gpg_priv "Usage: keyman gpg priv <email-or-KeyID>"
gpg_secret_not_found "Secret key not found"
warn_export_secret "About to export secret key! Make sure you are in a secure environment"
confirm_export "Confirm export? (y/N) "
# -- gpg copy --
usage_gpg_copy "Usage: keyman gpg copy <email-or-KeyID>"
gpg_pubkey_copied "GPG public key copied to clipboard"
# -- gpg fp --
usage_gpg_fp "Usage: keyman gpg fp <email-or-KeyID>"
# -- gpg rm --
usage_gpg_rm "Usage: keyman gpg rm <email-or-KeyID>"
about_to_delete_gpg "About to delete GPG key"
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 --
loaded "Loaded. Type 'keyman help' for help"
# -- help --
help_text \
"${_km_bold}keyman${_km_reset} — SSH & GPG Key Manager
${_km_cyan}Usage:${_km_reset}
keyman <group> <action> [args...]
keyman help
${_km_cyan}SSH Commands:${_km_reset}
keyman ssh new [comment] [file] [type] Create SSH key
keyman ssh ls List SSH public keys
keyman ssh copy [pubkey_file] Copy pubkey to clipboard
keyman ssh rm <keyfile> Delete SSH key pair
${_km_cyan}GPG Commands:${_km_reset}
keyman gpg new Create key (interactive)
keyman gpg quick-new \"Name\" \"Email\" [exp] Create key (quick)
keyman gpg ls [-s|--secret] List keys
keyman gpg pub <id> Export public key
keyman gpg priv <id> Export secret key
keyman gpg copy <id> Copy pubkey to clipboard
keyman gpg fp <id> Show fingerprint
keyman gpg rm <id> Delete key"
)
;;
esac
# Debug output
zstyle -t ':omz:plugins:keyman' debug && _km_info "${_km_msg[loaded]}"
}
# =====================================================
# SSH Actions
# =====================================================
# keyman ssh new [comment] [keyfile] [type]
_km_ssh_new() {
local comment="${1:-${USER:-$(whoami)}@${HOST:-$(hostname)}}"
local keyfile="${2:-}"
local keytype="${3:-}"
if [[ -z "$keytype" ]]; then
zstyle -s ':omz:plugins:keyman' default-ssh-type keytype || keytype=ed25519
fi
# Set default path by type
if [[ -z "$keyfile" ]]; then
case "$keytype" in
rsa) keyfile="$HOME/.ssh/id_rsa" ;;
ecdsa) keyfile="$HOME/.ssh/id_ecdsa" ;;
ed25519) keyfile="$HOME/.ssh/id_ed25519" ;;
*) keyfile="$HOME/.ssh/id_${keytype}" ;;
esac
fi
# Ensure .ssh directory exists
if [[ ! -d "$HOME/.ssh" ]]; then
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
_km_info "${_km_msg[ssh_dir_created]}"
fi
# Prevent overwriting existing key
if [[ -f "$keyfile" ]]; then
_km_warn "${_km_msg[file_exists]}: $keyfile"
read -q "REPLY?${_km_msg[confirm_overwrite]}"
echo
if [[ "$REPLY" != "y" ]]; then
_km_info "${_km_msg[cancelled]}"
return 1
fi
fi
_km_info "$(printf "${_km_msg[creating_key]}" "$keytype")"
local _km_rc=0
case "$keytype" in
rsa)
ssh-keygen -t rsa -b 4096 -C "$comment" -f "$keyfile" || _km_rc=$?
;;
ecdsa)
ssh-keygen -t ecdsa -b 521 -C "$comment" -f "$keyfile" || _km_rc=$?
;;
ed25519)
ssh-keygen -t ed25519 -C "$comment" -f "$keyfile" || _km_rc=$?
;;
*)
_km_err "$(printf "${_km_msg[unsupported_key_type]}" "$keytype")"
return 1
;;
esac
if [[ $_km_rc -eq 0 && -f "${keyfile}.pub" ]]; then
chmod 600 "$keyfile"
chmod 644 "${keyfile}.pub"
_km_ok "${_km_msg[key_created]}"
print ""
print -r -- "${_km_cyan}${_km_msg[label_private_key]}${_km_reset} $keyfile"
print -r -- "${_km_cyan}${_km_msg[label_public_key]}${_km_reset} ${keyfile}.pub"
print ""
print -r -- "${_km_cyan}${_km_msg[label_pubkey_content]}${_km_reset}"
cat "${keyfile}.pub"
# Add to ssh-agent (start agent if needed)
if [[ -z "$SSH_AUTH_SOCK" ]]; then
eval "$(ssh-agent -s)" >/dev/null 2>&1
fi
if ssh-add "$keyfile" 2>/dev/null; then
_km_ok "${_km_msg[added_to_agent]}"
fi
else
_km_err "${_km_msg[key_creation_failed]}"
return 1
fi
}
# keyman ssh ls
_km_ssh_ls() {
local found=0
if [[ ! -d "$HOME/.ssh" ]]; then
_km_warn "${_km_msg[ssh_dir_not_found]}"
return 1
fi
for pubkey in "$HOME"/.ssh/*.pub(N); do
found=1
local info
info=$(ssh-keygen -l -f "$pubkey" 2>/dev/null) || continue
local bits=${info%% *}
local rest=${info#* }
local fingerprint=${rest%% *}
rest=${rest#* }
local keytype=${rest##* }
local comment=${rest% *}
print -r -- "${_km_cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${_km_reset}"
print -r -- "${_km_green}${_km_msg[label_file]}${_km_reset} $pubkey"
print -r -- "${_km_green}${_km_msg[label_type]}${_km_reset} ${keytype} (${bits} bits)"
print -r -- "${_km_green}${_km_msg[label_fingerprint]}${_km_reset} $fingerprint"
print -r -- "${_km_green}${_km_msg[label_comment]}${_km_reset} $comment"
print -r -- "${_km_green}${_km_msg[label_pubkey_content]}${_km_reset}"
cat "$pubkey"
echo ""
done
if [[ $found -eq 0 ]]; then
_km_warn "${_km_msg[no_ssh_keys_found]}"
fi
}
# keyman ssh copy [keyfile]
_km_ssh_copy() {
local pubkey="${1:-$HOME/.ssh/id_ed25519.pub}"
[[ "$pubkey" != *.pub ]] && pubkey="${pubkey}.pub"
if [[ ! -f "$pubkey" ]]; then
_km_err "${_km_msg[pubkey_not_found]}: $pubkey"
_km_info "${_km_msg[available_pubkeys]}"
ls "$HOME"/.ssh/*.pub 2>/dev/null || echo " ${_km_msg[none]}"
return 1
fi
local content=$(cat "$pubkey")
if _km_copy_to_clipboard "$content"; then
_km_ok "${_km_msg[pubkey_copied]}: $pubkey"
fi
}
# keyman ssh rm <keyfile>
_km_ssh_rm() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_ssh_rm]}"
return 1
fi
local keyfile="$1"
keyfile="${keyfile%.pub}"
if [[ ! -f "$keyfile" && ! -f "${keyfile}.pub" ]]; then
_km_err "${_km_msg[key_not_found]}: $keyfile"
return 1
fi
_km_warn "${_km_msg[about_to_delete]}"
[[ -f "$keyfile" ]] && echo " ${_km_msg[label_private_key]} $keyfile"
[[ -f "${keyfile}.pub" ]] && echo " ${_km_msg[label_public_key]} ${keyfile}.pub"
read -q "REPLY?${_km_msg[confirm_delete]}"
echo
if [[ "$REPLY" == "y" ]]; then
ssh-add -d "$keyfile" 2>/dev/null
[[ -f "$keyfile" ]] && rm -f "$keyfile"
[[ -f "${keyfile}.pub" ]] && rm -f "${keyfile}.pub"
_km_ok "${_km_msg[deleted]}"
else
_km_info "${_km_msg[cancelled]}"
fi
}
# =====================================================
# GPG Actions
# =====================================================
# keyman gpg new (interactive)
_km_gpg_new() {
gpg --full-generate-key
}
# keyman gpg quick-new "Name" "Email" [expiry]
_km_gpg_quick_new() {
if [[ -z "${1:-}" || -z "${2:-}" ]]; then
_km_err "${_km_msg[usage_gpg_quick_new]}"
return 1
fi
local name="$1"
local email="$2"
local expire="${3:-2y}"
if gpg --list-keys "$email" &>/dev/null; then
_km_warn "${_km_msg[email_has_gpg_key]}"
gpg --list-keys "$email"
read -q "REPLY?${_km_msg[confirm_create_new]}"
echo
[[ "$REPLY" != "y" ]] && return 1
fi
_km_info "${_km_msg[creating_gpg_key]}"
_km_info "${_km_msg[label_name]} $name"
_km_info "${_km_msg[label_email]} $email"
_km_info "${_km_msg[label_expiry]} $expire"
local _km_rc=0
gpg --batch --gen-key <<EOF || _km_rc=$?
Key-Type: eddsa
Key-Curve: ed25519
Subkey-Type: ecdh
Subkey-Curve: cv25519
Name-Real: ${name}
Name-Email: ${email}
Expire-Date: ${expire}
%ask-passphrase
%commit
EOF
if [[ $_km_rc -eq 0 ]]; then
_km_ok "${_km_msg[gpg_key_created]}"
echo ""
gpg --list-keys --keyid-format long "$email"
else
_km_err "${_km_msg[gpg_key_creation_failed]}"
return 1
fi
}
# keyman gpg ls [--secret|-s]
_km_gpg_ls() {
if [[ "$1" == "--secret" || "$1" == "-s" ]]; then
_km_info "${_km_msg[gpg_secret_key_list]}"
echo ""
gpg --list-secret-keys --keyid-format long
else
_km_info "${_km_msg[gpg_public_key_list]}"
echo ""
gpg --list-keys --keyid-format long
fi
}
# keyman gpg pub <email-or-KeyID>
_km_gpg_pub() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_pub]}"
return 1
fi
local key_id="$1"
if ! gpg --list-keys "$key_id" &>/dev/null; then
_km_err "${_km_msg[gpg_key_not_found]}: $key_id"
return 1
fi
_km_info "${_km_msg[gpg_public_key]} ($key_id):"
echo ""
gpg --armor --export "$key_id"
}
# keyman gpg priv <email-or-KeyID>
_km_gpg_priv() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_priv]}"
return 1
fi
local key_id="$1"
if ! gpg --list-secret-keys "$key_id" &>/dev/null; then
_km_err "${_km_msg[gpg_secret_not_found]}: $key_id"
return 1
fi
_km_warn "${_km_msg[warn_export_secret]}"
read -q "REPLY?${_km_msg[confirm_export]}"
echo
if [[ "$REPLY" == "y" ]]; then
gpg --armor --export-secret-keys "$key_id"
else
_km_info "${_km_msg[cancelled]}"
fi
}
# keyman gpg copy <email-or-KeyID>
_km_gpg_copy() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_copy]}"
return 1
fi
local key_id="$1"
if ! gpg --list-keys "$key_id" &>/dev/null; then
_km_err "${_km_msg[gpg_key_not_found]}: $key_id"
return 1
fi
local content=$(gpg --armor --export "$key_id")
if _km_copy_to_clipboard "$content"; then
_km_ok "${_km_msg[gpg_pubkey_copied]} ($key_id)"
fi
}
# keyman gpg fp <email-or-KeyID>
_km_gpg_fp() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_fp]}"
return 1
fi
gpg --fingerprint "$1"
}
# keyman gpg rm <email-or-KeyID>
_km_gpg_rm() {
if [[ -z "${1:-}" ]]; then
_km_err "${_km_msg[usage_gpg_rm]}"
return 1
fi
local key_id="$1"
_km_warn "${_km_msg[about_to_delete_gpg]}: $key_id"
_km_info "${_km_msg[key_info]}"
gpg --list-keys "$key_id" 2>/dev/null
echo ""
read -q "REPLY?${_km_msg[confirm_delete]}"
echo
if [[ "$REPLY" == "y" ]]; then
gpg --delete-secret-and-public-key "$key_id"
_km_ok "${_km_msg[deleted]}"
else
_km_info "${_km_msg[cancelled]}"
fi
}
# =====================================================
# Main dispatcher
# =====================================================
keyman() {
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: '
/^pub/ { keyid = $5 }
/^uid/ && keyid != "" {
uid = $10
if (uid != "") {
print keyid ":" uid
n = index(uid, "<")
if (n > 0) {
email = substr(uid, n + 1)
p = index(email, ">")
if (p > 0) email = substr(email, 1, p - 1)
if (email != "") print email ":" uid
}
keyid = ""
}
}
')"})
_describe 'GPG key ID or email' key_ids
;;
esac
;;
esac
;;
esac
;;
esac
}
compdef _keyman keyman