#!/bin/bash

# omarchy:summary=Ask before new USB devices can access the system
# omarchy:args=[--boot] [--yes] [--review-existing]
# omarchy:requires-sudo=true

set -euo pipefail

assume_yes=0
from_boot=0
review_existing=0

while (( $# > 0 )); do
  case "$1" in
  --yes) assume_yes=1 ;;
  --boot) from_boot=1 ;;
  --review-existing) review_existing=1 ;;
  -h | --help)
    echo "Usage: omarchy-setup-security-usb-authorization [--boot] [--yes] [--review-existing]"
    echo
    echo "Trusts USB devices that are connected now, then blocks new devices"
    echo "until you approve them from an Omarchy notification."
    echo
    echo "--boot also blocks USB devices from the start of kernel boot. Connected"
    echo "devices are added to USBGuard's policy, but remain unavailable before"
    echo "USBGuard starts, including at an encrypted-disk password prompt."
    echo "Older snapshots without USBGuard keep all USB disabled after startup,"
    echo "including keyboards, network adapters, and storage. Use --boot only if"
    echo "disk unlock and recovery work without any USB devices."
    echo
    echo "--review-existing reviews connected devices with older port-bound approvals."
    echo "Each portable approval requires confirmation; existing rules are preserved."
    exit 0
    ;;
  *)
    echo "omarchy-setup-security-usb-authorization: unknown option '$1'. Try --help." >&2
    exit 2
    ;;
  esac
  shift
done

# Boot-time blocking goes into Limine's own configuration, which a Mac's boot
# package owns, so it is not offered there.
if (( from_boot )) && omarchy-hw-aarch64-apple; then
  echo "USB authorization from boot is not available on Apple Silicon yet; USB device authorization after login still works." >&2
  exit 2
fi

state_dir="$HOME/.local/state/omarchy/usb-authorization"
unit_source="$OMARCHY_PATH/default/systemd/user/omarchy-usb-authorization.service"
unit="$HOME/.config/systemd/user/omarchy-usb-authorization.service"
rules_file=/etc/usbguard/rules.conf
daemon_config=/etc/usbguard/usbguard-daemon.conf

source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"

if (( review_existing )); then
  # Older Omarchy rules have no per-rule ownership marker. They cannot safely
  # be distinguished from intentionally restricted administrator rules.
  (( ! assume_yes && ! from_boot )) || { echo "Review requires individual confirmation; do not combine it with --yes or --boot." >&2; exit 2; }
  policy=$(usbguard list-rules)
  declare -A reviewed=()
  # Keep stdin attached to the terminal for gum (and any sudo prompt).
  mapfile -t policy_lines <<<"$policy"
  for line in "${policy_lines[@]}"; do
    if [[ $line =~ ^[0-9]+:[[:space:]] ]]; then
      rule=${line#*: }
      [[ $rule == allow\ * ]] || continue
      portable=$(usb_authorization_portable_rule "$rule") || continue
      [[ ${portable% label *} != "$rule" ]] || continue
      devices=$(usbguard list-devices "$rule")
      mapfile -t candidates <<<"$devices"
      for device in "${candidates[@]}"; do
        [[ $device =~ ^([0-9]+):[[:space:]](allow[[:space:]].*)$ ]] || continue
        id=${BASH_REMATCH[1]} current=${BASH_REMATCH[2]}
        [[ ! -v reviewed[$id] ]] || continue
        reviewed[$id]=1
        echo
        printf '%s\n' "$current" | LC_ALL=C tr -c '\11\12\15\40-\176' '?'
        echo "This device has a location-bound approval. Details are supplied by the device."
        if gum confirm "Trust this device on any USB port or hub?"; then
          sudo /usr/bin/omarchy-usb-authorization-approve "$id" "$current"
        fi
      done
    fi
  done
  echo "Review complete. Disconnected devices can be approved when reconnected."
  exit 0
fi

# The watcher runs in the session's environment, which may differ from a
# command invoked in a checkout. Fail before enabling blocking on mismatched
# or incomplete installations, including dangling dev-link unit symlinks.
session_environment=$(systemctl --user show-environment)
grep -Fqx -- "OMARCHY_PATH=$OMARCHY_PATH" <<<"$session_environment" || {
  echo "The session and this command use different Omarchy installations. Update the session before enabling USB protection." >&2
  exit 1
}
for required in "$unit_source" /usr/share/omarchy/install/helpers/usb-authorization-policy.sh; do
  [[ -r $required ]] || { echo "USB authorization installation is incomplete: $required" >&2; exit 1; }
done
for required in "$OMARCHY_PATH/bin/omarchy-usb-authorization-watch" \
  "$OMARCHY_PATH/bin/omarchy-usb-authorization-event" \
  "$OMARCHY_PATH/bin/omarchy-usb-authorization-review" \
  /usr/bin/omarchy-usb-authorization-approve; do
  [[ -r $required && -x $required ]] || { echo "USB authorization command is unavailable: $required" >&2; exit 1; }
done

if (( ! assume_yes )); then
  if (( from_boot )); then
    gum style --foreground 212 --bold "USB authorization from boot"
  else
    gum style --foreground 212 --bold "USB device authorization"
  fi
  echo
  echo "Devices connected now will be trusted. Disconnect anything you do not trust."
  echo "New USB devices will remain blocked until you approve them."
  if (( from_boot )); then
    echo
    echo "Boot-time protection blocks all USB devices until USBGuard starts."
    echo "A USB keyboard will not work at an encrypted-disk password prompt, even"
    echo "when it is connected now."
    echo
    echo "Older snapshots without USBGuard keep ALL USB disabled after startup,"
    echo "including keyboards, network adapters, and storage."
    echo "Continue only if disk unlock and recovery work without any USB devices."
  fi
  echo
  if (( from_boot )); then
    gum confirm "Enable USB authorization from kernel boot?" || exit 130
  else
    gum confirm "Enable USB device authorization?" || exit 130
  fi
fi

omarchy-pkg-add usbguard

usb_authorization_require_secure_settings "$daemon_config"

mkdir -p "$state_dir" "${unit%/*}"
chmod 700 "$state_dir"

if ! usb_authorization_rules_present "$rules_file"; then
  policy=$(mktemp "${TMPDIR:-/tmp}/omarchy-usb-policy.XXXXXXXXXX")
  trap 'rm -f "$policy"' EXIT
  chmod 600 "$policy"
  usb_authorization_generate_policy "$policy"
  sudo install -Dm600 -o root -g root "$policy" "$rules_file"
  touch "$state_dir/policy-generated-by-omarchy"
fi

# This user can inspect USBGuard events and approve the device named by an
# event. Policy and daemon parameters remain unavailable through the IPC ACL.
sudo usbguard add-user "$USER" \
  --devices=list,listen,modify \
  --policy=list \
  --exceptions=listen

sudo install -Dm644 "$OMARCHY_PATH/default/polkit/org.omarchy.usb.policy" /usr/share/polkit-1/actions/org.omarchy.usb.policy

# Install a real file: a link into a checkout can become dangling on a branch
# switch. Start the waiting watcher before USBGuard can block new devices.
unit_temporary=$(mktemp "${unit}.XXXXXXXXXX")
install -m644 "$unit_source" "$unit_temporary"
mv -fT "$unit_temporary" "$unit"
systemctl --user daemon-reload
systemctl --user enable omarchy-usb-authorization.service
systemctl --user restart omarchy-usb-authorization.service
systemctl --user is-active --quiet omarchy-usb-authorization.service

sudo systemctl enable usbguard.service
# add-user ACL changes are loaded only when the daemon starts, so restart an
# existing service as well as starting a fresh one.
sudo systemctl restart usbguard.service
systemctl is-active --quiet usbguard.service
systemctl --user is-active --quiet omarchy-usb-authorization.service

if (( from_boot )); then
  # The fixed helper independently verifies each full live device snapshot.
  usb_authorization_trust_present_devices
  sudo omarchy-usb-authorization-boot enable
fi

echo
echo "USB device authorization is enabled."
echo "Devices connected during setup remain trusted; new devices require approval."
echo "To review older port-bound approvals, run: omarchy-setup-security-usb-authorization --review-existing"
if (( from_boot )); then
  echo "Boot-time authorization is enabled and takes effect after reboot."
fi
