#!/bin/bash
# One-time: create the FIDO2 hmac-secret credential on the YubiKey that
# yubikey-keyring-reset and yubikey-keyring-unlock use. Needs the FIDO2 PIN and
# a touch. Then run yubikey-keyring-reset to store the keyring password.
# Refuses to replace an existing credential unless given --force, because a new
# credential makes the stored password undecryptable until reset is re-run.
set -euo pipefail
. "$HOME/.local/lib/yubikey-keyring.sh"   # DIR, RP, yk_device
if [[ -s $DIR/cred_id && ${1:-} != --force ]]; then
  echo "a credential already exists in $DIR; use --force to replace it (then re-run yubikey-keyring-reset)"
  exit 1
fi
mkdir -p "$DIR"; chmod 700 "$DIR"
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT

dev=$(yk_device)
[[ -n $dev ]] || { echo "no YubiKey found"; exit 1; }
echo "device: $dev"

# fido2-cred reads the PIN from a tty only, so run it under a pty wrapper and
# feed the PIN from a dialog.
pin=$(zenity --password --title="YubiKey PIN" --text="Enter your YubiKey FIDO2 PIN (to create the keyring credential)")
{ head -c32 /dev/urandom | base64 -w0; echo
  echo "$RP"
  echo "$USER"
  head -c32 /dev/urandom | base64 -w0; echo; } > "$tmp/cred_in"
notify-send -t 20000 "Touch your YubiKey" "creating keyring credential" 2>/dev/null || true
printf '%s\n' "$pin" | timeout 40 "$HOME/.local/bin/fido2-with-pin" \
  fido2-cred -M -h -i "$tmp/cred_in" -o "$tmp/cred_out" "$dev" es256 >/dev/null 2>&1 || true
unset pin
[[ -s $tmp/cred_out ]] || { echo "credential creation failed (wrong PIN or no touch?)"; exit 1; }
fido2-cred -V -h -i "$tmp/cred_out" -o "$tmp/cred" es256
head -n1 "$tmp/cred" > "$DIR/cred_id"
head -c32 /dev/urandom | base64 -w0 > "$DIR/salt"; echo >> "$DIR/salt"
chmod 600 "$DIR"/cred_id "$DIR"/salt
echo "credential created; now run yubikey-keyring-reset"
