Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OmaGuard

A bar widget for Omarchy 4.x (Quattro) that puts USBGuard where you can actually use it: a shield in the bar that turns urgent the moment a USB device is blocked, and a panel that lets you allow, block, or reject any device with one click.

The OmaGuard panel open from the bar, listing USB devices with allow, block, and reject chips

What it does

  • Shield in the bar. Themed like everything else; it takes the urgent color and grows a count as soon as a device is sitting blocked.
  • Live, not polled. State comes from usbguard watch, so the bar reacts the instant a device is plugged in. A 30 second poll backs it up, and the watch reconnects with backoff whenever the daemon goes away.
  • A notification when something is blocked, with a click that opens the panel on the device in question.
  • Allow / block / reject per device. Left click applies the change to this session; right click writes a permanent rule (usbguard ... -p) so it survives a reboot.
  • Device interface classes, so you can see that the stick you just plugged in also claims to be a keyboard before you allow it.
  • No sudo, no polkit. The widget talks to usbguard-daemon over its IPC socket as your own user. The one privileged thing it offers — editing the rule file — is handed to sudoedit in a terminal.

Requirements

  • Omarchy 4.x (Quattro), i.e. the Quickshell-based omarchy-shell
  • usbguard, with usbguard-daemon running and your user in IPCAllowedUsers

setup.sh does all of that for you.

External dependencies, privileges, and services

Everything the plugin shells out to, and why:

Command Where Privilege Why
usbguard list-devices / watch widget, continuously none — your user, over the daemon's IPC socket Read device state and events
usbguard allow-device / block-device / reject-device widget, on your click none — same IPC socket Apply a policy decision
omarchy-notification-send widget, when a device is blocked none Raise the notification
omarchy-launch-floating-terminal-with-presentation widget, Rules / Run setup buttons none itself Open a terminal for the two commands below
sudoedit /etc/usbguard/rules.conf that terminal, Rules button root, interactive Edit the rule file
setup.sh that terminal, or by hand root, interactive, and only what it prints See below

The widget itself never elevates and never runs a second Quickshell process. Installing the plugin runs no code at all — omarchy plugin add only clones files — so setup.sh runs when, and only when, you run it.

setup.sh uses sudo for: pacman -S usbguard; writing /etc/usbguard/rules.conf (the existing file is backed up first, and kept untouched unless you pass --regenerate-policy); five keys in /etc/usbguard/usbguard-daemon.conf (IPCAllowedUsers, which it merges rather than replaces, plus the four policy targets listed above); /etc/usbguard/.omaguard-setup-state, the record of what it changed; and systemctl enable --now usbguard.service. It touches nothing under $HOME, installs no sudoers rule, and asks before any of it. All of it is reversible with setup.sh --undo.

Install

omarchy plugin add https://github.com/fcsonline/omaguard --enable
~/.config/omarchy/plugins/io.github.fcsonline.omaguard/setup.sh

The plugin lands in ~/.config/omarchy/plugins/io.github.fcsonline.omaguard/ (the directory is named after the manifest id, not the repo).

Place the widget wherever you want it:

omarchy bar move io.github.fcsonline.omaguard --section right

What setup.sh does

  1. Installs usbguard.
  2. Generates the baseline policy from the devices connected right now, so the hardware you are using keeps working (usbguard generate-policy).
  3. Adds your user to IPCAllowedUsers in /etc/usbguard/usbguard-daemon.conf, which is what lets the widget work without elevation.
  4. Sets ImplicitPolicyTarget=block and InsertedDevicePolicy=apply-policy: anything plugged in from now on is blocked until you allow it.
  5. Enables and starts usbguard.service.

It is idempotent — run it again after plugging in hardware you want in the baseline, with --regenerate-policy to rebuild the rule file (the old one is backed up first). --yes skips the prompt, --user <name> grants IPC access to someone other than the invoking user.

Every file it touches is copied aside before the first edit, and what it did is recorded in /etc/usbguard/.omaguard-setup-state, so setup.sh --undo puts the machine back: the daemon config restored from that copy, the policy file restored or removed, the service stopped and disabled. It leaves the usbguard package alone and prints the pacman -Rns line instead of running it.

Plug in everything you rely on before running it, and keep a wired keyboard attached while you test. USBGuard's whole job is to stop the kernel from authorizing devices your policy does not cover, and that includes the keyboard you would need to undo it.

setup.sh deliberately leaves PresentDevicePolicy=keep, so devices that are already connected when the daemon starts are never de-authorized — a policy generated at an awkward moment cannot lock you out at boot. Once you trust your rule file, switch it to apply-policy for a stricter setup.

Using it

Bar

Action What happens
Left click Open/close the panel
Right click Re-read the device list

Panel

Key Action
j / k, arrows Move the cursor
Enter / Space Toggle the selected device between allowed and blocked
a / A Allow for this session / permanently
b / B Block for this session / permanently
x Reject the selected device
r Refresh
e Edit the rule file with sudoedit
Esc Close

Mouse: hover moves the cursor, but only the three chips on a row change anything — a row click never changes a policy by accident. Left click on a chip acts for this session, right click writes a permanent rule. The chip matching a device's current state is shown as selected, so right-clicking a highlighted Allow is how you make a device you already trust permanent.

The dot on the left of each row is the device's current target: accent for allowed, urgent for blocked, dim for rejected. A device whose interface list claims both HID and mass storage gets its detail line in the urgent color — that combination is the classic BadUSB shape.

Settings

Set these per widget instance in ~/.config/omarchy/shell.json, or through Setup > Bar:

Key Default What it does
refreshIntervalSec 30 Backstop poll interval; events arrive live regardless
notifyOnBlocked true Raise a notification when an inserted device is blocked
rulesPath /etc/usbguard/rules.conf What the Rules button opens
{ "id": "io.github.fcsonline.omaguard", "refreshIntervalSec": 15, "notifyOnBlocked": true }

IPC

The widget registers its own IPC target, so scripts and keybinds can drive it:

omarchy-shell io.github.fcsonline.omaguard toggle     # open/close the panel
omarchy-shell io.github.fcsonline.omaguard refresh
omarchy-shell io.github.fcsonline.omaguard status     # JSON: counts and daemon health
omarchy-shell io.github.fcsonline.omaguard allow 9    # by usbguard device id
omarchy-shell io.github.fcsonline.omaguard block 9
omarchy-shell io.github.fcsonline.omaguard reject 9

Only digits are accepted as a device id; usbguard allow-device also takes a whole rule, and this never passes one on.

Notes on trust

A USB device supplies its own name and serial. Both are attacker-controlled strings, so:

  • everything that reaches a label is stripped of control characters and truncated (Model.sanitize)
  • every Text in the panel is pinned to Text.PlainText. QML's default is Text.AutoText, which sniffs a string and switches to rich text on its own — a device that called itself <img src="http://…"> would otherwise have the panel fetch it
  • the rule tokenizer honours usbguard's backslash escaping, so a device whose name contains a " cannot end the value early and push the rest of its name back through the parser as attribute/value pairs. Before that, a stick named Ultra Fit" dropped its own with-interface list — and the BadUSB warning that depends on it — out of the panel
  • notifications go out through omarchy-notification-send, which passes the text to the notification daemon as typed D-Bus parameters rather than as command-line arguments; the strings are stripped of leading dashes on the way in, and HTML-escaped, because a notification body is markup
  • notifications are capped as a whole, not just per device, so a device that re-enumerates under a fresh identity cannot spray critical toasts
  • device ids are validated as digits before they reach a command line
  • paths handed to the terminal launcher are shell-quoted: that launcher joins its arguments with $* and runs the result through bash -c

The plugin itself runs unsandboxed inside omarchy-shell, like every Omarchy plugin. Read it before you enable it.

Uninstall

~/.config/omarchy/plugins/io.github.fcsonline.omaguard/setup.sh --undo
omarchy plugin remove io.github.fcsonline.omaguard

--undo restores /etc/usbguard/usbguard-daemon.conf (including the IPCAllowedUsers entry setup.sh added), restores or removes /etc/usbguard/rules.conf, and stops and disables usbguard.service. Run it before removing the plugin, while the script is still on disk. To drop the package too:

sudo pacman -Rns usbguard

Development

omarchy plugin validate .
qmllint -I "$OMARCHY_PATH/shell" Panel.qml Service.qml   # qs.* imports resolve from there
qs log -p "$OMARCHY_PATH/shell" --tail 100

Saving a file under ~/.config/omarchy/plugins/ reloads the plugin automatically; omarchy-shell shell rescanPlugins forces it.

Layout:

File What it is
Panel.qml Bar widget and panel (the barWidget entry point)
Service.qml usbguard CLI plumbing: watch stream, polling, actions
Model.js Rule/event parsing and presentation helpers
setup.sh Installs and configures USBGuard

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages