| 1 | #!/usr/bin/env python3 |
| 2 | import hashlib |
| 3 | import json |
| 4 | from pathlib import Path |
| 5 | import re |
| 6 | import sys |
| 7 | |
| 8 | |
| 9 | folder = Path(sys.argv[1]) |
| 10 | if not folder.is_dir(): |
| 11 | raise SystemExit("Legacy handoff directory is unavailable") |
| 12 | folder = folder.resolve(strict=True) |
| 13 | database = sys.argv[2] |
| 14 | if folder.parent != Path("/mnt/storage1/apps/studio-handoff") or not re.fullmatch(r"\d{8}T\d{6}Z-[0-9a-f]{6}", folder.name): |
| 15 | raise ValueError("Unexpected legacy handoff directory") |
| 16 | if database not in {"evil-forgejo", "evil-hedgedoc"}: |
| 17 | raise ValueError("Unexpected legacy database") |
| 18 | manifest = json.loads((folder / "manifest.json").read_text()) |
| 19 | if manifest["id"] != folder.name: |
| 20 | raise ValueError("Legacy handoff ID changed") |
| 21 | entry = manifest["databases"][database] |
| 22 | if entry["file"] != database + ".dump": |
| 23 | raise ValueError("Legacy dump filename changed") |
| 24 | dump = folder / entry["file"] |
| 25 | digest = hashlib.sha256() |
| 26 | with dump.open("rb") as file: |
| 27 | for chunk in iter(lambda: file.read(1024 * 1024), b""): |
| 28 | digest.update(chunk) |
| 29 | if dump.stat().st_size != entry["bytes"] or digest.hexdigest() != entry["sha256"]: |
| 30 | raise ValueError("Legacy dump checksum mismatch") |
| 31 | if len(entry["counts"]) != (4 if database == "evil-hedgedoc" else 2) or any(not isinstance(value, int) or value < 0 for value in entry["counts"]): |
| 32 | raise ValueError("Legacy database counts are invalid") |
| 33 | if database == "evil-forgejo": |
| 34 | keys = {"lfs_jwt", "oauth_jwt", "security_key", "internal_token", "anubis_key", "mailer_address", "mailer_username", "mailer_password"} |
| 35 | if set(entry["secretSha256"]) != keys or any(not re.fullmatch(r"[0-9a-f]{64}", value) for value in entry["secretSha256"].values()): |
| 36 | raise ValueError("Legacy Forgejo secret fingerprints are invalid") |
| 37 | print(json.dumps(entry)) |