Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions qui/devices/actionable_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ def __init__(self, vm: backend.VM, device: backend.Device):
super().__init__(vm)
self.vm = vm
self.device = device
if not self.device.is_valid_for_vm(self.vm):
self.backend_label.set_markup(
self.backend_label.get_text() + " <i>(blocked by policy)</i>"
)
self.actionable = False

async def widget_action(self, *_args):
self.device.attach_to_vm(self.vm)
Expand Down
25 changes: 24 additions & 1 deletion qui/devices/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import qubesadmin.devices
import qubesadmin.vm
from qubesadmin.utils import size_to_human
from qubesadmin.device_protocol import DeviceAssignment, DeviceCategory
from qubesadmin.device_protocol import DeviceAssignment, DeviceCategory, DeviceInterface

import gi

Expand All @@ -50,9 +50,12 @@ def __init__(self, vm: qubesadmin.vm.QubesVM):
self._vm = vm
self.name = vm.name
self.vm_class = vm.klass
self._devices_denied = []
self.is_running = True # in most cases, this is just True, unless we're at
# sysusb

self.update_denied_devices()

def __str__(self):
return self.name

Expand Down Expand Up @@ -130,6 +133,18 @@ def toggle_feature_value(self, feature_name, value):
new_feature = " ".join(all_devs)
self._vm.features[feature_name] = new_feature

@property
def devices_denied(self) -> List[DeviceInterface]:
return self._devices_denied

def update_denied_devices(self):
try:
self._devices_denied = DeviceInterface.from_str_bulk(
self._vm.devices_denied
)
except AttributeError:
self._devices_denied = []


class Device:
@classmethod
Expand All @@ -141,6 +156,7 @@ def __init__(self, dev: qubesadmin.devices.DeviceInfo, gtk_app: Gtk.Application)
self._dev: qubesadmin.devices.DeviceInfo = dev
self.__hash = hash(dev)
self._port: str = str(dev.port)
self._interfaces = dev.interfaces
# Monotonic connection timestamp only for new devices
self.connection_timestamp: float = None

Expand Down Expand Up @@ -353,3 +369,10 @@ def detach_from_all(self, with_aux_devices: bool = True):
"""
for vm in self.attachments:
self.detach_from_vm(vm, with_aux_devices)

def is_valid_for_vm(self, vm: VM):
for deny_interface in vm.devices_denied:
for interface in self._interfaces:
if deny_interface.matches(interface):
return False
return True
17 changes: 16 additions & 1 deletion qui/devices/device_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,22 @@ def __init__(self, app_name, qapp, dispatcher):
self.dispatcher.add_handler(
"property-set:template_for_dispvms", self.vm_dispvm_template_change
)

self.dispatcher.add_handler(
"property-reset:template_for_dispvms",
self.vm_dispvm_template_change,
)
self.dispatcher.add_handler(
"property-del:template_for_dispvms", self.vm_dispvm_template_change
)
self.dispatcher.add_handler(
"property-set:devices_denied", self.vm_denied_changed
)
self.dispatcher.add_handler(
"property-reset:devices_denied", self.vm_denied_changed
)
self.dispatcher.add_handler(
"property-del:devices_denied", self.vm_denied_changed
)

self.dispatcher.add_handler(
"domain-feature-set:internal", self.update_internal_feature
Expand Down Expand Up @@ -604,6 +612,13 @@ def vm_dispvm_template_change(self, vm, _event, **_kwargs):
else:
self.dispvm_templates.discard(wrapped_vm)

def vm_denied_changed(self, vm, _event, **_kwargs):
"""devices_denied property changed"""
for wrapped_vm in self.vms:
if wrapped_vm.name == vm.name:
wrapped_vm.update_denied_devices()
return

@staticmethod
def load_css(widget) -> str:
"""Load appropriate css. This should be called whenever menu is shown,
Expand Down