60 lines
1.4 KiB
Shell
60 lines
1.4 KiB
Shell
|
|
#!/bin/sh
|
||
|
|
|
||
|
|
# Generate security.txt (RFC 9116), clearsigned with the [S] subkey
|
||
|
|
#
|
||
|
|
# Usage: ./scripts/security-txt.sh
|
||
|
|
#
|
||
|
|
# Expires is read from the key, so the January ceremony only re-runs this
|
||
|
|
# after the key's expiry was extended
|
||
|
|
|
||
|
|
set -eu
|
||
|
|
|
||
|
|
|
||
|
|
# Internal [S] subkey; pinned with "!" below so `gpg` never picks another subkey
|
||
|
|
SIGNING_KEY='D6D1989DF1F6B23FD776293DB46EDB4DFC26805D'
|
||
|
|
|
||
|
|
|
||
|
|
REPO=$(cd "$(dirname "$0")/.." && pwd)
|
||
|
|
OUT="$REPO/security.txt"
|
||
|
|
|
||
|
|
|
||
|
|
# Notes:
|
||
|
|
# - the 7th field of the pub line is the primary key's expiry in epoch seconds
|
||
|
|
# - a subkey resolves to the primary key
|
||
|
|
EPOCH=$(gpg --list-keys --with-colons "$SIGNING_KEY" \
|
||
|
|
| awk -F: '$1 == "pub" { print $7; exit }')
|
||
|
|
if [ -z "$EPOCH" ]; then
|
||
|
|
echo "Error: No expiry found for key $SIGNING_KEY" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
EXPIRES=$(date -u -d "@$EPOCH" +%Y-%m-%dT%H:%M:%SZ)
|
||
|
|
|
||
|
|
|
||
|
|
UNSIGNED=$(mktemp)
|
||
|
|
trap 'rm -f "$UNSIGNED"' EXIT
|
||
|
|
|
||
|
|
|
||
|
|
cat > "$UNSIGNED" <<EOT
|
||
|
|
Canonical: https://www.alexander-hess.com/.well-known/security.txt
|
||
|
|
Canonical: https://www.webartifex.de/.well-known/security.txt
|
||
|
|
Contact: mailto:ah@alexander-hess.com
|
||
|
|
Contact: mailto:alexander@webartifex.de
|
||
|
|
Encryption: https://www.alexander-hess.com/public-key.asc
|
||
|
|
Encryption: https://www.webartifex.de/public-key.asc
|
||
|
|
Expires: $EXPIRES
|
||
|
|
Preferred-Languages: en, de
|
||
|
|
EOT
|
||
|
|
|
||
|
|
|
||
|
|
gpg \
|
||
|
|
--clearsign \
|
||
|
|
--digest-algo SHA512 \
|
||
|
|
--local-user "${SIGNING_KEY}!" \
|
||
|
|
--yes \
|
||
|
|
--output "$OUT" \
|
||
|
|
"$UNSIGNED"
|
||
|
|
|
||
|
|
gpg --verify "$OUT"
|
||
|
|
|
||
|
|
|
||
|
|
echo "Wrote security.txt (Expires: $EXPIRES)"
|