72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Install pinned official archives from docs/toolchain.lock.json. No system writes."""
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import tarfile
|
|
import urllib.request
|
|
import zipfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
TOOLS = ROOT / "tools"
|
|
DOWNLOADS = TOOLS / "downloads"
|
|
|
|
def download(url, name, digest=None):
|
|
dest = DOWNLOADS / name
|
|
if not dest.exists():
|
|
part = dest.with_suffix(dest.suffix + ".part")
|
|
with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "verstack-local-setup"}), timeout=120) as src, part.open("wb") as out:
|
|
while chunk := src.read(1024 * 1024):
|
|
out.write(chunk)
|
|
part.rename(dest)
|
|
with dest.open("rb") as stream:
|
|
actual = hashlib.file_digest(stream, "sha256").hexdigest()
|
|
if digest and actual != digest.removeprefix("sha256:"):
|
|
raise ValueError(f"Checksum mismatch: {name}")
|
|
print(f"Verified {name}: sha256:{actual}", flush=True)
|
|
return dest, actual
|
|
|
|
def main():
|
|
DOWNLOADS.mkdir(parents=True, exist_ok=True)
|
|
lock = json.loads((ROOT / "docs/toolchain.lock.json").read_text())
|
|
ghidra = lock["ghidra"]
|
|
archive, digest = download(ghidra["url"], ghidra["url"].rsplit('/', 1)[1], ghidra["sha256"])
|
|
with zipfile.ZipFile(archive) as z:
|
|
folder = z.namelist()[0].split('/')[0]
|
|
if not (TOOLS / folder).exists():
|
|
z.extractall(TOOLS)
|
|
for e in z.infolist():
|
|
mode = e.external_attr >> 16
|
|
if mode:
|
|
(TOOLS / e.filename).chmod(mode & 0o777)
|
|
ghidra_home = TOOLS / folder
|
|
jdk = lock["jdk"]
|
|
java_archive, java_digest = download(jdk["url"], jdk["url"].rsplit('/', 1)[1], jdk["sha256"])
|
|
with tarfile.open(java_archive) as t:
|
|
java_folder = t.getnames()[0].split('/')[0]
|
|
if not (TOOLS / java_folder).exists():
|
|
t.extractall(TOOLS, filter="data")
|
|
java_home = TOOLS / java_folder
|
|
record = {"schema": 1, "ghidra_home": str(ghidra_home), "ghidra_version": ghidra["version"], "ghidra_archive_sha256": digest,
|
|
"java_home": str(java_home), "java_version": jdk["version"], "java_archive_sha256": java_digest}
|
|
(TOOLS / "installed.json").write_text(json.dumps(record, indent=2))
|
|
(TOOLS / "bin").mkdir(exist_ok=True)
|
|
for name, script in [("ghidra", "ghidraRun"), ("ghidra-headless", "support/analyzeHeadless")]:
|
|
launcher = TOOLS / "bin" / name
|
|
launcher.write_text('''#!/usr/bin/env python3
|
|
import json,os,pathlib,sys
|
|
root=pathlib.Path(__file__).resolve().parents[2]
|
|
record=json.loads((root/'tools/installed.json').read_text())
|
|
env=os.environ.copy()
|
|
env['JAVA_HOME']=record['java_home']
|
|
env['XDG_CONFIG_HOME']=str(root/'data/ghidra-user/config')
|
|
env['XDG_CACHE_HOME']=str(root/'data/ghidra-user/cache')
|
|
launcher=str(pathlib.Path(record['ghidra_home'])/SCRIPT)
|
|
os.execve(launcher,[launcher,*sys.argv[1:]],env)
|
|
'''.replace("SCRIPT", repr(script)))
|
|
launcher.chmod(0o755)
|
|
print(json.dumps(record, indent=2))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|