#!/bin/sh
# ABOUTME: Privileged helper invoked via pkexec from moonarch-camera-toggle; writes USB authorized.
# ABOUTME: Every precondition is re-derived from kernel data — nothing the caller says is trusted.

set -eu

PATH=/usr/bin:/bin
export PATH

ID="${1:-}"
VAL="${2:-}"

die() {
    echo "$1" >&2
    exit 1
}

[ "$#" -eq 2 ] || die "Usage: moonarch-camera-apply <usb-id> <0|1>"

case "$VAL" in
    0 | 1) ;;
    *) die "Invalid value: '$VAL' (expected 0 or 1)" ;;
esac

# A USB device id is a bus-port path: digits, then dash, then dot-separated port numbers.
# Rejects '/', '..', leading or trailing separators, whitespace and glob characters, so the id
# cannot address anything outside the device directory. DECISIONS.md (2026-03-31) records a past
# command injection from an unquoted expansion behind pkexec — hence the strict shape first.
case "$ID" in
    "" | *[!0-9.-]* | *..* | *.. | .* | -* | *. | *-) die "Invalid device id: '$ID'" ;;
esac
case "$ID" in
    *-*) ;;
    *) die "Invalid device id: '$ID'" ;;
esac
case "$ID" in
    *-*-*) die "Invalid device id: '$ID'" ;;
esac

DEV="/sys/bus/usb/devices/$ID"
[ -d "$DEV" ] || die "No such USB device: $ID"
[ -f "$DEV/authorized" ] || die "Device cannot be authorized: $ID"
if [ -L "$DEV/authorized" ]; then
    die "Unexpected symlink: $DEV/authorized"
fi

# /sys/bus/usb/devices/<id> is itself a symlink into /sys/devices, so confinement is checked
# against the resolved target rather than the bus path.
REAL=$(readlink -f "$DEV/authorized")
case "$REAL" in
    /sys/devices/*/authorized) ;;
    *) die "Refusing to write outside /sys/devices: $REAL" ;;
esac

# Reject interfaces and anything that is not a USB device proper.
grep -qx "DEVTYPE=usb_device" "$DEV/uevent" || die "Not a USB device: $ID"

# Camera gate: the descriptor blob must carry a video interface (class 0x0e). This is what makes
# the helper structurally unable to deauthorize a hub, keyboard or disk, and it works whether the
# device is currently on or off.
is_camera=$(od -An -v -tu1 "$DEV/descriptors" 2>/dev/null | awk '
    { for (k = 1; k <= NF; k++) b[n++] = $k }
    END {
        p = 0
        while (p < n) {
            l = b[p] + 0
            if (l == 0)
                break
            if (b[p + 1] == 4 && b[p + 5] + 0 == 14) {
                print "yes"
                exit
            }
            p += l
        }
    }')
[ "$is_camera" = "yes" ] || die "Not a camera: $ID"

# Writing the value it already has would tear the device down and rebuild it for nothing.
if [ "$(cat "$DEV/authorized" 2>/dev/null)" = "$VAL" ]; then
    exit 0
fi

printf %s "$VAL" > "$DEV/authorized" || die "Failed to write $DEV/authorized"
