packages: add git-crypt-rm-gpg-user
Source: https://gist.github.com/Falkor/7b29f16f5f79404fe41476be0d992783
This commit is contained in:
parent
c783e9d20a
commit
eb5c12da4b
3 changed files with 238 additions and 0 deletions
|
@ -49,6 +49,10 @@ in
|
|||
];
|
||||
|
||||
home.stateVersion = config.system.stateVersion;
|
||||
|
||||
home.packages = [
|
||||
(pkgs.callPackage ../../../packages/git-crypt-rm-gpg-user { })
|
||||
];
|
||||
};
|
||||
|
||||
nix.settings.trusted-users = lib.mkAfter [ "jan" ];
|
||||
|
|
5
packages/git-crypt-rm-gpg-user/default.nix
Normal file
5
packages/git-crypt-rm-gpg-user/default.nix
Normal file
|
@ -0,0 +1,5 @@
|
|||
{ writeScriptBin }:
|
||||
|
||||
writeScriptBin
|
||||
"git-crypt-rm-gpg-user"
|
||||
(builtins.readFile ./git-crypt-rm-gpg-user.sh)
|
229
packages/git-crypt-rm-gpg-user/git-crypt-rm-gpg-user.sh
Normal file
229
packages/git-crypt-rm-gpg-user/git-crypt-rm-gpg-user.sh
Normal file
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Script to remove GPG user (recipient) with git-crypt
|
||||
#
|
||||
# It will re-initialize git-crypt for the repository and re-add all keys except
|
||||
# the one requested for removal.
|
||||
#
|
||||
# Note: You still need to change all your secrets to fully protect yourself.
|
||||
# Removing a user will prevent them from reading future changes but they will
|
||||
# still have a copy of the data up to the point of their removal.
|
||||
#
|
||||
# Usage: see 'git-crypt-rm-gpg-user.sh -h'
|
||||
# git-crypt-rm-gpg-user.sh -l : list GPG keys configured within git-crypt for the current directory
|
||||
# git-crypt-rm-gpg-user.sh -r <FULL-GPG-FINGERPRINT> : remove specified key from git-crypt configuration
|
||||
# Ex: remove-gpg-user.sh -r 3BC18383F838C0B815B961480F8CAF5467D
|
||||
#
|
||||
# Typical workflow (assuming the script is placed in ~/bin/) :
|
||||
#
|
||||
# cd /path/to/protected/repo
|
||||
# git checkout -b git-crypt-remove
|
||||
# git-crypt-rm-gpg-user.sh -l # List configured GPG keys
|
||||
# git-crypt-rm-gpg-user.sh -r <KEYID>
|
||||
# git push origin git-crypt-remove # publish the branch
|
||||
#
|
||||
# Merge (sync with your collaborators for the appropriate timing):
|
||||
# git checkout master # or devel or whatever main branch
|
||||
# git-crypt lock
|
||||
# git merge git-crypt-remove
|
||||
# # release the repository
|
||||
#
|
||||
# Pulling for your collaborators
|
||||
# cd /path/to/protected/repo
|
||||
# git-crypt lock
|
||||
# git pull origin
|
||||
#
|
||||
# You can check the full, 64-bit (8-byte) key ID for a key within your keyring with
|
||||
# gpg -k [email | pattern]
|
||||
# gpg -k --with-colons [email | pattern | id] | awk -F: '/^pub:/ { print $5 }'
|
||||
# See https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
|
||||
#
|
||||
# The script will create multiple commits to your repo. Feel free to squash them
|
||||
# all down to one.
|
||||
#
|
||||
# Based on https://github.com/AGWA/git-crypt/issues/47#issuecomment-212734882
|
||||
#
|
||||
#
|
||||
# GIST source https://gist.github.com/glogiotatidis/e0ab45ed5575a9d7973390dace0552b0
|
||||
# amended to work on Mac OS and with cosmetic changes for a more convenient interface in
|
||||
# https://gist.github.com/Falkor/7b29f16f5f79404fe41476be0d992783
|
||||
# Script is now shellcheck compliant and safer: https://gist.github.com/thomsh/ed14fa82cf43a6b283c1eea9574fb76e
|
||||
#################
|
||||
set -eo pipefail
|
||||
|
||||
KEY_TO_REMOVE=
|
||||
KEY_FINGERPRINT=
|
||||
# CMD_PREFIX=
|
||||
|
||||
# HELPERS
|
||||
print_error_and_exit () {
|
||||
echo "*** ERROR *** $*"
|
||||
echo "Usage: see '$(basename $0) -h'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
really_continue() {
|
||||
echo "/!\\ WARNING: $*"
|
||||
echo "Are you sure you want to continue? [Y|n]"
|
||||
read -r ans
|
||||
case $ans in
|
||||
n*|N*) exit 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
print_usage () {
|
||||
cat <<EOF
|
||||
$(basename $0): Remove a given GPG key from a git-crypt enabled repository.
|
||||
|
||||
Options:
|
||||
-l : list GPG keys configured within git-crypt
|
||||
[-n] -r <FULL-GPG-FINGERPRINT> : remove key from git-crypt configuration
|
||||
|
||||
Typical workflow:
|
||||
|
||||
cd /path/to/protected/repo
|
||||
git checkout -b git-crypt-remove
|
||||
$(basename $0) -l # List configured GPG keys
|
||||
$(basename $0) -r <KEYID>
|
||||
|
||||
You can check the full, 64-bit (8-byte) key ID for a key within your keyring with
|
||||
gpg -k [email | pattern]
|
||||
gpg -k --with-colons [email | pattern | id] | awk -F: '/^pub:/ { print \$5 }'
|
||||
|
||||
See https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
|
||||
EOF
|
||||
}
|
||||
|
||||
###
|
||||
# Print info for a given key from your keyring
|
||||
##
|
||||
print_key_info() {
|
||||
[ -z "${1:-}" ] && print_error_and_exit "${FUNCNAME[0]} missing text argument"
|
||||
local key
|
||||
local gpgid
|
||||
local fpr
|
||||
key="$1"
|
||||
gpgid="$(gpg --list-keys --with-colons "${key}" | awk -F: '/^pub:/ { print $5 }')"
|
||||
fpr="$(gpg -k --with-colons "${key}" | awk -F: '/^fpr:/ { print $10; exit; }')" # Only first fpr
|
||||
echo "==== Key Fingerprint: ${fpr} ==="
|
||||
echo "==== Long GPG ID: ${gpgid}"
|
||||
gpg --list-key "$key" || print_error_and_exit "Couldn't find info about $key"
|
||||
export KEY_FINGERPRINT="$fpr"
|
||||
}
|
||||
|
||||
###
|
||||
# List GPG keys configured for protecting this repository
|
||||
##
|
||||
list_git_crypt_keys() {
|
||||
for f in .git-crypt/keys/default/0/*.gpg; do
|
||||
# key="$(basename "${f}" .gpg)"
|
||||
print_key_info "$(basename "${f}" .gpg)"
|
||||
# gpgid=$(gpg --list-keys --with-colons $key | awk -F: '/^pub:/ { print $5 }')
|
||||
# echo "==== Key Fingerprint: ${key} ==="
|
||||
# echo "==== Long GPG ID: ${gpgid}"
|
||||
# gpg --list-key "$key" || print_error_and_exit "Couldn't find info about $key"
|
||||
done
|
||||
}
|
||||
|
||||
##### Let's go #####
|
||||
# Check for options
|
||||
while [ $# -ge 1 ]; do
|
||||
case $1 in
|
||||
-h | --help) print_usage; exit 0;;
|
||||
-l | --list) list_git_crypt_keys; exit 0;;
|
||||
-r | --remove) shift; KEY_TO_REMOVE=$1;;
|
||||
# -n | --dry-run) CMD_PREFIX=echo ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${KEY_TO_REMOVE:-}" ];then
|
||||
print_error_and_exit "No key to remove has been indicated"
|
||||
fi
|
||||
|
||||
print_key_info "${KEY_TO_REMOVE}"
|
||||
|
||||
if [ -z "${KEY_FINGERPRINT:-}" ]; then
|
||||
print_error_and_exit "Unable to retrieve key fingerprint"
|
||||
fi
|
||||
|
||||
if [ -z "$(command -v rsync)" ]; then
|
||||
print_error_and_exit "This script use rsync, sadly rsync is not found on your system"
|
||||
fi
|
||||
|
||||
really_continue "About to remove the GPG Key ID ${KEY_TO_REMOVE} from Git-crypt configuration"
|
||||
|
||||
set -x # enable debug just in case we need to dig
|
||||
set -euo pipefail # enforce mode with nounset (-u)
|
||||
|
||||
# Below code adapted from @glogiotatidis - https://gist.github.com/glogiotatidis/e0ab45ed5575a9d7973390dace0552b0
|
||||
TMPDIR="$(mktemp -d)"
|
||||
CURRENT_DIR="$(git rev-parse --show-toplevel)"
|
||||
BASENAME="$(basename "$(pwd)")"
|
||||
TMPFILE=list-encrypted-files.txt
|
||||
|
||||
cat <<EOF
|
||||
TMPDIR=${TMPDIR}
|
||||
CURRENT_DIR=${CURRENT_DIR}
|
||||
EOF
|
||||
# Unlock the directory, we need to copy encrypted versions of the files
|
||||
git crypt unlock
|
||||
|
||||
# Work on copy.
|
||||
cp -a -- "$(pwd)" "$TMPDIR"
|
||||
|
||||
pushd "$TMPDIR/$BASENAME"
|
||||
git stash # stash potential typechange
|
||||
|
||||
# Remove encrypted files and git-crypt
|
||||
git crypt status -e |sed -E 's/^\s+encrypted: //g' > "${TMPFILE}"
|
||||
if [ -s "${TMPFILE}" ]; then
|
||||
awk '{print $2}' ${TMPFILE} | xargs rm
|
||||
#xargs -I {} -- rm -- {} < "${TMPFILE}"
|
||||
git commit -a -m "Remove encrypted files"
|
||||
fi
|
||||
rm -rf -- .git-crypt
|
||||
git commit -m "Remove git-crypt (in particular configuration related to key ${KEY_TO_REMOVE})" .git-crypt
|
||||
rm -rf .git/git-crypt
|
||||
|
||||
# Re-initialize git crypt
|
||||
git crypt init
|
||||
|
||||
# Add existing users, except the key to remove
|
||||
find "${CURRENT_DIR}/.git-crypt/keys/default/0" -type f -iname '*gpg' -print|while read -r keyfilename
|
||||
do
|
||||
basename="$(basename "$keyfilename")"
|
||||
key="${basename%.*}"
|
||||
if [[ "$key" == "$KEY_FINGERPRINT" ]]; then
|
||||
echo "ignoring key ${KEY_FINGERPRINT} to be removed"
|
||||
continue
|
||||
fi
|
||||
# check if the key is expired - second field is 'e'
|
||||
# See https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
|
||||
expired="$(gpg --with-colons --list-keys --with-fingerprint "$key" | awk -F: '/^pub:/ { print $2; }')"
|
||||
if [[ "${expired}" == "e" ]]; then
|
||||
echo "/!\\ WARNING: key $key expired thus not integrated in the git-crypt keyring"
|
||||
echo "/!\\ WARNING: key details: "
|
||||
print_key_info "$key"
|
||||
continue
|
||||
fi
|
||||
git crypt add-gpg-user "$key"
|
||||
done
|
||||
|
||||
cd "${CURRENT_DIR}"
|
||||
for encrypted_file in $(awk '{print $2}' ${TMPDIR}/${BASENAME}/${TMPFILE}); do
|
||||
rsync -rp -R "${encrypted_file}" "${TMPDIR}/${BASENAME}"
|
||||
done
|
||||
|
||||
cd "${TMPDIR}/${BASENAME}"
|
||||
for encrypted_file in $(awk '{print $2}' ${TMPFILE}); do
|
||||
git add "${encrypted_file}"
|
||||
done
|
||||
|
||||
git commit -m "New encrypted files" || true
|
||||
popd
|
||||
|
||||
git crypt lock
|
||||
git pull "${TMPDIR}/${BASENAME}"
|
||||
|
||||
rm -rf -- "${TMPDIR}"
|
Loading…
Reference in a new issue