Skip to content

Commit

Permalink
Changed feature keyboard_layout to a property
Browse files Browse the repository at this point in the history
Purpose: make it easier to implement more robust keyboard layout tools and
propagation.

references QubesOS/qubes-issues#1396
references QubesOS/qubes-issues#4294
  • Loading branch information
marmarta committed Jun 17, 2020
1 parent b889bf9 commit e4b24bb
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 23 deletions.
38 changes: 15 additions & 23 deletions qubes/ext/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,8 @@ def on_domain_qdb_create(self, vm, event):
vm.untrusted_qdb.write('/qubes-gui-domain-xid',
str(vm.guivm.xid))

# Add keyboard layout from that of GuiVM
kbd_layout = vm.guivm.features.get('keyboard-layout', None)
if kbd_layout:
vm.untrusted_qdb.write('/keyboard-layout', kbd_layout)
# Add keyboard layout
vm.untrusted_qdb.write('/keyboard-layout', vm.keyboard_layout)

# Set GuiVM prefix
guivm_windows_prefix = vm.features.get('guivm-windows-prefix', 'GuiVM')
Expand All @@ -121,22 +119,16 @@ def on_domain_start(self, vm, event, **kwargs):
attached_vm.untrusted_qdb.write('/qubes-gui-domain-xid',
str(vm.xid))

@qubes.ext.handler('domain-feature-pre-set:keyboard-layout')
def on_feature_pre_set(self, subject, event, feature, value, oldvalue=None):
untrusted_xkb_layout = value.split('+')
if len(untrusted_xkb_layout) != 3:
raise qubes.exc.QubesValueError("Invalid number of parameters")

untrusted_layout = untrusted_xkb_layout[0]
untrusted_variant = untrusted_xkb_layout[1]
untrusted_options = untrusted_xkb_layout[2]

re_variant = r'^[a-zA-Z0-9-_]*$'
re_options = r'^[a-zA-Z0-9-_:,]*$'

if not untrusted_layout.isalpha():
raise qubes.exc.QubesValueError("Invalid layout provided")
if not re.match(re_variant, untrusted_variant):
raise qubes.exc.QubesValueError("Invalid variant provided")
if not re.match(re_options, untrusted_options):
raise qubes.exc.QubesValueError("Invalid options provided")
@qubes.ext.handler('property-reset:keyboard_layout')
def on_keyboard_reset(self, subject, event, name, oldvalue=None):
if getattr(subject, 'guivm'):
kbd_layout = subject.guivm.keyboard_layout
else:
kbd_layout = 'us++'

subject.untrusted_qdb.write('/keyboard-layout', kbd_layout)

@qubes.ext.handler('property-set:keyboard_layout')
def on_keyboard_set(self, subject, event, name, newvalue, oldvalue=None):
subject.untrusted_qdb.write('/keyboard-layout', newvalue)

8 changes: 8 additions & 0 deletions qubes/vm/adminvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import qubes
import qubes.exc
import qubes.vm
from qubes.vm.qubesvm import _setter_kbd_layout


class AdminVM(qubes.vm.BaseVM):
Expand Down Expand Up @@ -61,6 +62,13 @@ class AdminVM(qubes.vm.BaseVM):
setter=qubes.property.forbidden,
doc='True if this machine may be updated on its own.')

# for changes in keyboard_layout, see also the same property in QubesVM
keyboard_layout = qubes.property(
'keyboard_layout',
type=str,
setter=_setter_kbd_layout,
doc='Keyboard layout for this VM')

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down
33 changes: 33 additions & 0 deletions qubes/vm/qubesvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import asyncio
import base64
import grp
import re
import os
import os.path
import shutil
Expand Down Expand Up @@ -115,6 +116,30 @@ def _setter_virt_mode(self, prop, value):
return value


def _setter_kbd_layout(self, prop, value):
untrusted_xkb_layout = value.split('+')
if len(untrusted_xkb_layout) != 3:
raise qubes.exc.QubesPropertyValueError(
self, prop, value, "invalid number of keyboard layout parameters")

untrusted_layout = untrusted_xkb_layout[0]
untrusted_variant = untrusted_xkb_layout[1]
untrusted_options = untrusted_xkb_layout[2]

re_variant = r'^[a-zA-Z0-9-_]*$'
re_options = r'^[a-zA-Z0-9-_:,]*$'

if not untrusted_layout.isalpha():
raise qubes.exc.QubesPropertyValueError(
self, prop, value, "Invalid keyboard layout provided")
if not re.match(re_variant, untrusted_variant):
raise qubes.exc.QubesPropertyValueError(
self, prop, value, "Invalid laoyout variant provided")
if not re.match(re_options, untrusted_options):
raise qubes.exc.QubesPropertyValueError(
self, prop, value, "Invalid layout options provided")


def _default_virt_mode(self):
if self.devices['pci'].persistent():
return 'hvm'
Expand Down Expand Up @@ -690,6 +715,14 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
setter=qubes.property.forbidden,
doc='True if this machine may be updated on its own.')

# for changes in keyboard_layout, see also the same property in AdminVM
keyboard_layout = qubes.property(
'keyboard_layout',
default=(lambda self: self.guivm.keyboard_layout),
type=str,
setter=_setter_kbd_layout,
doc='Keyboard layout for this VM')

#
# static, class-wide properties
#
Expand Down

0 comments on commit e4b24bb

Please sign in to comment.