Files
omarchy/bin/omarchy-usb-authorization-review
T

143 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
# omarchy:hidden=true
# omarchy:summary=Review a blocked USB device authorization request
set -euo pipefail
token="${1:-}"
if [[ ! $token =~ ^request-[0-9a-f]{64}$ ]]; then
echo "This USB authorization request is invalid or expired." >&2
exit 1
fi
request="$HOME/.local/state/omarchy/usb-authorization/requests/$token.json"
# Serialize request updates with watcher events, but release the lock while the
# user chooses. A changed request must never inherit an old dialog's approval.
if [[ ! -d ${request%/*} ]]; then
echo "This USB authorization request is no longer available." >&2
exit 1
fi
exec 9>"${request%/*}/.lock"
flock 9
if [[ ! -f $request || -L $request ]]; then
echo "This USB authorization request is no longer available." >&2
exit 1
fi
snapshot=$(cat "$request")
id=$(jq -er '.id | select(test("^[0-9]+$"))' <<<"$snapshot")
expected_rule=$(jq -er '.rule | select(type == "string" and startswith("block "))' <<<"$snapshot")
choice=$(jq -er '.approval // "" | select(. == "" or . == "Allow once" or . == "Always allow this device")' <<<"$snapshot")
allowed_rule="allow ${expected_rule#block }"
approval_failed() {
echo "Could not confirm USB approval. The request has been kept; try again." >&2
exit 1
}
read_current_rule() {
local devices line
current_rule=""
devices=$(usbguard list-devices) || approval_failed
while IFS= read -r line; do
if [[ $line == "$id: "* ]]; then
current_rule="${line#"$id: "}"
return
fi
done <<<"$devices"
}
validate_device() {
read_current_rule
if [[ $current_rule == "$expected_rule" ]] ||
[[ -n $choice && $current_rule == "$allowed_rule" ]]; then
return
fi
rm -f "$request"
echo "That USB device was removed or changed. Connect it again to review it." >&2
exit 1
}
validate_device
if [[ -z $choice ]]; then
flock -u 9
gum style --foreground 212 --bold "Blocked USB accessory"
echo
echo "The following details come from the device and can be forged:"
printf '%s\n' "$current_rule" | LC_ALL=C tr -c '\11\12\15\40-\176' '?'
echo
choice=$(gum choose \
"Allow once" \
"Always allow this device" \
"Keep blocked") || exit 130
flock 9
if [[ ! -f $request || -L $request || $(cat "$request") != "$snapshot" ]]; then
echo "This USB authorization request changed. Open the latest notification to review it." >&2
exit 1
fi
# A fresh choice can authorize only the blocked identity shown in the dialog.
read_current_rule
if [[ $current_rule != "$expected_rule" ]]; then
rm -f "$request"
echo "That USB device was removed or changed. Connect it again to review it." >&2
exit 1
fi
fi
case "$choice" in
"Allow once" | "Always allow this device")
# Save intent before applying policy: a later query can fail after the device
# was authorized. Retry must verify that approval, including persistent trust.
temporary=$(mktemp "${request%/*}/.request.XXXXXXXXXX")
trap 'rm -f "$temporary"' EXIT
jq --arg approval "$choice" '.approval = $approval' "$request" >"$temporary"
mv -f "$temporary" "$request"
if [[ $choice == "Always allow this device" ]]; then
pkexec /usr/bin/omarchy-usb-authorization-approve "$id" "$current_rule" || approval_failed
elif [[ $current_rule == "$expected_rule" ]]; then
# Match the complete identity, since numeric IDs can be reassigned.
usbguard allow-device "$expected_rule" || approval_failed
fi
# Rule-based USBGuard commands swallow applyDevicePolicy exceptions and can
# return success without authorizing anything. Verify the exact device.
allowed=$(usbguard list-devices --allowed) || approval_failed
grep -Fqx -- "$id: $allowed_rule" <<<"$allowed" || approval_failed
if [[ $choice == "Always allow this device" ]]; then
# Let USBGuard match policy rules: saved rules can omit the device's port.
# --show-devices indents the devices matching each policy rule.
policy=$(usbguard list-rules --label omarchy-usb-authorization-v1 --show-devices) || approval_failed
policy_allows=0
matched=0
while IFS= read -r line; do
if [[ $line =~ ^[0-9]+:[[:space:]] ]]; then
policy_allows=0
if [[ $line =~ ^[0-9]+:[[:space:]]allow[[:space:]] ]]; then
policy_allows=1
fi
elif (( policy_allows )) && [[ $line == $'\t'"$id: $allowed_rule" ]]; then
matched=1
break
fi
done <<<"$policy"
(( matched )) || approval_failed
echo "USB accessory added to the trusted policy."
else
echo "USB accessory allowed until it is disconnected."
fi
;;
"Keep blocked")
echo "USB accessory remains blocked."
;;
*) exit 1 ;;
esac
rm -f "$request"