#!/bin/bash

# Copyright (c) 2014 Gunnar Wolf <gwolf@debian.org>,
#      Based on 2008 Jonathan McDowell <noodles@earth.li>
# GNU GPL; v2 or later
# Replaces an existing key with a new one in its same keyring directory

set -e

if [ -z "$1" ] || [ -z "$2" ]; then
	echo "Usage: replace-key oldkeyid newkeyid" >&2
	exit 1
fi

scriptdir=`dirname $0`
oldkey=$1
newkey=$2

# avoid gnupg touching ~/.gnupg
GNUPGHOME=$(mktemp -d -t jetring.XXXXXXXX)
export GNUPGHOME
cat  > "$GNUPGHOME"/gpg.conf <<EOF
keyid-format 0xlong
keyserver pgpkeys.eu
no-autostart
EOF
trap cleanup exit
cleanup () {
	rm -rf "$GNUPGHOME"
}

newkeytemp=`mktemp -t newkey.XXXXXXXXX`
gpgconf --launch dirmngr
gpg --recv-key "$newkey"
gpg --no-auto-check-trustdb --options /dev/null \
	--keyring output/keyrings/debian-keyring.pgp \
	--keyring output/keyrings/debian-nonupload.pgp \
	--keyring output/keyrings/debian-maintainers.pgp \
	--export-options export-clean,no-export-attributes \
	--export "$newkey" > $newkeytemp

# strip leading 0x from fingerprints
oldkey=${oldkey##0x}
newkey=${newkey##0x}

if [ $(echo -n $oldkey|wc -c) -eq 16 ]; then
    key='0x'$(echo $oldkey|tr a-z A-Z)
elif [ $(echo -n $oldkey|wc -c) -eq 40 ] ; then
    key='0x'$(echo -n $oldkey | cut -b 25-)
else
    echo "Please supply either a long keyid or a full fingerprint for the old key."
    exit 1
fi

for dir in *-pgp/; do
    if [ -f $dir/$key ]; then
	oldkeyfile=$(readlink -f "$dir/$key")
	keydir=$(readlink -f $dir)
	keyring=`basename $keydir`
	break
    fi
done

if [ -z "$oldkeyfile" -o -z "$keydir" ]; then
    echo "Requested key '$oldkey' not found (looked for '*-pgp/$key')"
    exit 1
fi

oldkeyfp=$(gpg --with-colons --fingerprint --no-auto-check-trustdb --no-default-keyring --keyring $oldkeyfile| grep '^fpr' | cut -d : -f 10)
newkeyfp=$(gpg --with-colons --fingerprint --no-auto-check-trustdb --no-default-keyring --keyring $newkeytemp| grep '^fpr' | cut -d : -f 10)

oldkeydata=$(gpg --with-colons --keyid long --options /dev/null --no-auto-check-trustdb < $oldkeyfile|grep '^pub')
newkeydata=$(gpg --with-colons --keyid long --options /dev/null --no-auto-check-trustdb < $newkeytemp|grep '^pub')
oldkeyuser=$(echo $oldkeydata | cut -d : -f 10)
newkeyuser=$(echo $newkeydata | cut -d : -f 10)
oldkeylen=$(echo $oldkeydata | cut -d : -f 3)
newkeylen=$(echo $newkeydata | cut -d : -f 3)
oldkeyalg=$(echo $oldkeydata | cut -d : -f 4)
if [ "$oldkeyalg" == "1" ]; then
    oldkeyalg='R'
elif [ "$oldkeyalg" == "17" ]; then
    oldkeyalg='D'
elif [ "$oldkeyalg" == "22" ]; then
    oldkeyalg='E'
else
    oldkeyalg='UNK'
fi
newkeyalg=$(echo $newkeydata | cut -d : -f 4)
if [ "$newkeyalg" == "1" ]; then
    newkeyalg='R'
elif [ "$newkeyalg" == "17" ]; then
    newkeyalg='D'
elif [ "$oldkeyalg" == "22" ]; then
    oldkeyalg='E'
else
    newkeyalg='UNK'
fi
echo $oldkeydata

echo ""
echo "About to replace key $oldkey ($oldkeyuser)"
echo "   with NEW key $newkey ($newkeyuser)"
echo "   in the $keyring keyring."
echo "Are you sure you want to update this key? (y/n)"
read n

if [ "x$n" = "xy" -o "x$n" = "xY" ]; then
    destkeyring="$keyring"
    if ! $scriptdir/add-key $newkeytemp $destkeyring ; then
        echo "add-key failed"
        exit 1
    fi

    if [ "$keyring" = "debian-keyring-pgp" -o "$keyring" = "debian-nonupload-pgp" ]; then
	name=`grep $newkey keyids | sed 's/^[^ ]* //'|sed s/\<.*//`
	account=`grep $newkey keyids | sed 's/.*\<//'|sed s/\>$//`
	if [ "$keyring" = "debian-nonupload-pgp" ]; then
	    role='DD-NU'
	else
	    role='DD'
	fi
    elif [ "$keyring" = "debian-maintainers-pgp" ]; then
	echo -n "Enter full name of new key: "
	read name
	role='DM'
    else
	echo "*** Key to be replaced is of a strange type (not DD, NonUplDD, DM)"
	echo "    Be sure you are doing the right thing before committing. Double-check"
	echo "    the log message, as it will most likely not be correct."
	name="Unknown"
    fi
    echo -n 'RT issue ID this change closes, if any: '
    read rtid
    name=$(echo $name | sed -r 's/^ *(.*) *$/\1/')

    log="Replace 0x$oldkey with 0x$newkey ($name) (RT #$rtid)"

    git rm $oldkeyfile
    VERSION=$(head -1 debian/changelog | awk '{print $2}' | sed 's/[\(\)]//g')
    RELEASE=$(head -1 debian/changelog | awk '{print $3}' | sed 's/;$//')
    case $RELEASE in
	UNRELEASED)
	    dch  --multimaint-merge -D UNRELEASED -a "$log"
	    ;;
	unstable)
	    NEWVER=$(date +%Y.%m.xx)
	    if [ "$VERSION" = "$NEWVER" ]
	    then
		echo '* Warning: New version and previous released version are'
		echo "  the same: $VERSION. This should not be so!"
		echo '  Check debian/changelog'
	    fi
	    dch -D UNRELEASED -v $NEWVER "$log"
	    ;;
	*)
	    echo "Last release $VERSION for unknown distribution «$RELEASE»."
	    echo "Not calling dch, do it manually."
	    ;;
    esac
    git add debian/changelog

    cat > git-commit-template <<EOF
$log

Action: replace
Subject: $name
Username: $account
Role: $role
Old-key: $oldkeyfp
Old-key-type: $oldkeylen$oldkeyalg
New-key: $newkeyfp
New-key-type: $newkeylen$newkeyalg
RT-Ticket: $rtid
Request-signed-by: \$oldkey
New-key-certified-by: \$oldkey,
EOF

fi
