diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index bede5b221..a365b28e3 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -149,6 +149,19 @@ class AddonMeta: ) +def package_name_valid(name: str) -> bool: + # embedded /? + base = os.path.basename(name) + if base != name: + return False + # tries to escape to parent? + root = os.getcwd() + subfolder = os.path.abspath(os.path.join(root, name)) + if root.startswith(subfolder): + return False + return True + + # fixme: this class should not have any GUI code in it class AddonManager: @@ -202,7 +215,7 @@ class AddonManager: def addonsFolder(self, dir: Optional[str] = None) -> str: root = self.mw.pm.addonFolder() - if not dir: + if dir is None: return root return os.path.join(root, dir) @@ -381,6 +394,8 @@ class AddonManager: if not manifest: return InstallError(errmsg="manifest") package = manifest["package"] + if not package_name_valid(package): + return InstallError(errmsg="invalid package") conflicts = manifest.get("conflicts", []) found_conflicts = self._disableConflicting(package, conflicts) meta = self.addonMeta(package) diff --git a/qt/tests/test_addons.py b/qt/tests/test_addons.py index 366ce22ff..f06955878 100644 --- a/qt/tests/test_addons.py +++ b/qt/tests/test_addons.py @@ -7,7 +7,7 @@ from zipfile import ZipFile from mock import MagicMock -from aqt.addons import AddonManager, extract_update_info +from aqt.addons import AddonManager, extract_update_info, package_name_valid def test_readMinimalManifest(): @@ -94,3 +94,11 @@ def test_update_info(): r = extract_update_info(20, 1, json_info) assert r.current_branch_max_point_ver == -25 assert r.suitable_branch_last_modified == 333 + + +def test_package_name_validation(): + assert not package_name_valid("") + assert not package_name_valid("/") + assert not package_name_valid("a/b") + assert not package_name_valid("..") + assert package_name_valid("ab")