unittests for the new permission checks

xkb
sezanzeb 4 years ago committed by sezanzeb
parent 070e3cc8a4
commit 74da396fd8

@ -90,9 +90,9 @@ def check_injection_rights():
def can_read_devices():
"""Help the user to setup correct permissions."""
"""Get a list of problems before key-mapper can be used properly."""
if getpass.getuser() == 'root':
return None
return []
input_check = check_group('input')
plugdev_check = check_group('plugdev')
@ -100,13 +100,11 @@ def can_read_devices():
# ubuntu. funnily, individual devices in /dev/input/ have write permitted.
can_write = check_injection_rights()
ret = []
if can_write is not None:
ret.append(can_write)
if input_check is not None:
ret.append(input_check)
if plugdev_check is not None:
ret.append(plugdev_check)
ret = [
check for check
in [can_write, input_check, plugdev_check]
if check is not None
]
if len(ret) > 0:
logger.info(

@ -19,37 +19,136 @@
# along with key-mapper. If not, see <https://www.gnu.org/licenses/>.
import os
import grp
import getpass
import subprocess
import unittest
from keymapper.dev.permissions import can_read_devices
from keymapper.dev.permissions import check_injection_rights, check_group, \
can_read_devices
from keymapper.paths import USER
class TestPermissions(unittest.TestCase):
def setUp(self):
self.getgrnam = grp.getgrnam
original_access = os.access
original_getgrnam = grp.getgrnam
original_check_output = subprocess.check_output
original_stat = os.stat
oringal_getuser = getpass.getuser
class TestCheckGroup(unittest.TestCase):
def tearDown(self):
grp.getgrnam = self.getgrnam
# reset all fakes
os.access = original_access
grp.getgrnam = original_getgrnam
subprocess.check_output = original_check_output
os.stat = original_stat
getpass.getuser = oringal_getuser
def test_cannot_access(self):
# TODO modify test
class Grnam:
def __init__(self, group):
self.gr_mem = []
def test_check_injection_rights(self):
can_access = False
os.access = lambda *args: can_access
self.assertIsNotNone(check_injection_rights())
can_access = True
self.assertIsNone(check_injection_rights())
def fake_setup(self):
"""Patch some functions to have the following fake environment:
Groups
------
input: id: 0, members: $USER, used in /dev, set up
plugdev: id: 1, members: $USER, used in /dev, not in `groups`
foobar: id: 2, no members, used in /dev
a_unused: id: 0, members: $USER, not used in /dev, set up
b_unused: id: 1, members: $USER, not used in /dev, not in `groups`
c_unused: id: 2, no members, not used in /dev
"""
gr_mems = {
'input': (0, [USER]),
'plugdev': (1, [USER]),
'foobar': (2, []),
'a_unused': (3, [USER]),
'b_unused': (4, [USER]),
'c_unused': (5, [])
}
stat_counter = 0
grp.getgrnam = Grnam
self.assertFalse(can_read_devices()[0])
class stat:
def __init__(self, path):
nonlocal stat_counter
stat_counter += 1
# make sure stat returns all of those groups at some point.
# only works if there are more than three files in /dev, which
# should be the case
self.st_gid = [0, 1, 2][stat_counter % 3]
def test_can_access(self):
# TODO modify test
class Grnam:
os.stat = stat
class getgrnam:
def __init__(self, group):
self.gr_mem = [USER]
if group not in gr_mems:
raise KeyError()
self.gr_gid = gr_mems[group][0]
self.gr_mem = gr_mems[group][1]
grp.getgrnam = getgrnam
# fake the `groups` output to act like the current session only
# has input and a_unused active
subprocess.check_output = lambda cmd: b'foo input a_unused bar'
def test_can_read_devices(self):
self.fake_setup()
# root user doesn't need this stuff
getpass.getuser = lambda: 'root'
self.assertEqual(len(can_read_devices()), 0)
getpass.getuser = lambda: USER
os.access = lambda *args: False
# plugdev not yet setup correctly and cannot write
self.assertEqual(len(can_read_devices()), 2)
os.access = lambda *args: True
self.assertEqual(len(can_read_devices()), 1)
subprocess.check_output = lambda cmd: b'plugdev input'
self.assertEqual(len(can_read_devices()), 0)
def test_check_group(self):
self.fake_setup()
# correctly setup
self.assertIsNone(check_group('input'))
# session restart required, usermod already done
self.assertIsNotNone(check_group('plugdev'))
self.assertIn('plugdev', check_group('plugdev'))
self.assertNotIn('usermod', check_group('plugdev'))
# usermod required
self.assertIsNotNone(check_group('foobar'))
self.assertIn('foobar', check_group('foobar'))
self.assertIn('usermod', check_group('foobar'))
# don't exist in /dev
self.assertIsNone(check_group('a_unused'))
self.assertIsNone(check_group('b_unused'))
self.assertIsNone(check_group('c_unused'))
# group doesn't exist
self.assertIsNone(check_group('qux'))
def file_not_found_error(cmd):
raise FileNotFoundError()
subprocess.check_output = file_not_found_error
grp.getgrnam = Grnam
self.assertTrue(can_read_devices()[0])
# groups command doesn't exist, so cannot check this suff
self.assertIsNone(check_group('plugdev'))
if __name__ == "__main__":

Loading…
Cancel
Save