From 6cb83289574c6f87622cad908e1db840ea92d259 Mon Sep 17 00:00:00 2001 From: Kairo de Araujo Date: Thu, 6 Jan 2022 09:10:27 +0100 Subject: [PATCH] explicit encode role names This commit explicitly encodes role names. Mostly this encoding is already happening in ``requests`` for what is not a URL. The "/" in a role name will now be encoded. Also, a slight change in the RepositorySimulator will align with the tests. This commit partially covers issue #1634 Signed-off-by: Kairo de Araujo --- tests/repository_simulator.py | 1 + tests/test_updater_delegation_graphs.py | 54 +++++++++++++++++++++++++ tuf/ngclient/updater.py | 5 ++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index 39535ef26b..270b3fca2b 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -258,6 +258,7 @@ def fetch_metadata(self, role: str, version: Optional[int] = None) -> bytes: If version is None, non-versioned metadata is being requested. """ + role = parse.unquote(role, encoding="utf-8") self.fetch_tracker.metadata.append((role, version)) if role == Root.type: diff --git a/tests/test_updater_delegation_graphs.py b/tests/test_updater_delegation_graphs.py index a5ef66291a..95229bf812 100644 --- a/tests/test_updater_delegation_graphs.py +++ b/tests/test_updater_delegation_graphs.py @@ -430,6 +430,60 @@ def test_targetfile_search(self, test_data: TargetTestCase) -> None: self.teardown_subtest() +class TestTargetEncodedFileSearch(TestDelegations): + r""" + Create a single repository with the following delegations with encoded roles + names + """ + + delegations = DelegationsTestCase( + delegations=[ + TestDelegation("targets", "ö", paths=["project_ö\\*"]), + TestDelegation("targets", "ç", paths=["project_ç/*"]), + TestDelegation("targets", "Á/", paths=["project_Á//*"]) + ], + target_files=[ + TestTarget("ö", b"content", "project_ö\\file_ö.txt"), + TestTarget("ç", b"content", "project_ç/file_ç.txt"), + TestTarget("Á/", b"content", "project_Á//file_Á.txt"), + ], + ) + + def setUp(self) -> None: + super().setUp() + self._init_repo(self.delegations) + + # fmt: off + targets: utils.DataSet = { + "targetpath delegated to ö": + TargetTestCase("project_ö\\file_ö.txt", True, ["ö"]), + "targetpath delegated to ç": + TargetTestCase("project_ç/file_ç.txt", True, ["ç"]), + "targetpaht deletated to Á/": + TargetTestCase("project_Á//file_Á.txt", True, ["Á/"]) + } + # fmt: on + + @utils.run_sub_tests_with_dataset(targets) + def test_targetfile_search(self, test_data: TargetTestCase) -> None: + self.setup_subtest() + + # get expected target + expected_target = self.sim.target_files[ + test_data.targetpath + ].target_file + + updater = self._init_updater() + # Call explicitly refresh to simplify the expected_calls list + updater.refresh() + self.sim.fetch_tracker.metadata.clear() + target = updater.get_targetinfo(test_data.targetpath) + assert target is not None + self.assertDictEqual(target.to_dict(), expected_target.to_dict()) + + self.teardown_subtest() + + if __name__ == "__main__": if "--dump" in sys.argv: TestDelegations.dump_dir = tempfile.mkdtemp() diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index f4c5b24249..bd940425ed 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -290,10 +290,11 @@ def _download_metadata( self, rolename: str, length: int, version: Optional[int] = None ) -> bytes: """Download a metadata file and return it as bytes""" + encoded_name = parse.quote(rolename, "") if version is None: - url = f"{self._metadata_base_url}{rolename}.json" + url = f"{self._metadata_base_url}{encoded_name}.json" else: - url = f"{self._metadata_base_url}{version}.{rolename}.json" + url = f"{self._metadata_base_url}{version}.{encoded_name}.json" return self._fetcher.download_bytes(url, length) def _load_local_metadata(self, rolename: str) -> bytes: