Require approval for new USB devices by default

Co-authored-by: Outfoxxed <outfoxxed@outfoxxed.me>
This commit is contained in:
acrogenesisandOutfoxxed committed 2026-09-14 22:13:36 -06:00
1 parent 86a2e5830e
commit 44f68f4329
19 files changed
+1382 -2

No files matched your search

+6
View File
@@ -747,6 +747,12 @@ create_user() {
echo "%wheel ALL=(ALL:ALL) ALL" >/etc/sudoers.d/00-omarchy-wheel
chmod 440 /etc/sudoers.d/00-omarchy-wheel
if omarchy-pkg-present usbguard; then
source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"
usb_authorization_add_user "$username"
systemctl try-restart usbguard.service
fi
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
for dir in "${BROWSER_POLICY_MANAGED_DIRS[@]}"; do
[[ -d $dir || -L $dir ]] || continue
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# omarchy:summary=Stop asking before new USB devices can access the system
# omarchy:args=[--boot-only] [--yes]
# omarchy:requires-sudo=true
set -euo pipefail
assume_yes=0
boot_only=0
while (( $# > 0 )); do
case "$1" in
--yes) assume_yes=1 ;;
--boot-only) boot_only=1 ;;
-h | --help)
echo "Usage: omarchy-remove-security-usb-authorization [--boot-only] [--yes]"
echo
echo "Disables Omarchy's USB approval prompts and restores the kernel's"
echo "normal default-allow behavior."
echo "Use --boot-only to keep USBGuard enabled after the system starts."
exit 0
;;
*)
echo "omarchy-remove-security-usb-authorization: unknown option '$1'. Try --help." >&2
exit 2
;;
esac
shift
done
if (( boot_only )); then
if (( ! assume_yes )); then
gum style --foreground 212 --bold "Remove USB authorization from boot"
echo
echo "USBGuard will continue blocking unknown devices after its service starts."
echo "Devices can reach kernel drivers earlier during boot."
echo
gum confirm "Disable USB authorization from kernel boot?" || exit 130
fi
sudo omarchy-usb-authorization-boot disable
echo
echo "Boot-time USB authorization is disabled and takes effect after reboot."
exit 0
fi
state_dir="$HOME/.local/state/omarchy/usb-authorization"
unit="$HOME/.config/systemd/user/omarchy-usb-authorization.service"
if (( ! assume_yes )); then
gum style --foreground 212 --bold "Remove USB device authorization"
echo
echo "New USB devices will be allowed to bind to kernel drivers without approval."
echo
gum confirm "Disable USB device authorization?" || exit 130
fi
# Rebuild a permissive boot image before stopping USBGuard. If rebuilding
# fails, the command stops here and leaves the complete policy enabled.
sudo omarchy-usb-authorization-boot disable
systemctl --user disable --now omarchy-usb-authorization.service 2>/dev/null || true
rm -f "$unit"
systemctl --user daemon-reload
if omarchy-pkg-present usbguard; then
sudo usbguard remove-user "$USER" 2>/dev/null || true
fi
if omarchy-pkg-present usbguard; then
sudo systemctl disable --now usbguard.service 2>/dev/null || true
sudo omarchy-usb-authorization-restore-default
fi
if [[ -d $state_dir/requests ]]; then
find "$state_dir/requests" -mindepth 1 -maxdepth 1 -type f -delete
rmdir "$state_dir/requests" 2>/dev/null || true
fi
rm -f "$state_dir/package-installed-by-omarchy" \
"$state_dir/policy-generated-by-omarchy" \
"$state_dir/service-enabled-by-omarchy"
rmdir "$state_dir" 2>/dev/null || true
echo "USB device authorization is disabled."
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
# omarchy:summary=Ask before new USB devices can access the system
# omarchy:args=[--boot] [--yes]
# omarchy:requires-sudo=true
set -euo pipefail
assume_yes=0
from_boot=0
while (( $# > 0 )); do
case "$1" in
--yes) assume_yes=1 ;;
--boot) from_boot=1 ;;
-h | --help)
echo "Usage: omarchy-setup-security-usb-authorization [--boot] [--yes]"
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."
exit 0
;;
*)
echo "omarchy-setup-security-usb-authorization: unknown option '$1'. Try --help." >&2
exit 2
;;
esac
shift
done
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 (( ! 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. Continue only if unlock and recovery do not"
echo "depend on USB input."
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 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
ln -sfn "$unit_source" "$unit"
systemctl --user daemon-reload
systemctl --user enable --now omarchy-usb-authorization.service
if (( from_boot )); then
# Take the trust snapshot only after USBGuard is enforcing the policy. Every
# ID is resolved by the daemon, and no device-controlled descriptor text is
# passed to a privileged command.
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."
if (( from_boot )); then
echo "Boot-time authorization is enabled and takes effect after reboot."
fi
+432
View File
@@ -0,0 +1,432 @@
#!/bin/bash
# omarchy:summary=Manage USB authorization from the start of kernel boot
# omarchy:args=<enable|disable>
# omarchy:requires-sudo=true
# omarchy:hidden=true
set -euo pipefail
drop_in=/etc/limine-entry-tool.d/usb-authorization.conf
setting='KERNEL_CMDLINE[default]+=" usbcore.authorized_default=0"'
limine_conf=/boot/limine.conf
limine_defaults=/etc/default/limine
boot_path=/boot
kernel_parameter=usbcore.authorized_default=0
snapshot_begin='# Omarchy USB authorization begin'
snapshot_setting='SNAPSHOT_KERNEL_PARAMETERS+=usbcore.authorized_default=0'
snapshot_end='# Omarchy USB authorization end'
usb_authorization_cmdline_has_parameter() {
local cmdline="$1" parameter="$2" word
for word in $cmdline; do
[[ $word == "$parameter" ]] && return 0
done
return 1
}
usb_authorization_secure_boot_enabled() {
local value variable
for variable in /sys/firmware/efi/efivars/SecureBoot-*; do
[[ -r $variable ]] || continue
value=$(od -An -t u1 -j 4 -N 1 "$variable")
value=${value//[[:space:]]/}
[[ $value == "1" ]] && return 0
done
return 1
}
usb_authorization_verify_boot_entries() {
local expected="$1" config="$2" esp="$3"
local machine_id="${4:-$(</etc/machine-id)}"
local secure_boot="${5:-auto}"
local actual_hash embedded_cmdline expected_hash image mode path paths section
if [[ $secure_boot == "auto" ]]; then
if usb_authorization_secure_boot_enabled; then
secure_boot=enabled
else
secure_boot=disabled
fi
fi
if [[ ! -r $config ]]; then
echo "Cannot verify the generated Limine boot entries in $config." >&2
return 1
fi
paths=$(mktemp /tmp/omarchy-usb-boot-paths.XXXXXXXXXX)
section=$(mktemp /tmp/omarchy-usb-boot-cmdline.XXXXXXXXXX)
if ! awk -v expected="$expected" -v machine_id="$machine_id" -v parameter="$kernel_parameter" '
function contains_parameter(value, count, fields, field_index) {
count = split(value, fields, /[[:space:]]+/)
for (field_index = 1; field_index <= count; field_index++) {
if (fields[field_index] == parameter) return 1
}
return 0
}
function finish_entry(found) {
if (!target_os || !is_kernel) return
entries++
if (has_cmdline) {
found = contains_parameter(cmdline)
if ((expected == "enabled" && !found) || (expected == "disabled" && found)) bad = 1
}
if (path == "") {
bad = 1
} else {
print (has_cmdline ? "external" : "embedded") "\t" path
}
}
/^\/[^/]/ {
finish_entry()
target_os = 0
is_kernel = 0
has_cmdline = 0
cmdline = ""
path = ""
next
}
/^[[:space:]]*comment:[[:space:]]*machine-id=/ {
target_os = index($0, "machine-id=" machine_id) > 0
next
}
/^[[:space:]]*\/\// {
finish_entry()
is_kernel = 0
has_cmdline = 0
cmdline = ""
path = ""
next
}
/^[[:space:]]*comment:[[:space:]]*kernel-id=/ {
is_kernel = target_os
next
}
is_kernel && /^[[:space:]]*path:[[:space:]]*/ {
path = $0
sub(/^[[:space:]]*path:[[:space:]]*/, "", path)
next
}
is_kernel && /^[[:space:]]*cmdline:[[:space:]]*/ {
has_cmdline = 1
cmdline = $0
sub(/^[[:space:]]*cmdline:[[:space:]]*/, "", cmdline)
next
}
END {
finish_entry()
if (entries == 0) bad = 1
exit bad
}
' "$config" >"$paths"; then
rm -f "$paths" "$section"
echo "The generated Limine kernel entries do not all have USB authorization $expected." >&2
return 1
fi
while IFS=$'\t' read -r mode path; do
if [[ $path != 'boot():/'* ]]; then
rm -f "$paths" "$section"
echo "Cannot verify the kernel image referenced by Limine: $path" >&2
return 1
fi
image="$esp/${path#'boot():/'}"
image=${image%%#*}
if [[ ! -r $image ]]; then
rm -f "$paths" "$section"
echo "Cannot verify the kernel image referenced by Limine: $image" >&2
return 1
fi
if [[ $path == *'#'* ]]; then
expected_hash=${path##*#}
actual_hash=$(b2sum "$image")
actual_hash=${actual_hash%% *}
if [[ $actual_hash != "$expected_hash" ]]; then
rm -f "$paths" "$section"
echo "The verification hash for $image does not match the generated Limine entry." >&2
return 1
fi
fi
: >"$section"
if ! objcopy -O binary --only-section=.cmdline "$image" "$section" 2>/dev/null; then
[[ $mode == "external" ]] && continue
rm -f "$paths" "$section"
echo "Cannot inspect the embedded kernel command line in $image." >&2
return 1
fi
embedded_cmdline=$(tr '\0' '\n' <"$section")
# Without Secure Boot, Limine's external command line takes precedence.
# Under Secure Boot, systemd-stub uses a nonempty embedded .cmdline.
if [[ $mode == "external" && $secure_boot == "disabled" ]]; then
continue
fi
# A signed UKI can ignore Limine's external cmdline and use its embedded
# .cmdline instead. If one exists, both representations must agree.
if [[ -z $embedded_cmdline ]]; then
if [[ $mode == "external" || $expected == "disabled" ]]; then
continue
fi
rm -f "$paths" "$section"
echo "The generated kernel image $image has no verifiable kernel command line." >&2
return 1
fi
if [[ $expected == "enabled" ]]; then
if ! usb_authorization_cmdline_has_parameter "$embedded_cmdline" "$kernel_parameter"; then
rm -f "$paths" "$section"
echo "The generated kernel image $image does not enable boot-time USB authorization." >&2
return 1
fi
elif usb_authorization_cmdline_has_parameter "$embedded_cmdline" "$kernel_parameter"; then
rm -f "$paths" "$section"
echo "The generated kernel image $image still enables boot-time USB authorization." >&2
return 1
fi
done <"$paths"
rm -f "$paths" "$section"
}
usb_authorization_rebuild_and_verify() {
local expected="$1" config="$2" esp="$3"
local machine_id="${4:-$(</etc/machine-id)}" secure_boot="${5:-auto}"
if ! limine-mkinitcpio; then
return 1
fi
# limine-mkinitcpio-hook can swallow an individual kernel build failure and
# still return success, so its exit status alone is not a safety boundary.
usb_authorization_verify_boot_entries "$expected" "$config" "$esp" "$machine_id" "$secure_boot"
}
usb_authorization_snapshot_block_status() {
local config="$1"
[[ -r $config ]] || return 2
awk -v begin="$snapshot_begin" -v setting="$snapshot_setting" -v end="$snapshot_end" '
$0 == begin { begin_count++; state = 1; next }
$0 == setting { setting_count++; if (state == 1) state = 2; next }
$0 == end { end_count++; if (state == 2) valid_count++; state = 0; next }
{ state = 0 }
END {
if (begin_count == 0 && setting_count == 0 && end_count == 0) exit 1
if (begin_count == 1 && setting_count == 1 && end_count == 1 && valid_count == 1) exit 0
exit 2
}
' "$config"
}
usb_authorization_enable_snapshot_setting() {
local config="$1" status temporary
if usb_authorization_snapshot_block_status "$config"; then
return 0
else
status=$?
fi
if (( status != 1 )); then
echo "Refusing to modify the USB authorization block in $config." >&2
return 1
fi
temporary=$(mktemp "${config}.XXXXXXXXXX")
cp --preserve=mode,ownership "$config" "$temporary"
{
cat "$config"
printf '\n%s\n%s\n%s\n' "$snapshot_begin" "$snapshot_setting" "$snapshot_end"
} >"$temporary"
mv -f "$temporary" "$config"
}
usb_authorization_disable_snapshot_setting() {
local config="$1" status temporary
if usb_authorization_snapshot_block_status "$config"; then
status=0
else
status=$?
fi
(( status == 1 )) && return 0
if (( status != 0 )); then
echo "Refusing to modify the USB authorization block in $config." >&2
return 1
fi
temporary=$(mktemp "${config}.XXXXXXXXXX")
cp --preserve=mode,ownership "$config" "$temporary"
awk -v begin="$snapshot_begin" '
$0 == begin { skip = 2; next }
skip > 0 { skip--; next }
{ print }
' "$config" >"$temporary"
mv -f "$temporary" "$config"
}
usb_authorization_rewrite_boot_cmdlines() {
local expected="$1" config="$2" machine_id="${3:-$(</etc/machine-id)}"
local backup temporary
backup=$(mktemp "${config}.omarchy-usb-backup.XXXXXXXXXX")
temporary=$(mktemp "${config}.omarchy-usb-new.XXXXXXXXXX")
cp --preserve=mode,ownership "$config" "$backup"
cp --preserve=mode,ownership "$config" "$temporary"
if ! awk -v expected="$expected" -v machine_id="$machine_id" -v parameter="$kernel_parameter" '
function rewrite_cmdline(line, prefix, value, count, fields, field_index, result, found) {
prefix = line
sub(/cmdline:.*/, "cmdline:", prefix)
value = line
sub(/^[[:space:]]*cmdline:[[:space:]]*/, "", value)
count = split(value, fields, /[[:space:]]+/)
result = ""
found = 0
for (field_index = 1; field_index <= count; field_index++) {
if (fields[field_index] == parameter) {
found = 1
continue
}
if (fields[field_index] != "") result = result (result == "" ? "" : " ") fields[field_index]
}
if (expected == "enabled") result = result (result == "" ? "" : " ") parameter
return prefix (result == "" ? "" : " ") result
}
/^\/[^/]/ { target_os = 0 }
/^[[:space:]]*comment:[[:space:]]*machine-id=/ {
target_os = index($0, "machine-id=" machine_id) > 0
}
target_os && /^[[:space:]]*cmdline:[[:space:]]*/ {
print rewrite_cmdline($0)
next
}
{ print }
' "$config" >"$temporary"; then
rm -f "$backup" "$temporary"
return 1
fi
mv -f "$temporary" "$config"
if ! limine-enroll-config; then
mv -f "$backup" "$config"
limine-enroll-config >/dev/null 2>&1 || true
echo "Restored $config because its bootloader verification data could not be updated." >&2
return 1
fi
rm -f "$backup"
}
main() {
local had_drop_in=0 had_snapshot_setting=0 snapshot_status temporary
if (( EUID != 0 )); then
echo "Error: omarchy-usb-authorization-boot must run as root" >&2
exit 1
fi
case "${1:-}" in
enable)
if usb_authorization_snapshot_block_status "$limine_defaults"; then
snapshot_status=0
else
snapshot_status=$?
fi
if (( snapshot_status == 2 )); then
echo "Refusing to modify the USB authorization block in $limine_defaults." >&2
exit 1
fi
# Quote the expected value because the Limine key contains glob brackets.
if [[ -e $drop_in ]] && [[ $(<"$drop_in") != "$setting" ]]; then
echo "Refusing to replace the existing $drop_in." >&2
exit 1
fi
usb_authorization_enable_snapshot_setting "$limine_defaults"
if [[ ! -e $drop_in ]]; then
install -d -m755 "${drop_in%/*}"
temporary=$(mktemp "${drop_in}.XXXXXXXXXX")
trap 'rm -f "$temporary"' EXIT
printf '%s\n' "$setting" >"$temporary"
chmod 644 "$temporary"
mv -f "$temporary" "$drop_in"
trap - EXIT
fi
if ! limine-mkinitcpio ||
! usb_authorization_rewrite_boot_cmdlines enabled "$limine_conf" ||
! usb_authorization_verify_boot_entries enabled "$limine_conf" "$boot_path"; then
echo "Boot-time USB authorization remains configured in $drop_in; rerun this command after fixing the boot-image error." >&2
exit 1
fi
;;
disable)
if usb_authorization_snapshot_block_status "$limine_defaults"; then
had_snapshot_setting=1
else
snapshot_status=$?
if (( snapshot_status == 2 )); then
echo "Refusing to modify the USB authorization block in $limine_defaults." >&2
exit 1
fi
fi
if [[ -e $drop_in ]]; then
if [[ $(<"$drop_in") != "$setting" ]]; then
echo "Refusing to remove the modified $drop_in." >&2
exit 1
fi
had_drop_in=1
rm -f "$drop_in"
elif (( ! had_snapshot_setting )) && usb_authorization_verify_boot_entries disabled "$limine_conf" "$boot_path"; then
exit 0
fi
usb_authorization_disable_snapshot_setting "$limine_defaults"
if ! limine-mkinitcpio ||
! usb_authorization_rewrite_boot_cmdlines disabled "$limine_conf" ||
! usb_authorization_verify_boot_entries disabled "$limine_conf" "$boot_path"; then
if (( had_drop_in )); then
printf '%s\n' "$setting" >"$drop_in"
chmod 644 "$drop_in"
fi
if (( had_snapshot_setting )); then
usb_authorization_enable_snapshot_setting "$limine_defaults"
fi
echo "USBGuard remains required because the boot images could not be verified as default-allow." >&2
exit 1
fi
;;
*)
echo "Usage: omarchy-usb-authorization-boot <enable|disable>" >&2
exit 2
;;
esac
}
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
main "$@"
fi
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# omarchy:hidden=true
# omarchy:summary=Create an approval request for a blocked USB device
set -euo pipefail
[[ ${USBGUARD_IPC_SIGNAL:-} == "Device.PresenceChanged" ]] || exit 0
[[ ${USBGUARD_DEVICE_EVENT:-} == "Insert" ]] || exit 0
[[ ${USBGUARD_DEVICE_TARGET:-} == "block" ]] || exit 0
[[ ${USBGUARD_DEVICE_ID:-} =~ ^[0-9]+$ ]] || exit 0
[[ -n ${USBGUARD_DEVICE_RULE:-} ]] || exit 0
requests="$HOME/.local/state/omarchy/usb-authorization/requests"
mkdir -p "$requests"
chmod 700 "${requests%/*}" "$requests"
# The token is safe to carry through the presentation launcher's command
# string. The device-controlled rule itself stays in a mode-0600 JSON file and
# is never interpolated into a shell command.
token="request-$(printf '%s\0%s' "$USBGUARD_DEVICE_ID" "$USBGUARD_DEVICE_RULE" | sha256sum | cut -d' ' -f1)"
request="$requests/$token.json"
temporary=$(mktemp "$requests/.request.XXXXXXXXXX")
trap 'rm -f "$temporary"' EXIT
jq -n \
--arg id "$USBGUARD_DEVICE_ID" \
--arg rule "$USBGUARD_DEVICE_RULE" \
'{id: $id, rule: $rule}' >"$temporary"
chmod 600 "$temporary"
mv -f "$temporary" "$request"
omarchy-notification-send \
--app-name omarchy-action \
--urgency critical \
--glyph 󰖀 \
"USB accessory blocked" \
"Click to review it. Keep it blocked unless you recognize the device." \
--exec omarchy-launch-floating-terminal-with-presentation \
omarchy-usb-authorization-review "$token"
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# omarchy:summary=Restore the kernel's default USB authorization state
# omarchy:requires-sudo=true
# omarchy:hidden=true
set -euo pipefail
if (( EUID != 0 )); then
echo "Error: omarchy-usb-authorization-restore-default must run as root" >&2
exit 1
fi
# USBGuard intentionally leaves root hubs in default-deny mode when it exits.
# Restore both the hub defaults and devices that are still connected.
shopt -s nullglob
for attribute in /sys/bus/usb/devices/usb*/authorized_default; do
echo 1 >"$attribute"
done
for attribute in /sys/bus/usb/devices/*/authorized; do
echo 1 >"$attribute"
done
shopt -u nullglob
+79
View File
@@ -0,0 +1,79 @@
#!/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"
if [[ ! -f $request || -L $request ]]; then
echo "This USB authorization request is no longer available." >&2
exit 1
fi
id=$(jq -er '.id | select(test("^[0-9]+$"))' "$request")
expected_rule=$(jq -er '.rule | select(type == "string" and length > 0)' "$request")
read_blocked_rule() {
local line
while IFS= read -r line; do
if [[ $line == "$id: "* ]]; then
printf '%s\n' "${line#"$id: "}"
return 0
fi
done < <(usbguard list-devices --blocked)
return 1
}
current_rule=$(read_blocked_rule || true)
if [[ -z $current_rule || $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
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
if [[ $choice != "Keep blocked" ]]; then
current_rule=$(read_blocked_rule || true)
if [[ -z $current_rule || $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")
# Target the complete identity rule instead of USBGuard's numeric ID. IDs can
# be reassigned when the daemon restarts while the review dialog is open.
usbguard allow-device "$expected_rule"
echo "USB accessory allowed until it is disconnected."
;;
"Always allow this device")
usbguard allow-device --permanent "$expected_rule"
echo "USB accessory added to the trusted policy."
;;
"Keep blocked")
echo "USB accessory remains blocked."
;;
esac
rm -f "$request"
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# omarchy:hidden=true
# omarchy:summary=Watch USBGuard for devices awaiting user approval
set -euo pipefail
event_handler="$OMARCHY_PATH/bin/omarchy-usb-authorization-event"
# A device inserted while the graphical session was stopped is already safely
# blocked by USBGuard. Surface it now so the user can approve it after login.
while IFS= read -r line; do
if [[ $line =~ ^([0-9]+):[[:space:]](block.*)$ ]]; then
USBGUARD_IPC_SIGNAL=Device.PresenceChanged \
USBGUARD_DEVICE_ID="${BASH_REMATCH[1]}" \
USBGUARD_DEVICE_EVENT=Insert \
USBGUARD_DEVICE_TARGET=block \
USBGUARD_DEVICE_RULE="${BASH_REMATCH[2]}" \
"$event_handler"
fi
done < <(usbguard list-devices --blocked)
exec usbguard watch --wait --exec "$event_handler"