e6d1ebd152
gates / gates (push) Successful in 28s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
38 lines
2.7 KiB
Python
38 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""fg_setup.py — on 9202 (controller 0.287.0, drill catalog): two family members through the dashboard's Család card
|
|
(POST /family/members/add — the card's own call), then MeTube and Grimmory installed through the product, and Grimmory's
|
|
first admin made by the household through the SETUP gate (it is setup-gated AND family-gated). Secrets → 0600 scratch."""
|
|
import json, os, re, subprocess, sys, time
|
|
from fg import *
|
|
SC = w.SC
|
|
log = open(f"{w.EV}/setup.txt", "a", buffering=1)
|
|
def say(*a):
|
|
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
|
w.login()
|
|
say(f"##### family gate live setup on 9202 — controller {w.guest('docker inspect felhom-controller --format {{.Config.Image}}').strip()} | {time.strftime('%FT%TZ', time.gmtime())}")
|
|
sess = dash_session(); csrf = open(f"{SC}/csrf{os.getpid()}.txt").read().strip()
|
|
fam = {}
|
|
for name in ("anna", "bela"):
|
|
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", "-H", f"X-CSRF-Token: {csrf}",
|
|
"-X", "POST", "--data", f"name={name}", f"{w.BASE}/family/members/add"], capture_output=True, text=True)
|
|
d = json.loads(r.stdout)
|
|
fam[name] = d["data"]["password"]
|
|
say(f"Család card: add {name} -> ok={d['ok']} members={d['data']['members']} password returned ONCE (len {len(fam[name])}, not printed)")
|
|
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", f"{w.BASE}/settings/security"], capture_output=True, text=True)
|
|
say("the security page carries the card:", 'id="family-card"' in r.stdout, "| and no member password:", not any(p in r.stdout for p in fam.values()))
|
|
json.dump(fam, open(f"{SC}/fam.json", "w")); os.chmod(f"{SC}/fam.json", 0o600)
|
|
for app, sub in (("metube", "video"), ("grimmory", "library")):
|
|
say(f"deploy {app} ->", w.deploy(app, sub))
|
|
say(f" {app} family-gate file:", w.guest(f"ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'family-gate-{app}|setup-gate-{app}' | tr '\\n' ' '"))
|
|
w.wait_app("library", "/api/v1/healthcheck", want=("200",), tries=90)
|
|
pw = "Gm-" + __import__("secrets").token_hex(10)
|
|
c, h, b = lan(f"library.{DOM}", "/api/v1/setup", method="POST", cookie=w.gate_cookie("library"),
|
|
hdrs=("Content-Type: application/json",), data=json.dumps({"username": "admin", "password": pw, "email": "admin@felhom.invalid", "name": "Felhom"}))
|
|
say("grimmory: the household makes the first admin THROUGH THE SETUP GATE ->", c)
|
|
json.dump({"admin_pw": pw}, open(f"{SC}/gm.json", "w")); os.chmod(f"{SC}/gm.json", 0o600)
|
|
for i in range(40):
|
|
files = w.guest("ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'grimmory' | tr '\\n' ' '")
|
|
if "setup-gate-grimmory" not in files: break
|
|
time.sleep(5)
|
|
say(f"grimmory: setup gate opened by its probe after ~{5*i} s; files now: {files}")
|