Last active
November 21, 2019 19:46
-
-
Save erichmachado/586eec1efdd9aade2edd945bd53bba91 to your computer and use it in GitHub Desktop.
Set Git/GitHub PGP signing key
This file contains 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 sh | |
# To test the script, set the GNUPGHOME to a temporary directory, e.g: | |
# $ export GNUPGHOME="$(mktemp -d)" | |
set -eu -o pipefail | |
DEPENDENCIES="gpg git" | |
EXPIRATION="${EXPIRATION:-6m}" | |
ALGORITHM="${ALGORITHM:-RSA}" | |
KEY_LENGTH="${KEY_LENGTH:-4096}" | |
function command_available() { | |
[ -x "$(command -v "$1")" ] | |
} | |
function check_dependency() { | |
if ! command_available "$1"; then | |
echo "Please, install '$1' and try again." && exit 1 | |
fi | |
} | |
function check_dependencies() { | |
for dependency in $DEPENDENCIES; do check_dependency $dependency; done | |
} | |
function downcase() { | |
echo "$1" | tr '[:upper:]' '[:lower:]' | |
} | |
function display_exported_keys_info() { | |
gpg --with-colons --import-options show-only --import | |
} | |
function list_user_keys() { | |
gpg --list-keys --with-colons "<$1>" 2> /dev/null || true | |
} | |
function filter_trusted_signing_keys() { | |
awk -v key_length="$1" -F: '{ if($1 == "sub" && $2 ~ /[fu]/ && $3 == key_length && $12 ~ /s/) print $5 }' | |
} | |
function filter_trusted_keys_ids() { | |
awk -v key_length="$1" -F: '{ if($1 == "pub" && $2 ~ /[fu]/ && $3 == key_length) print $5 }' | |
} | |
function filter_fingerprints() { | |
awk -F: '{ if($1 == "fpr") print $10 }' | |
} | |
function add_gpg_primary_key() { | |
gpg --quick-generate-key "$1 <$2>" $(downcase "$3")"$4" cert "$5" | |
} | |
function add_gpg_signing_subkey() { | |
gpg --quick-add-key "$1" $(downcase "$2")"$3" sign "$4" | |
} | |
function primary_key_id() { | |
list_user_keys "$1" | filter_trusted_keys_ids "$2" | tail -1 | |
} | |
function key_fingerprint() { | |
export_armored_gpg_key "$1" | display_exported_keys_info | filter_fingerprints | |
} | |
function export_armored_gpg_key() { | |
# Appending ! to the key ID instructs GPG to export only the key without its subkeys | |
export_armored_gpg_key_and_subkeys "$1!" | |
} | |
function export_armored_gpg_key_and_subkeys() { | |
gpg --armor --export "$1" | |
} | |
function get_gpg_signing_key_id() { | |
export_armored_gpg_key_and_subkeys "$1" | display_exported_keys_info | filter_trusted_signing_keys "$2" | tail -1 | |
} | |
function get_git_signing_key_id() { | |
git config --get --global user.signingkey | |
} | |
function set_git_signing_key_id() { | |
git config --replace-all --global user.signingkey "$1" | |
} | |
function get_git_commit_signing() { | |
git config --get --global commit.gpgsign | |
} | |
function set_git_commit_signing() { | |
git config --replace-all --global commit.gpgsign "$1" | |
} | |
function main() { | |
check_dependencies | |
local email | |
read -p "Please enter your email: " email | |
pk_id="$(primary_key_id "$email" "$KEY_LENGTH")" | |
if [ -z "$pk_id" ]; then | |
echo "User $email does not have a suitable primary key ($ALGORITHM $KEY_LENGTH). Creating a primary key now..." | |
local fullname | |
read -p "Please enter your full name: " fullname | |
local expiration | |
read -p "Set the key expiration (e.g: '2y' for 2 years, '60d' for 60 days, 'none' for no expiration; default: '$EXPIRATION'): " expiration | |
add_gpg_primary_key "$fullname" "$email" "$ALGORITHM" "$KEY_LENGTH" "${expiration:-$EXPIRATION}" | |
pk_id="$(primary_key_id "$email" "$KEY_LENGTH")" | |
fi | |
echo "Primary key ID: $pk_id" | |
sg_id="$(get_gpg_signing_key_id "$pk_id" "$KEY_LENGTH")" | |
if [ -z "$sg_id" ]; then | |
echo "User $email does not have a suitable signing subkey ($ALGORITHM $KEY_LENGTH). Creating a signing subkey now..." | |
local expiration | |
read -p "Set the key expiration (e.g: '2y' for 2 years, '60d' for 60 days, 'none' for no expiration; default: '$EXPIRATION'): " expiration | |
add_gpg_signing_subkey "$(key_fingerprint "$pk_id")" "$ALGORITHM" "$KEY_LENGTH" "${expiration:-$EXPIRATION}" | |
sg_id="$(get_gpg_signing_key_id "$pk_id" "$KEY_LENGTH")" | |
fi | |
echo "Signing key ID: $sg_id" | |
if [ "$(get_git_commit_signing)" != 'true' ]; then | |
local gpg_sign | |
read -p 'Your Git client is not set to sign commits. Do you want to set it to sign all commits by default? [Y/n] ' gpg_sign | |
case "$(downcase "$gpg_sign")" in | |
n*) echo 'Git client not set to sign commits.';; | |
*) set_git_commit_signing true;; | |
esac | |
fi | |
if [ -z "$(get_git_signing_key_id)" ]; then | |
local set_signing_key | |
read -p "Your Git client is not set to use a signing key. Do you want to set it to use $sg_id? [Y/n] " set_signing_key | |
case "$(downcase "$set_signing_key")" in | |
n*) echo 'Git client signing key not set.';; | |
*) set_git_signing_key_id "$sg_id";; | |
esac | |
elif [ "$(get_git_signing_key_id)" != "$sg_id" ]; then | |
local set_signing_key | |
read -p "Your Git client is using a different signing key. Do you want to set it to use $sg_id? [y/N] " set_signing_key | |
case "$(downcase "$set_signing_key")" in | |
y*) set_git_signing_key_id "$sg_id";; | |
*) echo 'Git client signing key not changed.';; | |
esac | |
fi | |
if [ "$(get_git_signing_key_id)" == "$sg_id" ]; then | |
echo "Git client signing key set to $sg_id. You're all set!\n" | |
if ! command_available pbcopy; then | |
echo "Please, copy the signing public key below and paste it to your profile on GitHub:\n" | |
export_armored_gpg_key "$sg_id" | |
else | |
export_armored_gpg_key "$sg_id" | pbcopy | |
echo 'Signing public key was copied to the pastebin. You should be able to paste it to your profile on GitHub now.' | |
fi | |
fi | |
} | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment