Files
felhom.eu/documentation/audits/night-2026-10-28/tools/walk_launcher.py
T

79 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""walk_launcher.py — capability map E8/E9 walked on scratch 9202 (night 2026-10-28), front doors only: the household's
launcher, then the guest link (/s/<token>): enable, open it with NO session, a wrong token, rotate, and put the share back
as found. The token is a capability secret: never printed (redacted to its length)."""
import os, re, sys
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
os.environ.setdefault("SC", "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0b76c4d7-9b39-4e4e-869d-d0d2c6006331/scratchpad/rt-9202")
os.environ.setdefault("TARGET", "9202")
import box_walk as w
EV = "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0b76c4d7-9b39-4e4e-869d-d0d2c6006331/scratchpad/night/p5"
w.login()
SC = os.environ["SC"]
sess = open(f"{SC}/sess{os.getpid()}.txt").read().strip()
csrf = open(f"{SC}/csrf{os.getpid()}.txt").read().strip()
res = {}
def get(path, auth=True):
a = ["curl", "-sk", "-D", "-", "-H", w.HOSTHDR]
if auth:
a += ["-H", f"Cookie: {sess}"]
r = w.sh(a + [f"{w.BASE}{path}"])
head, _, body = (r.stdout or "").replace("\r\n", "\n").partition("\n\n")
m = re.match(r"HTTP/\S+ (\d+)", head)
return (m.group(1) if m else "?"), head, body
def post(path):
r = w.sh(["curl", "-sk", "-D", "-", "-o", "/dev/null", "-H", w.HOSTHDR, "-H", f"Cookie: {sess}", "-X", "POST",
"--data-urlencode", f"_csrf={csrf}", f"{w.BASE}{path}"])
loc = [l for l in (r.stdout or "").split("\n") if l.lower().startswith("location:")]
return (r.stdout or "").split("\n")[0].strip(), (loc[0].strip() if loc else "")
def token_of(body):
m = re.search(r'id="share-link-input"[^>]*value="https?://[^"]*/s/([^"/?#]+)"', body)
return m.group(1) if m else None
code, _, body = get("/launcher")
apps = sorted(set(re.findall(r'https://([a-z0-9-]+)\.' + re.escape(w.DOMAIN), body)) - {"felhom"})
res["launcher"] = {"http": code, "app_links": apps}
w.say(f"E8 launcher: http={code}, app links {apps}")
before = token_of(body)
if os.environ.get("SHARE_WAS_OFF") == "1": # the first run switched it on, then stopped (its regex missed the link)
before = None
res["share_on_before"] = bool(before)
w.say(f"E9 share on before the walk: {bool(before)}")
if not before:
w.say("enable: " + str(post("/launcher/share/enable")))
_, _, body = get("/launcher")
tok = token_of(body)
assert tok, "no share link after enable"
w.say(f"E9 the guest link exists (token length {len(tok)})")
g, head, gbody = get(f"/s/{tok}", auth=False)
admin_links = sorted(set(re.findall(r'href="(/(?:stacks|settings|backups|storage|debug|launcher/share)[^"]*)"', gbody)))
gapps = sorted(set(re.findall(r'https://([a-z0-9-]+)\.' + re.escape(w.DOMAIN), gbody)) - {"felhom"})
res["guest"] = {"http": g, "app_links": gapps, "admin_links": admin_links, "set_cookie": "set-cookie" in head.lower()}
w.say(f"E9 guest link with NO session: http={g}, app links {gapps}, admin links {admin_links}")
bad, _, badbody = get("/s/" + "x" * len(tok), auth=False)
unk, _, unkbody = get("/no-such-route-r1256", auth=False)
res["wrong_token"] = {"http": bad, "same_as_unknown_route": badbody == unkbody, "unknown_http": unk}
w.say(f"E9 a wrong token: http={bad}; byte-identical to an unknown route: {badbody == unkbody} (unknown route http={unk})")
w.say("rotate: " + str(post("/launcher/share/rotate")))
_, _, body = get("/launcher")
tok2 = token_of(body)
o, _, _ = get(f"/s/{tok}", auth=False)
n, _, _ = get(f"/s/{tok2}", auth=False) if tok2 else ("none", "", "")
res["rotate"] = {"old_link_http": o, "new_link_http": n, "token_changed": tok2 != tok}
w.say(f"E9 after rotate: old link http={o}, new link http={n}, changed={tok2 != tok}")
if not before:
w.say("disable (as found): " + str(post("/launcher/share/disable")))
d, _, _ = get(f"/s/{tok2}", auth=False)
res["after_disable_http"] = d
w.say(f"E9 after disable: the link answers http={d}")
import json
json.dump(res, open(os.path.join(EV, "launcher-walk.json"), "w"), indent=1)
open(os.path.join(EV, "launcher-walk.log"), "w").write("\n".join(w.LOG) + "\n")