#!/usr/bin/env python3
"""Probe authentication.curogram.com/graphql for the password mutations.
Sends schema-validation probes (placeholder values) to learn which fields/types
exist. Does NOT use the real password. Prints statuses + error messages only."""
import json
import urllib.error
import urllib.request

from websocket import create_connection

PORT = 9223
HOSTS = [
    "https://authentication.curogram.com/graphql",
    "https://api-v2.curogram.com/graphql",
]


def http_json(url):
    with urllib.request.urlopen(url, timeout=10) as r:
        return json.loads(r.read().decode())


def cdp_call(ws, method, params=None, _id=1):
    ws.send(json.dumps({"id": _id, "method": method, "params": params or {}}))
    while True:
        m = json.loads(ws.recv())
        if m.get("id") == _id:
            return m.get("result", {})


tabs = [t for t in http_json(f"http://localhost:{PORT}/json") if t.get("type") == "page"]
tab = next((t for t in tabs if "curogram.com" in (t.get("url") or "").lower()), tabs[0])
ws = create_connection(tab["webSocketDebuggerUrl"], timeout=10)
try:
    res = cdp_call(ws, "Network.getAllCookies")
finally:
    ws.close()
cookies = [c for c in res.get("cookies", []) if "curogram" in (c.get("domain") or "").lower()]
cookie_header = "; ".join(f"{c['name']}={c['value']}" for c in cookies)

H = {"X-Curogram-Frontend": "web", "Accept": "application/json",
     "Content-Type": "application/json", "Cookie": cookie_header}

# String-typed probes so we isolate FIELD existence from scalar-type existence.
PROBES = {
    "setPassword_StringArgs": (
        "mutation($o:String!,$p:String!,$c:String!){setPassword("
        "oldPassword:$o,password:$p,passwordConfirmation:$c)}",
        {"o": "x", "p": "y", "c": "y"},
    ),
    "changePassword_StringArgs": (
        "mutation($p:String!,$c:String!,$t:String!){changePassword("
        "password:$p,passwordConfirmation:$c,token:$t){expiresAt}}",
        {"p": "y", "c": "y", "t": "z"},
    ),
}


def post(url, body):
    req = urllib.request.Request(url, data=json.dumps(body).encode(),
                                 headers=H, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=20) as resp:
            return resp.status, json.loads(resp.read().decode() or "{}")
    except urllib.error.HTTPError as e:
        raw = e.read().decode("utf-8", "replace")
        try:
            return e.code, json.loads(raw)
        except Exception:
            return e.code, {"raw": raw[:300]}


for host in HOSTS:
    for name, (q, v) in PROBES.items():
        s, r = post(host, {"query": q, "variables": v})
        msgs = []
        if isinstance(r, dict) and "errors" in r:
            for e in r["errors"]:
                m = e.get("message") if isinstance(e, dict) else str(e)
                msgs.append(m)
        else:
            msgs = ["NO_GRAPHQL_ERRORS data=" + json.dumps(r.get("data"))
                    if isinstance(r, dict) else str(r)[:120]]
        print(json.dumps({"host": host.split("//")[1].split(".")[0],
                          "probe": name, "status": s, "messages": msgs}))
