#!/bin/sh
# WardenKey Linux sign-in helper (Linux), the counterpart of the Windows Hello key.
#
# pkexec runs this as root, and only after polkit has asked the user to prove who they are (fingerprint through fprintd, or their
# account password, whatever the system's PAM setup uses). The key it hands back lives in a root-only file, so a program running as
# the user cannot read it without passing that same prompt, just as a Windows Hello key cannot sign without a Hello prompt.
#
# It must be installed root-owned at /usr/lib/wardenkey/wardenkey-auth (the .deb does this; Settings > Unlock methods offers it
# for other installs). The polkit policy com.wardenkey.auth.policy names that exact path.
#
#   verify  prints RESULT:Verified           (the "gate" style and passkey checks: the prompt itself is the check)
#   create [id]  makes a new random key, prints SIG:<base64>
#   open [id]    prints SIG:<base64>, or STATUS:NotFound if no key was ever created for this user
#
# `id` names one WardenKey installation (the app derives it from its data folder), so a second vault or data folder of the same user
# can never replace the key of the first. Without an id the single legacy key (vault.key) is used, as in older versions; `open id` falls
# back to that legacy key when no key exists for the id yet, so vaults enrolled before this change keep opening until they are re-enrolled.
# helper format version: 2
set -eu
umask 077
PATH=/usr/sbin:/usr/bin:/sbin:/bin
export PATH

uid="${PKEXEC_UID:-}"
case "$uid" in
  ''|*[!0-9]*) echo 'ERROR:must be started by pkexec'; exit 2 ;;
esac

base=/var/lib/wardenkey
# Tests run this script as a normal user against a scratch folder; root (the real use, via pkexec) ignores the override.
if [ "$(id -u)" != 0 ] && [ -n "${WK_AUTH_BASE:-}" ]; then base="$WK_AUTH_BASE"; fi
dir="$base/$uid"
legacy="$dir/vault.key"
id="${2:-}"
case "$id" in
  '') key="$legacy" ;;
  *[!A-Za-z0-9-]*) echo 'ERROR:bad id'; exit 2 ;;
  *) [ "${#id}" -ge 8 ] && [ "${#id}" -le 64 ] || { echo 'ERROR:bad id'; exit 2; }; key="$dir/$id.key" ;;
esac

case "${1:-}" in
  verify)
    echo 'RESULT:Verified'
    ;;
  create)
    mkdir -p "$dir"
    if [ "$(id -u)" = 0 ]; then chown root:root "$base" "$dir"; fi # always root when run through pkexec; tests run as a normal user
    chmod 700 "$base" "$dir"
    tmp=$(mktemp "$dir/.new.XXXXXX")
    head -c 32 /dev/urandom | base64 | tr -d '\n' > "$tmp"
    mv -f "$tmp" "$key"
    printf 'SIG:%s\n' "$(cat "$key")"
    ;;
  open)
    if [ -s "$key" ]; then printf 'SIG:%s\n' "$(cat "$key")"
    elif [ -n "$id" ] && [ -s "$legacy" ]; then printf 'SIG:%s\n' "$(cat "$legacy")"
    else echo 'STATUS:NotFound'; fi
    ;;
  *)
    echo 'ERROR:usage: wardenkey-auth verify|create|open [id]'
    exit 2
    ;;
esac
