#!/bin/sh
set -eu

usage() {
  cat >&2 <<'EOF'
usage:
  configure_capture_helper_sudoers.sh install --user <username> --helper-path <path> [--sudoers-file <path>] [--packetlogger-source <path>] [--managed-packetlogger-app <path>]
  configure_capture_helper_sudoers.sh remove [--sudoers-file <path>]
EOF
}

escape_sudoers_command() {
  value="$1"
  value=$(printf '%s' "$value" | /usr/bin/sed 's/\\/\\\\/g; s/ /\\ /g; s/,/\\,/g')
  printf '%s' "$value"
}

physical_path() {
  value="$1"
  directory="$(/usr/bin/dirname "$value")"
  basename="$(/usr/bin/basename "$value")"
  physical_directory="$(cd "$directory" && /bin/pwd -P)"
  printf '%s/%s' "$physical_directory" "$basename"
}

validate_sudoers_user_name() {
  value="$1"
  case "$value" in
    *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-]*|"")
      echo "configure_capture_helper_sudoers.sh: refusing unsafe sudoers user name: $value" >&2
      exit 64
      ;;
  esac
}

validate_sudoers_command_path() {
  value="$1"
  if printf '%s' "$value" | /usr/bin/grep -q '[][?*]'; then
    echo "configure_capture_helper_sudoers.sh: refusing helper path with sudoers wildcard characters: $value" >&2
    exit 64
  fi
}

append_helper_rules() {
  rule_user_name="$1"
  rule_helper_path="$2"
  rule_user_uid="$3"
  rule_user_gid="$4"
  escaped_helper="$(escape_sudoers_command "$rule_helper_path")"
  for packetlogger_path in \
    "/Applications/PacketLogger.app/Contents/Resources/packetlogger" \
    "/Library/Application Support/SiriPlus/Additional Tools/Hardware/PacketLogger.app/Contents/Resources/packetlogger" \
    "/Applications/Additional Tools for Xcode/PacketLogger.app/Contents/Resources/packetlogger" \
    "/Applications/Additional Tools for Xcode/Hardware/PacketLogger.app/Contents/Resources/packetlogger"
  do
    escaped_packetlogger="$(escape_sudoers_command "$packetlogger_path")"
    packetlogger_prefix="%s ALL=(root) NOPASSWD: %s --packetlogger-capture --virtual-mic --virtual-mic-shm /siriplus_remote_mic_pcm --packetlogger-path %s"
    packetlogger_suffix="--duration 0 --status-event-path /tmp/siriplus_bluetooth_capture_helper_status.json --status-only-remote-input --status-owner-uid %s --status-owner-gid %s --control-socket-path /tmp/siriplus_capture_helper_%s.sock --control-socket-owner-uid %s --control-socket-owner-gid %s --diagnostic-recording --record-dir /tmp/siriplus_packetlogger_diagnostics --record-owner-uid %s --record-owner-gid %s"
    printf "${packetlogger_prefix} ${packetlogger_suffix}\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} ${packetlogger_suffix} --privilege-verification-probe\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote * ${packetlogger_suffix}\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote * ${packetlogger_suffix} --privilege-verification-probe\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote-address * ${packetlogger_suffix}\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote-address * ${packetlogger_suffix} --privilege-verification-probe\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote * --remote-address * ${packetlogger_suffix}\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
    printf "${packetlogger_prefix} --remote * --remote-address * ${packetlogger_suffix} --privilege-verification-probe\n" "$rule_user_name" "$escaped_helper" "$escaped_packetlogger" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_uid" "$rule_user_gid" "$rule_user_uid" "$rule_user_gid"
  done
  printf '%s ALL=(root) NOPASSWD: %s --self-check\n' "$rule_user_name" "$escaped_helper"
}

packetlogger_app_for_source() {
  value="$1"
  case "$value" in
    */PacketLogger.app/Contents/Resources/packetlogger)
      printf '%s' "${value%/Contents/Resources/packetlogger}"
      ;;
    *)
      echo "configure_capture_helper_sudoers.sh: refusing unsupported PacketLogger source path: $value" >&2
      exit 64
      ;;
  esac
}

install_managed_packetlogger() {
  source_path="$1"
  if [ -z "$source_path" ]; then
    return 0
  fi
  case "$managed_packetlogger_app" in
    /*)
      ;;
    *)
      echo "configure_capture_helper_sudoers.sh: managed PacketLogger app path must be absolute: $managed_packetlogger_app" >&2
      exit 64
      ;;
  esac
  validate_sudoers_command_path "$managed_packetlogger_app"
  case "$source_path" in
    /*)
      ;;
    *)
      echo "configure_capture_helper_sudoers.sh: PacketLogger source path must be absolute: $source_path" >&2
      exit 64
      ;;
  esac
  if [ ! -x "$source_path" ]; then
    echo "configure_capture_helper_sudoers.sh: PacketLogger source executable not found at $source_path" >&2
    exit 66
  fi
  validate_sudoers_command_path "$source_path"
  source_app="$(packetlogger_app_for_source "$source_path")"
  if [ ! -d "$source_app/Contents" ]; then
    echo "configure_capture_helper_sudoers.sh: PacketLogger source app is incomplete: $source_app" >&2
    exit 66
  fi

  managed_parent="$(/usr/bin/dirname "$managed_packetlogger_app")"
  managed_packetlogger_temp_app="${managed_packetlogger_app}.tmp.$$"
  /bin/mkdir -p "$managed_parent"
  /bin/rm -rf "$managed_packetlogger_temp_app"
  /usr/bin/ditto --norsrc --noextattr --noqtn "$source_app" "$managed_packetlogger_temp_app"
  if [ ! -x "$managed_packetlogger_temp_app/Contents/Resources/packetlogger" ]; then
    echo "configure_capture_helper_sudoers.sh: imported PacketLogger app does not contain Contents/Resources/packetlogger: $source_app" >&2
    exit 66
  fi
  /usr/sbin/chown -R root:wheel "$managed_packetlogger_temp_app" 2>/dev/null || true
  /bin/chmod -R go-w "$managed_packetlogger_temp_app"
  /bin/rm -rf "$managed_packetlogger_app"
  /bin/mv "$managed_packetlogger_temp_app" "$managed_packetlogger_app"
  managed_packetlogger_temp_app=""
}

remove_stale_sudoers_fragments() {
  for stale_file in "${sudoers_dir}/siriplus-capture-helper."*; do
    if [ -e "$stale_file" ]; then
      /bin/rm -f "$stale_file"
    fi
  done
  # Pre-rename installs left a root rule under the old product name; nothing
  # else ever cleans it, so retire it whenever setup runs.
  if [ -e "${sudoers_dir}/goatremote-siri-helper" ]; then
    /bin/rm -f "${sudoers_dir}/goatremote-siri-helper"
  fi
}

command_name="${1:-}"
if [ -z "$command_name" ]; then
  usage
  exit 64
fi
shift

user_name=""
helper_path=""
packetlogger_source=""
sudoers_file="/private/etc/sudoers.d/siriplus-capture-helper"
managed_packetlogger_app="/Library/Application Support/SiriPlus/Additional Tools/Hardware/PacketLogger.app"
temp_file=""
managed_packetlogger_temp_app=""

cleanup_temp_file() {
  if [ -n "$temp_file" ] && [ -f "$temp_file" ]; then
    /bin/rm -f "$temp_file"
  fi
  if [ -n "$managed_packetlogger_temp_app" ] && [ -e "$managed_packetlogger_temp_app" ]; then
    /bin/rm -rf "$managed_packetlogger_temp_app"
  fi
}

trap cleanup_temp_file EXIT HUP INT TERM

while [ "$#" -gt 0 ]; do
  case "$1" in
    --user)
      user_name="${2:-}"
      shift 2
      ;;
    --helper-path)
      helper_path="${2:-}"
      shift 2
      ;;
    --packetlogger-source)
      packetlogger_source="${2:-}"
      shift 2
      ;;
    --sudoers-file)
      sudoers_file="${2:-}"
      shift 2
      ;;
    --managed-packetlogger-app)
      managed_packetlogger_app="${2:-}"
      shift 2
      ;;
    *)
      echo "configure_capture_helper_sudoers.sh: unknown argument $1" >&2
      usage
      exit 64
      ;;
  esac
done

sudoers_dir="$(/usr/bin/dirname "$sudoers_file")"

case "$command_name" in
  install)
    if [ -z "$user_name" ] || [ -z "$helper_path" ]; then
      usage
      exit 64
    fi
    validate_sudoers_user_name "$user_name"
    case "$helper_path" in
      /*)
        ;;
      *)
        echo "configure_capture_helper_sudoers.sh: helper path must be absolute: $helper_path" >&2
        exit 64
        ;;
    esac
    if [ ! -x "$helper_path" ]; then
      echo "configure_capture_helper_sudoers.sh: helper executable not found at $helper_path" >&2
      exit 66
    fi
    validate_sudoers_command_path "$helper_path"
    user_uid="$(/usr/bin/id -u "$user_name")"
    user_gid="$(/usr/bin/id -g "$user_name")"

    /bin/mkdir -p "$sudoers_dir"
    install_managed_packetlogger "$packetlogger_source"
    remove_stale_sudoers_fragments
    temp_file="$(/usr/bin/mktemp "${sudoers_dir}/siriplus-capture-helper.XXXXXX")"
    canonical_helper_path="$(physical_path "$helper_path")"
    validate_sudoers_command_path "$canonical_helper_path"
    {
      append_helper_rules "$user_name" "$helper_path" "$user_uid" "$user_gid"
      if [ "$canonical_helper_path" != "$helper_path" ]; then
        append_helper_rules "$user_name" "$canonical_helper_path" "$user_uid" "$user_gid"
      fi
    } > "$temp_file"
    /bin/chmod 0440 "$temp_file"
    /usr/sbin/visudo -cf "$temp_file" >/dev/null
    /bin/mv -f "$temp_file" "$sudoers_file"
    temp_file=""
    /bin/chmod 0440 "$sudoers_file"
    echo "Installed SiriPlus PacketLogger sudoers rule for $helper_path."
    ;;

  remove)
    remove_stale_sudoers_fragments
    /bin/rm -f "$sudoers_file"
    ;;

  *)
    usage
    exit 64
    ;;
esac

exit 0
