Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
100 lines
2.8 KiB
Bash
Executable File
100 lines
2.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# omarchy:summary=Store, read, or delete AI provider API keys
|
|
# omarchy:args=<set|get|rm> <provider>
|
|
# omarchy:examples=omarchycn ai secret set deepseek | omarchycn ai secret get deepseek
|
|
|
|
set -euo pipefail
|
|
|
|
action="${1:?usage: omarchycn ai secret <set|get|rm> <provider>}"
|
|
provider="${2:?usage: omarchycn ai secret <set|get|rm> <provider>}"
|
|
|
|
if [[ ! $provider =~ ^[a-z0-9-]+$ ]]; then
|
|
echo "Invalid provider name: $provider" >&2
|
|
exit 1
|
|
fi
|
|
|
|
FILE_DIR="$HOME/.local/state/omarchycn/secrets"
|
|
FILE_PATH="$FILE_DIR/$provider"
|
|
|
|
secret_service_ok() {
|
|
command -v secret-tool > /dev/null 2>&1 && secret-tool search service omarchycn > /dev/null 2>&1
|
|
}
|
|
|
|
pass_ok() {
|
|
command -v pass > /dev/null 2>&1 && pass ls > /dev/null 2>&1
|
|
}
|
|
|
|
case "$action" in
|
|
set)
|
|
if [[ -t 0 ]]; then
|
|
read -rs -p "API key for $provider: " key
|
|
echo
|
|
else
|
|
IFS= read -r key || true
|
|
fi
|
|
if [[ -z $key ]]; then
|
|
echo "Empty key refused" >&2
|
|
exit 1
|
|
fi
|
|
if secret_service_ok; then
|
|
printf '%s' "$key" | secret-tool store --label "OmarchyCN AI: $provider" service omarchycn key "ai/$provider"
|
|
# Purge stale copies in lower-priority backends so get never falls
|
|
# through to an outdated key
|
|
if pass_ok; then
|
|
pass rm -f "omarchycn/ai/$provider" > /dev/null 2>&1 || true
|
|
fi
|
|
rm -f "$FILE_PATH"
|
|
echo "Stored in Secret Service (secret-tool)"
|
|
elif pass_ok; then
|
|
printf '%s\n' "$key" | pass insert -m -f "omarchycn/ai/$provider" > /dev/null
|
|
rm -f "$FILE_PATH"
|
|
echo "Stored in pass (omarchycn/ai/$provider)"
|
|
else
|
|
mkdir -p "$FILE_DIR"
|
|
chmod 700 "$FILE_DIR"
|
|
rm -f "$FILE_PATH"
|
|
(umask 177 && printf '%s' "$key" > "$FILE_PATH")
|
|
echo "Stored in $FILE_PATH (0600 file fallback — 安装 libsecret 或 pass 可获得更安全的存储)"
|
|
fi
|
|
;;
|
|
get)
|
|
if secret_service_ok && secret-tool lookup service omarchycn key "ai/$provider" 2>/dev/null; then
|
|
exit 0
|
|
fi
|
|
if pass_ok && pass show "omarchycn/ai/$provider" 2>/dev/null; then
|
|
exit 0
|
|
fi
|
|
if [[ -f $FILE_PATH ]]; then
|
|
cat "$FILE_PATH"
|
|
exit 0
|
|
fi
|
|
echo "No secret stored for $provider (run: omarchycn ai secret set $provider)" >&2
|
|
exit 1
|
|
;;
|
|
rm)
|
|
removed=0
|
|
if secret_service_ok && secret-tool clear service omarchycn key "ai/$provider" 2>/dev/null; then
|
|
removed=1
|
|
fi
|
|
if pass_ok && pass rm -f "omarchycn/ai/$provider" > /dev/null 2>&1; then
|
|
removed=1
|
|
fi
|
|
if [[ -f $FILE_PATH ]]; then
|
|
rm -f "$FILE_PATH"
|
|
removed=1
|
|
fi
|
|
if command -v secret-tool > /dev/null 2>&1 && ! secret_service_ok; then
|
|
echo "警告: Secret Service 当前不可达,其中的副本(如有)未被清除" >&2
|
|
fi
|
|
if (( removed == 0 )); then
|
|
echo "No secret stored for $provider" >&2
|
|
exit 1
|
|
fi
|
|
echo "Secret for $provider removed"
|
|
;;
|
|
*)
|
|
echo "Unknown action: $action (expected set, get, or rm)" >&2
|
|
exit 1
|
|
;;
|
|
esac
|