#!/opt/pw/bin/python """bind.py — the household's self-bind page, in real Chromium (rehearsal 2026-10-20, B2). Env (handed in by brun.sh, never on a command line): BIND_TOKEN, PAIRING, PASS. --typo : change ONE character of PASS before sending (a household's typo; the value is never printed) Screenshots are taken BEFORE the fields are filled and AFTER the answer page loads — the passphrase field is type=text, so a filled-form screenshot would show it. Prints the answer page's visible text. usage: bind.py OUTPREFIX [--typo] [--size phone|desktop] [--lang hu|en] [--get-only] """ import os, re, sys from playwright.sync_api import sync_playwright out = sys.argv[1]; args = sys.argv[2:] size = args[args.index("--size") + 1] if "--size" in args else "phone" lang = args[args.index("--lang") + 1] if "--lang" in args else "hu" vp = {"phone": dict(viewport={"width": 390, "height": 844}, device_scale_factor=2, is_mobile=True, has_touch=True), "desktop": dict(viewport={"width": 1366, "height": 768})}[size] loc = {"hu": "hu-HU", "en": "en-US"}[lang] url = "https://hub.felhom.eu/bind/" + os.environ["BIND_TOKEN"] with sync_playwright() as p: b = p.chromium.launch(executable_path="/usr/bin/chromium", args=["--no-sandbox"]) ctx = b.new_context(locale=loc, extra_http_headers={"Accept-Language": loc}, timezone_id="Europe/Budapest", **vp) pg = ctx.new_page() r = pg.goto(url, wait_until="networkidle") pg.screenshot(path=f"{out}-1-open-{size}-{lang}.png", full_page=True) print("GET", r.status, pg.title()) body = pg.inner_text("body") print(re.sub(r"\s+", " ", body)[:600]) if "--get-only" in args or not pg.locator("#pairing_code").count(): b.close(); sys.exit(0) pw = os.environ["PASS"] if "--typo" in args: # swap one inner letter for its neighbour in the alphabet i = len(pw) // 2 while not pw[i].isalpha(): i += 1 pw = pw[:i] + ("b" if pw[i] != "b" else "c") + pw[i + 1:] pg.fill("#pairing_code", os.environ["PAIRING"]) pg.fill("#passphrase", pw) with pg.expect_navigation(wait_until="networkidle"): pg.click("button[type=submit]") # blank both inputs before the screenshot, in case a re-rendered form echoes a value pg.evaluate("document.querySelectorAll('input').forEach(e => e.value = '')") pg.screenshot(path=f"{out}-2-answer-{size}-{lang}.png", full_page=True) print("POST answer:", re.sub(r"\s+", " ", pg.inner_text("body"))[:600]) b.close()