#!/usr/bin/env python3 """fg_b4_member.py — B4 part 2: a family member signs in through the REAL internet (Cloudflare → demo-hp's tunnel) with a browser's user agent. Attempt 2 of fg_b4.py used Python's urllib, whose user agent Cloudflare refuses at its edge (403, "error code 1010") before the box — measured. MeTube is installed through the product, a test member is added on the Család card, the member signs in with curl (cookie jar, browser UA) on the box's own page, reaches MeTube, then logs out (and is refused after); a stranger's cookie-less request is refused through the same path. Then MeTube is removed with its data and the member removed. Secrets never printed. Evidence: $EV/B4/member-internet.txt.""" import html, json, os, re, secrets, subprocess, sys, tempfile, time os.environ.setdefault("GUEST", "9201"); os.environ.setdefault("BASE", "https://192.168.0.155") sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import fg_b4_lib as L w = L.w log = open(f"{w.EV}/B4/member-internet.txt", "a", buffering=1) def say(*a): w.say(*a); log.write(" ".join(map(str, a)) + "\n") UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0 Safari/537.36" jar = tempfile.mktemp(prefix="b4jar-") def c(url, *a, data=None): args = ["curl", "-s", "-L", "--max-time", "30", "-A", UA, "-b", jar, "-c", jar, "-H", "Accept: text/html", "-o", "/tmp/b4body", "-w", "%{http_code} %{url_effective}"] if data is not None: args += ["--data", data] r = subprocess.run(args + list(a) + [url], capture_output=True, text=True) code, _, eff = r.stdout.strip().partition(" ") body = open("/tmp/b4body", encoding="utf-8", errors="replace").read() if os.path.exists("/tmp/b4body") else "" return code, eff.split("?")[0], body w.login() say(f"##### B4 member through the real internet — {time.strftime('%FT%TZ', time.gmtime())}") say("control: Python's user agent at the edge ->", subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-A", "Python-urllib/3.13", "https://video.enkisfelhom.hu/"], capture_output=True, text=True).stdout, "| a browser's ->", subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-A", UA, "https://video.enkisfelhom.hu/"], capture_output=True, text=True).stdout, "(MeTube not installed yet: 404 from the box)") L.deploy("metube", "video", say) fpw = L.add_member("b4teszt", say) code, url, body = c("https://video.enkisfelhom.hu/") say(f"a member's browser opens video.enkisfelhom.hu (no cookie) -> {code} at {url} (the family sign-in page: {'name=\"_ft\"' in body})") ft = re.search(r'name="_ft" value="([^"]+)"', body); rd = re.search(r'name="rd" value="([^"]*)"', body) form = "&".join(f"{k}={__import__('urllib.parse').parse.quote(v)}" for k, v in (("_ft", ft.group(1) if ft else ""), ("rd", html.unescape(rd.group(1)) if rd else ""), ("name", "b4teszt"), ("password", fpw))) code, url, body = c("https://felhom.enkisfelhom.hu/__family/login", data=form) say(f"the member signs in on the box's own page -> {code} at {url} (MeTube's own page: {'MeTube' in body and 'name=\"_ft\"' not in body})") code, url, body = c("https://video.enkisfelhom.hu/history") say(f"the member reads /history -> {code} ({'done' in body})") code, url, body = c("https://felhom.enkisfelhom.hu/launcher") say(f"the same browser at the DASHBOARD (/launcher) -> {code} at {url} (sent to the dashboard login: {'/login' in url})") code, url, body = c("https://felhom.enkisfelhom.hu/__family/logout", data="") code2, url2, _ = c("https://video.enkisfelhom.hu/history") say(f"logout -> {code}; then /history -> {code2} at {url2} (refused: {'video.' not in url2 or code2 != '200'})") say("a STRANGER (no cookie, browser UA) at video.enkisfelhom.hu/history ->", subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-A", UA, "https://video.enkisfelhom.hu/history"], capture_output=True, text=True).stdout) L.remove("metube", say) L.remove_member("b4teszt", say) os.unlink(jar)