Last active
September 23, 2025 02:36
-
-
Save yanyaoer/63b40dc2ca9737286b34e89689fc5fa7 to your computer and use it in GitHub Desktop.
simple app/shortcuts/cli/password/otp luncher on macos
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# brew install choose-gui pass pass-otp fd | |
# https://github.com/chipsenkbeil/choose?tab=readme-ov-file#open-apps-from-the-applications-directories | |
# bindkey with .skhdrc | |
# ctrl + alt + shift + cmd - r : app-choose.sh | |
shopt -s nullglob globstar | |
CACHE_PREFIX="/tmp/.launcher_cache" | |
CACHE_DURATION=3600 | |
file_birthtime() { | |
stat -f %B "$1" 2>/dev/null || stat -c %Y "$1" 2>/dev/null | |
} | |
cache_run() { | |
local key="$1" | |
shift | |
local cache_file="${CACHE_PREFIX}_${key}" | |
if [[ -f $cache_file ]]; then | |
cat "$cache_file" | |
local created | |
created=$(file_birthtime "$cache_file" 2>/dev/null) | |
local now=$(date +%s) | |
if [[ ! $created =~ ^[0-9]+$ ]] || (( now - created >= CACHE_DURATION )); then | |
( | |
local tmp | |
tmp=$(mktemp "${cache_file}.XXXX") || exit 0 | |
if "$@" >"$tmp"; then | |
mv "$tmp" "$cache_file" | |
else | |
rm -f "$tmp" | |
fi | |
) >/dev/null 2>&1 & | |
fi | |
return | |
fi | |
local tmp | |
tmp=$(mktemp "${cache_file}.XXXX") || return 1 | |
if "$@" >"$tmp"; then | |
cat "$tmp" | |
mv "$tmp" "$cache_file" | |
else | |
rm -f "$tmp" | |
return 1 | |
fi | |
} | |
build_candidates() { | |
local dirs=( | |
/Applications/ | |
"$HOME"/Applications/ | |
/Applications/Utilities/ | |
/System/Applications/ | |
/System/Applications/Utilities/ | |
/System/Library/CoreServices/Applications/ | |
) | |
/opt/homebrew/bin/fd . "${dirs[@]}" -e app -d 1 --format '{/}' | |
if command -v /usr/bin/shortcuts >/dev/null 2>&1; then | |
/usr/bin/shortcuts list 2>/dev/null | sed 's/^/short-/' | |
fi | |
local store=${PASSWORD_STORE_DIR:-$HOME/.password-store} | |
if [[ -d $store ]]; then | |
/opt/homebrew/bin/fd . "$store" -e gpg --format 'pass {/}' 2>/dev/null | |
fi | |
} | |
get_candidates() { | |
cache_run candidates build_candidates | |
} | |
get_password_details() { | |
local password_name="$1" | |
local content=$(pass show "$password_name" 2>/dev/null) | |
local password=$(echo "$content" | head -n1) | |
local username=$(echo "$content" | grep -i "^user\|^login\|^email" | head -n1 | cut -d: -f2- | sed 's/^ *//') | |
# Check if OTP is available and cache the result | |
local otp_code="" | |
if echo "$content" | grep -q "otpauth://"; then | |
otp_code=$(pass otp "$password_name" 2>/dev/null) | |
fi | |
if [[ -n $username ]] && [[ -n $otp_code ]]; then | |
printf '%s (username)\n%s (password)\n%s (otp)\n' "$username" "$password" "$otp_code" | |
elif [[ -n $username ]]; then | |
printf '%s (username)\n%s (password)\n' "$username" "$password" | |
elif [[ -n $otp_code ]]; then | |
printf '%s (password)\n%s (otp)\n' "$password" "$otp_code" | |
else | |
printf '%s (password)\n' "$password" | |
fi | |
} | |
run_app() { | |
if [[ $1 == short-* ]]; then | |
/usr/bin/shortcuts run ${1#short-} | |
elif [[ $1 == *.app ]]; then | |
open -a "$1" | |
else | |
# run as shell if not match app and password | |
export PATH="$HOME/bin/:$PATH" | |
eval "$1" | |
fi | |
} | |
run_pass() { | |
local password_name="$1" | |
# Get password details and let user choose | |
details=$(get_password_details "$password_name") | |
if [[ -n $details ]]; then | |
chosen_detail=$(echo "$details" | choose -m) | |
if [[ $chosen_detail == *"(username)" ]]; then | |
echo "${chosen_detail% (username)}" | pbcopy | |
echo "Username copied to clipboard" | |
elif [[ $chosen_detail == *"(password)" ]]; then | |
echo "${chosen_detail% (password)}" | pbcopy | |
echo "Password copied to clipboard" | |
elif [[ $chosen_detail == *"(otp)" ]]; then | |
echo "${chosen_detail% (otp)}" | pbcopy | |
echo "OTP copied to clipboard" | |
fi | |
else | |
# Fallback to just copying password | |
pass show -c "$password_name" 2>/dev/null | |
fi | |
} | |
main() { | |
while true; do | |
selection=$(get_candidates | choose -m) | |
[[ -n $selection ]] || exit | |
if [[ $selection == pass* ]]; then | |
password_name="${selection#pass }" | |
run_pass "$password_name" | |
break | |
else | |
run_app "$selection" | |
break | |
fi | |
done | |
} | |
main "$@" |
Author
yanyaoer
commented
Sep 2, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment