Skip to content

Commit fd5b2cc

Browse files
sezanzebbranan
andauthored
Escape portions of paths not intended to be globbed on (#978)
Co-authored-by: Branan Riley <[email protected]>
1 parent 057663a commit fd5b2cc

File tree

7 files changed

+52
-40
lines changed

7 files changed

+52
-40
lines changed

inputremapper/gui/data_manager.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def get_preset_names(self) -> Tuple[Name, ...]:
187187
device_folder = PathUtils.get_preset_path(self.active_group.name)
188188
PathUtils.mkdir(device_folder)
189189

190-
paths = glob.glob(os.path.join(device_folder, "*.json"))
190+
paths = glob.glob(os.path.join(glob.escape(device_folder), "*.json"))
191191
presets = [
192192
os.path.splitext(os.path.basename(path))[0]
193193
for path in sorted(paths, key=os.path.getmtime)
@@ -231,7 +231,11 @@ def set_autoload(self, status: bool):
231231
def get_newest_group_key(self) -> GroupKey:
232232
"""group_key of the group with the most recently modified preset."""
233233
paths = []
234-
for path in glob.glob(os.path.join(PathUtils.get_preset_path(), "*/*.json")):
234+
pattern = os.path.join(
235+
glob.escape(PathUtils.get_preset_path()),
236+
"*/*.json",
237+
)
238+
for path in glob.glob(pattern):
235239
if self._reader_client.groups.find(key=PathUtils.split_all(path)[-2]):
236240
paths.append((path, os.path.getmtime(path)))
237241

@@ -246,14 +250,11 @@ def get_newest_preset_name(self) -> Name:
246250
if not self.active_group:
247251
raise DataManagementError("Cannot find newest preset: Group is not set")
248252

249-
paths = [
250-
(path, os.path.getmtime(path))
251-
for path in glob.glob(
252-
os.path.join(
253-
PathUtils.get_preset_path(self.active_group.name), "*.json"
254-
)
255-
)
256-
]
253+
pattern = os.path.join(
254+
glob.escape(PathUtils.get_preset_path(self.active_group.name)),
255+
"*.json",
256+
)
257+
paths = [(path, os.path.getmtime(path)) for path in glob.glob(pattern)]
257258
if not paths:
258259
raise FileNotFoundError()
259260

tests/lib/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class _Fixtures:
213213
capabilities={evdev.ecodes.EV_KEY: keyboard_keys},
214214
phys="usb-0000:03:00.0-3/input1",
215215
info=evdev.device.DeviceInfo(2, 1, 2, 1),
216-
name="Qux/Device?",
216+
name="Qux/[Device]?",
217217
path="/dev/input/event52",
218218
)
219219

tests/unit/test_controller.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def f(groups):
135135
self.message_broker.subscribe(MessageType.groups, f)
136136
self.message_broker.signal(MessageType.init)
137137
self.assertEqual(
138-
["Foo Device", "Foo Device 2", "Bar Device", "gamepad", "Qux/Device?"],
138+
["Foo Device", "Foo Device 2", "Bar Device", "gamepad", "Qux/[Device]?"],
139139
list(calls[-1].groups.keys()),
140140
)
141141

@@ -408,36 +408,38 @@ def test_rename_preset(self):
408408
self.assertTrue(os.path.exists(PathUtils.get_preset_path("Foo Device", "foo")))
409409

410410
def test_rename_preset_sanitized(self):
411-
Preset(PathUtils.get_preset_path("Qux/Device?", "bla")).save()
411+
Preset(PathUtils.get_preset_path("Qux/[Device]?", "bla")).save()
412412

413-
self.assertTrue(os.path.isfile(PathUtils.get_preset_path("Qux/Device?", "bla")))
413+
self.assertTrue(
414+
os.path.isfile(PathUtils.get_preset_path("Qux/[Device]?", "bla"))
415+
)
414416
self.assertFalse(
415-
os.path.exists(PathUtils.get_preset_path("Qux/Device?", "blubb"))
417+
os.path.exists(PathUtils.get_preset_path("Qux/[Device]?", "blubb"))
416418
)
417419

418-
self.data_manager.load_group("Qux/Device?")
420+
self.data_manager.load_group("Qux/[Device]?")
419421
self.data_manager.load_preset("bla")
420422
self.controller.rename_preset(new_name="foo:/bar")
421423

422424
# all functions expect the true name, which is also shown to the user, but on
423425
# the file system it always uses sanitized names.
424426
self.assertTrue(
425-
os.path.exists(PathUtils.get_preset_path("Qux/Device?", "foo__bar"))
427+
os.path.exists(PathUtils.get_preset_path("Qux/[Device]?", "foo__bar"))
426428
)
427429

428430
# since the name is never stored in an un-sanitized way, this can't work
429431
self.assertFalse(
430-
os.path.exists(PathUtils.get_preset_path("Qux/Device?", "foo:/bar"))
432+
os.path.exists(PathUtils.get_preset_path("Qux/[Device]?", "foo:/bar"))
431433
)
432434

433435
path = os.path.join(
434-
PathUtils.config_path(), "presets", "Qux_Device_", "foo__bar.json"
436+
PathUtils.config_path(), "presets", "Qux_[Device]_", "foo__bar.json"
435437
)
436438
self.assertTrue(os.path.exists(path))
437439

438440
# using the sanitized name in function calls works as well
439441
self.assertTrue(
440-
os.path.isfile(PathUtils.get_preset_path("Qux_Device_", "foo__bar"))
442+
os.path.isfile(PathUtils.get_preset_path("Qux_[Device]_", "foo__bar"))
441443
)
442444

443445
def test_rename_preset_should_pick_available_name(self):

tests/unit/test_daemon.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def test_xmodmap_file(self):
390390
self.assertEqual(event.value, 1)
391391

392392
def test_start_stop(self):
393-
group_key = "Qux/Device?"
393+
group_key = "Qux/[Device]?"
394394
group = groups.find(key=group_key)
395395
preset_name = "preset8"
396396

@@ -463,7 +463,7 @@ def test_start_stop(self):
463463

464464
def test_autoload(self):
465465
preset_name = "preset7"
466-
group_key = "Qux/Device?"
466+
group_key = "Qux/[Device]?"
467467
group = groups.find(key=group_key)
468468

469469
daemon = Daemon(self.global_config, self.global_uinputs, self.mapping_parser)

tests/unit/test_data_manager.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,13 @@ def test_delete_preset(self):
352352

353353
def test_delete_preset_sanitized(self):
354354
"""should be able to delete the current preset"""
355-
Preset(PathUtils.get_preset_path("Qux/Device?", "bla")).save()
356-
Preset(PathUtils.get_preset_path("Qux/Device?", "foo")).save()
357-
self.assertTrue(os.path.exists(PathUtils.get_preset_path("Qux/Device?", "bla")))
355+
Preset(PathUtils.get_preset_path("Qux/[Device]?", "bla")).save()
356+
Preset(PathUtils.get_preset_path("Qux/[Device]?", "foo")).save()
357+
self.assertTrue(
358+
os.path.exists(PathUtils.get_preset_path("Qux/[Device]?", "bla"))
359+
)
358360

359-
self.data_manager.load_group(group_key="Qux/Device?")
361+
self.data_manager.load_group(group_key="Qux/[Device]?")
360362
self.data_manager.load_preset(name="bla")
361363
listener = Listener()
362364
self.message_broker.subscribe(MessageType.group, listener)
@@ -373,7 +375,7 @@ def test_delete_preset_sanitized(self):
373375
self.assertEqual(len(listener.calls), 1)
374376

375377
self.assertFalse(
376-
os.path.exists(PathUtils.get_preset_path("Qux/Device?", "bla"))
378+
os.path.exists(PathUtils.get_preset_path("Qux/[Device]?", "bla"))
377379
)
378380

379381
def test_load_mapping(self):
@@ -798,12 +800,12 @@ def test_newest_preset_ignores_unknown_filetypes(self):
798800

799801
self.assertEqual(self.data_manager.get_newest_preset_name(), "preset 3")
800802

801-
def test_newest_group_ignores_unknon_groups(self):
803+
def test_newest_group_ignores_unknown_groups(self):
802804
Preset(PathUtils.get_preset_path("Bar Device", "preset 1")).save()
803805
time.sleep(0.01)
804-
Preset(
805-
PathUtils.get_preset_path("unknown_group", "preset 2")
806-
).save() # not a known group
806+
807+
# not a known group
808+
Preset(PathUtils.get_preset_path("unknown_group", "preset 2")).save()
807809

808810
self.assertEqual(self.data_manager.get_newest_group_key(), "Bar Device")
809811

@@ -857,18 +859,25 @@ def test_available_preset_name_raises_data_management_error(self):
857859
DataManagementError, self.data_manager.get_available_preset_name
858860
)
859861

862+
def test_get_preset_names(self):
863+
self.data_manager.load_group("Qux/[Device]?")
864+
Preset(PathUtils.get_preset_path("Qux/[Device]?", "new preset")).save()
865+
# get_preset_names uses glob, the special characters in the device name
866+
# don't break it.
867+
self.assertEqual(self.data_manager.get_preset_names(), ("new preset",))
868+
860869
def test_available_preset_name_sanitized(self):
861-
self.data_manager.load_group("Qux/Device?")
870+
self.data_manager.load_group("Qux/[Device]?")
862871
self.assertEqual(
863872
self.data_manager.get_available_preset_name(), DEFAULT_PRESET_NAME
864873
)
865874

866-
Preset(PathUtils.get_preset_path("Qux/Device?", DEFAULT_PRESET_NAME)).save()
875+
Preset(PathUtils.get_preset_path("Qux/[Device]?", DEFAULT_PRESET_NAME)).save()
867876
self.assertEqual(
868877
self.data_manager.get_available_preset_name(), f"{DEFAULT_PRESET_NAME} 2"
869878
)
870879

871-
Preset(PathUtils.get_preset_path("Qux/Device?", "foo")).save()
880+
Preset(PathUtils.get_preset_path("Qux/[Device]?", "foo")).save()
872881
self.assertEqual(self.data_manager.get_available_preset_name("foo"), "foo 2")
873882

874883
def test_available_preset_name_increments_default(self):
@@ -906,7 +915,7 @@ def test_should_publish_groups(self):
906915
"Foo Device 2": ["gamepad", "keyboard", "mouse"],
907916
"Bar Device": ["keyboard"],
908917
"gamepad": ["gamepad"],
909-
"Qux/Device?": ["keyboard"],
918+
"Qux/[Device]?": ["keyboard"],
910919
},
911920
)
912921

tests/unit/test_groups.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ def test_find_groups(self):
135135
json.dumps(
136136
{
137137
"paths": ["/dev/input/event52"],
138-
"names": ["Qux/Device?"],
138+
"names": ["Qux/[Device]?"],
139139
"types": [DeviceType.KEYBOARD],
140-
"key": "Qux/Device?",
140+
"key": "Qux/[Device]?",
141141
}
142142
),
143143
]
@@ -157,7 +157,7 @@ def test_list_group_names(self):
157157
"Foo Device",
158158
"Bar Device",
159159
"gamepad",
160-
"Qux/Device?",
160+
"Qux/[Device]?",
161161
],
162162
)
163163

tests/unit/test_reader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -907,9 +907,9 @@ def test_are_new_groups_available(self):
907907
json.dumps(
908908
{
909909
"paths": ["/dev/input/event52"],
910-
"names": ["Qux/Device?"],
910+
"names": ["Qux/[Device]?"],
911911
"types": [DeviceType.KEYBOARD],
912-
"key": "Qux/Device?",
912+
"key": "Qux/[Device]?",
913913
}
914914
),
915915
]

0 commit comments

Comments
 (0)