forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdesktop_repair_installer.py
More file actions
131 lines (111 loc) · 4.81 KB
/
Copy pathdesktop_repair_installer.py
File metadata and controls
131 lines (111 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
"""Build static metadata for a verified macOS stable repair installer."""
from __future__ import annotations
import argparse
import html
import json
import re
from pathlib import Path
from typing import Any
from urllib.parse import quote
RELEASE_ID_RE = re.compile(r"^v\d+\.\d+(?:\.\d+)?\+\d+-macos$")
SHA40_RE = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE)
SHA256_RE = re.compile(r"^sha256:[0-9a-f]{64}$", re.IGNORECASE)
def _required_string(data: dict[str, Any], key: str) -> str:
value = data.get(key)
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{key} is required")
return value.strip()
def _validate_bucket(bucket: str) -> str:
if not bucket.startswith("gs://"):
raise ValueError("bucket must use the gs://bucket-name form")
name = bucket.removeprefix("gs://").strip().rstrip("/")
if not name or "/" in name:
raise ValueError("bucket must name exactly one GCS bucket")
return name
def build_repair_bundle(manifest: dict[str, Any], bucket: str) -> dict[str, Any]:
"""Create immutable and latest-stable metadata from a validated manifest."""
bucket_name = _validate_bucket(bucket)
release_id = _required_string(manifest, "release_id")
if not RELEASE_ID_RE.fullmatch(release_id):
raise ValueError("release_id must be a macOS release tag")
if _required_string(manifest, "platform") != "macos":
raise ValueError("repair installers support only the macos platform")
build_number = manifest.get("build_number")
if not isinstance(build_number, int) or isinstance(build_number, bool) or build_number <= 0:
raise ValueError("build_number must be a positive integer")
source_sha = _required_string(manifest, "app_source_sha")
if not SHA40_RE.fullmatch(source_sha):
raise ValueError("app_source_sha has an invalid digest")
dmg_sha256 = _required_string(manifest, "dmg_sha256")
if not SHA256_RE.fullmatch(dmg_sha256):
raise ValueError("dmg_sha256 has an invalid digest")
release_path = quote(release_id, safe=".-_~+")
public_base = f"https://storage.googleapis.com/{quote(bucket_name, safe='.-_~')}"
repair_object = f"stable/{release_id}/repair.json"
installer_url = _required_string(manifest, "dmg_url")
repair_manifest_url = f"{public_base}/stable/{release_path}/repair.json"
repair = {
"schema_version": 1,
"channel": "stable",
"release_id": release_id,
"version": _required_string(manifest, "version"),
"build_number": build_number,
"installer_url": installer_url,
"installer_sha256": dmg_sha256.lower(),
"source_sha": source_sha.lower(),
"published_at": _required_string(manifest, "published_at"),
}
latest = {**repair, "repair_manifest_url": repair_manifest_url}
version = html.escape(repair["version"])
safe_installer_url = html.escape(installer_url, quote=True)
landing_page = f"""<!doctype html>
<html lang=\"en\">
<head>
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
<title>Download Omi for macOS</title>
</head>
<body>
<main>
<h1>Download Omi for macOS</h1>
<p>Stable version {version} is ready to install.</p>
<p><a href=\"{safe_installer_url}\">Download the verified Omi installer</a></p>
<ol>
<li>Open the downloaded DMG.</li>
<li>Move Omi to the <code>/Applications</code> folder.</li>
<li>Open Omi from <code>/Applications</code> to finish the update.</li>
</ol>
</main>
</body>
</html>
"""
return {
"repair_object": repair_object,
"repair": repair,
"latest": latest,
"landing_page": landing_page,
}
def write_repair_bundle(manifest: dict[str, Any], bucket: str, output_dir: Path) -> dict[str, Any]:
bundle = build_repair_bundle(manifest, bucket)
output_dir.mkdir(parents=True, exist_ok=True)
(output_dir / "repair.json").write_text(json.dumps(bundle["repair"], indent=2) + "\n")
(output_dir / "latest.json").write_text(json.dumps(bundle["latest"], indent=2) + "\n")
(output_dir / "index.html").write_text(bundle["landing_page"])
return bundle
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--manifest", required=True)
parser.add_argument("--bucket", required=True)
parser.add_argument("--output-dir", required=True)
args = parser.parse_args()
manifest = json.loads(Path(args.manifest).read_text())
if not isinstance(manifest, dict):
raise ValueError("manifest must be a JSON object")
bundle = write_repair_bundle(manifest, args.bucket, Path(args.output_dir))
print(
json.dumps({"installer_url": bundle["repair"]["installer_url"], "release_id": bundle["repair"]["release_id"]})
)
return 0
if __name__ == "__main__":
raise SystemExit(main())