162 lines
4.0 KiB
Bash
Executable File
162 lines
4.0 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
umask 077
|
|
|
|
if [ "$#" -ne 2 ]; then
|
|
echo "Usage: $0 ENV_FILE VAPID_SUBJECT" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
|
env_file=$1
|
|
subject=$2
|
|
|
|
if [ ! -f "$env_file" ]; then
|
|
echo "Environment file does not exist: $env_file" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$(stat -c '%a' "$env_file")" != 600 ]; then
|
|
echo "Environment file must have mode 0600: $env_file" >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "$subject" in
|
|
mailto:?* | https://?*) ;;
|
|
*)
|
|
echo "VAPID_SUBJECT must be a non-empty mailto: or https:// URI without whitespace." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$subject" in
|
|
*'
|
|
'*)
|
|
echo "VAPID_SUBJECT must be a non-empty mailto: or https:// URI without whitespace." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if printf '%s' "$subject" | LC_ALL=C grep -q '[[:space:]]'; then
|
|
echo "VAPID_SUBJECT must be a non-empty mailto: or https:// URI without whitespace." >&2
|
|
exit 1
|
|
fi
|
|
|
|
for command in awk chmod date docker grep mktemp rm stat; do
|
|
if ! command -v "$command" >/dev/null 2>&1; then
|
|
echo "Required command is unavailable: $command" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
for key in \
|
|
WEB_PUSH_VAPID_PUBLIC_KEY \
|
|
WEB_PUSH_VAPID_PRIVATE_KEY \
|
|
WEB_PUSH_VAPID_SUBJECT; do
|
|
key_count=$(
|
|
awk -F= -v key="$key" '$1 == key { count++ } END { print count + 0 }' \
|
|
"$env_file"
|
|
)
|
|
if [ "$key_count" -ne 1 ]; then
|
|
echo "Environment must contain exactly one $key entry before VAPID generation." >&2
|
|
exit 1
|
|
fi
|
|
|
|
existing_value=$(
|
|
awk -F= -v key="$key" '
|
|
$1 == key {
|
|
print substr($0, index($0, "=") + 1)
|
|
exit
|
|
}
|
|
' "$env_file"
|
|
)
|
|
if [ -n "$existing_value" ]; then
|
|
echo "Refusing to rotate an existing VAPID identity: $key is already configured." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
unset existing_value
|
|
|
|
env_dir=$(CDPATH='' cd -- "$(dirname -- "$env_file")" && pwd)
|
|
temporary_dir=$(mktemp -d "$env_dir/.vapid-generation.XXXXXX")
|
|
chmod 700 "$temporary_dir"
|
|
raw_keys="$temporary_dir/generated.txt"
|
|
values_file="$temporary_dir/values.env"
|
|
generator_image=${WNH_VAPID_GENERATOR_IMAGE:-}
|
|
owned_image=false
|
|
run_id="$(date -u +%Y%m%d%H%M%S)-$$"
|
|
generator_container="wnh-vapid-tool-$run_id"
|
|
|
|
cleanup() {
|
|
trap - EXIT HUP INT TERM
|
|
rm -rf "$temporary_dir"
|
|
docker rm --force "$generator_container" >/dev/null 2>&1 || true
|
|
if [ "$owned_image" = true ]; then
|
|
docker image rm "$generator_image" >/dev/null 2>&1 || true
|
|
fi
|
|
}
|
|
|
|
cleanup_on_exit() {
|
|
exit_status=$?
|
|
cleanup
|
|
exit "$exit_status"
|
|
}
|
|
|
|
trap cleanup_on_exit EXIT
|
|
trap 'cleanup; exit 129' HUP
|
|
trap 'cleanup; exit 130' INT
|
|
trap 'cleanup; exit 143' TERM
|
|
|
|
if [ -z "$generator_image" ]; then
|
|
generator_image="who-need-help:vapid-tool-$run_id"
|
|
owned_image=true
|
|
docker build --quiet --target test --tag "$generator_image" "$ROOT" >/dev/null
|
|
fi
|
|
|
|
docker image inspect "$generator_image" >/dev/null
|
|
docker run --rm \
|
|
--name "$generator_container" \
|
|
--network none \
|
|
--read-only \
|
|
--tmpfs /tmp:rw,noexec,nosuid,size=16m \
|
|
--entrypoint mix \
|
|
"$generator_image" \
|
|
generate.vapid.keys >"$raw_keys"
|
|
chmod 600 "$raw_keys"
|
|
|
|
if ! awk -F'"' -v subject="$subject" '
|
|
/^[[:space:]]*vapid_private_key:/ {
|
|
private_count++
|
|
private_key = $2
|
|
}
|
|
/^[[:space:]]*vapid_public_key:/ {
|
|
public_count++
|
|
public_key = $2
|
|
}
|
|
END {
|
|
valid_private = private_key ~ /^[A-Za-z0-9_-]+$/
|
|
valid_public = public_key ~ /^[A-Za-z0-9_-]+$/
|
|
|
|
if (private_count != 1 ||
|
|
public_count != 1 ||
|
|
!valid_private ||
|
|
!valid_public ||
|
|
private_key == public_key) {
|
|
exit 40
|
|
}
|
|
|
|
print "WEB_PUSH_VAPID_PUBLIC_KEY=" public_key
|
|
print "WEB_PUSH_VAPID_PRIVATE_KEY=" private_key
|
|
print "WEB_PUSH_VAPID_SUBJECT=" subject
|
|
}
|
|
' "$raw_keys" >"$values_file"; then
|
|
echo "The pinned web_push_elixir generator returned an unexpected key format." >&2
|
|
exit 1
|
|
fi
|
|
chmod 600 "$values_file"
|
|
|
|
"$ROOT/scripts/set-env-values.sh" "$env_file" "$values_file" >/dev/null
|
|
|
|
echo "Generated a new environment-specific VAPID identity without printing its keys."
|
|
echo "Updated the single mode-0600 environment file: $env_file"
|