1
0
Fork 0
dotfiles/common/.config/git/gpg-fallback-keys

67 lines
2.4 KiB
Bash
Executable File

#!/bin/bash
# This is a small wrapper script for gpg intended to be used by git
# As far as I can tell, git cannot automatically pick a fallback signing key by itself
# Setting GIT_SIGN_FALLBACK_KEY_IDS="config" or leaving it unset will make the program try all keys listed by git config
# Setting GIT_SIGN_FALLBACK_KEY_IDS="all" will make the program try all keys listed by gpg
# Setting the fallback keys manually can be done like this: GIT_SIGN_FALLBACK_KEY_IDS="<key id 1> <key id 2>"
# This script was written in about two hours, if you find any bugs, tell Luca!
set -eu
# A quick and dirty array filtering function
function reject {
predicate=$1
shift
for el in "$@"; do
if ! eval ":() { [[ $predicate ]]; }; : '$el'"; then
echo "$el"
fi
done
}
case "$*" in
# Git is trying to sign a commit
*-bsau*)
# The key passed by git
primary_key=$(echo "$*" | grep -oP '(?<=-bsau )[A-Z0-9]{16}')
# Select fallback keys based on config
case "${GIT_SIGN_FALLBACK_KEY_IDS:-}" in
"" | "config")
mapfile -t signing_keys < <(git config --get-all user.signingKey)
mapfile -t fallback_keys < <(reject "\$1 == $primary_key" "${signing_keys[@]}")
;;
"all")
mapfile -t signing_keys < <(gpg --list-keys --with-colons | awk -F: '/^pub:/ {print $5}')
mapfile -t fallback_keys < <(reject "\$1 == $primary_key" "${signing_keys[@]}")
;;
*)
mapfile -t fallback_keys < <(echo "$GIT_SIGN_FALLBACK_KEY_IDS" | xargs -n 1)
;;
esac
# Number of signing keys
n_keys=$(($(echo "${fallback_keys[*]}" | wc -w) + 1))
# Unaccounted for gpg flags
mapfile -t extra_flags < <(reject "\$1 == -bsau || \$1 == --status-fd=2 || \$1 == $primary_key" "$@")
gpg_flags=("${extra_flags[@]}" --status-fd=2 -bsau)
# Try signing with the primary key first, then try the fallback keys
counter=0
try_key=$primary_key
while
[ "$counter" -lt "$n_keys" ] &&
! gpg "${gpg_flags[@]}" "$try_key"
do
try_key="${fallback_keys[$counter - 1]}"
counter=$((counter + 1))
done
;;
# Git is trying to do something else, so we just pass the flags through
*) gpg "$@" ;;
esac