import stat import tempfile import unittest import zipfile from pathlib import Path from chinatravel.ui.archive import SubmissionArchiveError, extract_submission_archive class SubmissionArchiveTests(unittest.TestCase): def _archive(self, root, entries): path = Path(root) / "submission.zip" with zipfile.ZipFile(path, "w") as archive: for name, value in entries: if isinstance(value, zipfile.ZipInfo): archive.writestr(value, "target") else: archive.writestr(name, value) return path def test_extracts_json_from_outer_directory(self): with tempfile.TemporaryDirectory() as root: archive = self._archive( root, [ ("team/uid-1.json", "{}"), ("team/README.txt", "ignored"), ("__MACOSX/._uid-1.json", "ignored"), ], ) output = Path(root) / "output" summary = extract_submission_archive(archive, output) self.assertEqual(summary.json_files, 1) self.assertEqual((output / "team" / "uid-1.json").read_text(), "{}") self.assertFalse((output / "team" / "README.txt").exists()) def test_rejects_parent_path(self): with tempfile.TemporaryDirectory() as root: archive = self._archive(root, [("../uid.json", "{}")]) with self.assertRaisesRegex(SubmissionArchiveError, "Unsafe archive path"): extract_submission_archive(archive, Path(root) / "output") def test_rejects_duplicate_uid_filenames(self): with tempfile.TemporaryDirectory() as root: archive = self._archive( root, [("first/uid.json", "{}"), ("second/uid.json", "{}")], ) with self.assertRaisesRegex(SubmissionArchiveError, "Duplicate"): extract_submission_archive(archive, Path(root) / "output") def test_rejects_symbolic_link(self): with tempfile.TemporaryDirectory() as root: link = zipfile.ZipInfo("uid.json") link.create_system = 3 link.external_attr = (stat.S_IFLNK | 0o777) << 16 archive = self._archive(root, [("uid.json", link)]) with self.assertRaisesRegex(SubmissionArchiveError, "Symbolic links"): extract_submission_archive(archive, Path(root) / "output") if __name__ == "__main__": unittest.main()