#!/usr/bin/env python3
"""Step 1+2: JWT capture from signin RESPONSE + InternalTokenFilter reverse.
Read-only L2. Auto-approved."""
import json, subprocess, sys, re

BASE = "https://grafana.adgentic.tv"
COOKIE = ".session_cookies"


def loki_query(expr, hours=168, max_lines=500):
    payload = json.dumps({
        'queries': [{'refId': 'A', 'datasource': {'uid': 'loki', 'type': 'loki'},
                     'expr': expr, 'queryType': 'range', 'maxLines': max_lines}],
        'from': f'now-{hours}h', 'to': 'now'
    })
    with open('/tmp/lq.json', 'w') as f:
        f.write(payload)
    r = subprocess.run(
        ['curl', '-sk', '-b', COOKIE, '-X', 'POST',
         f'{BASE}/api/ds/query', '-H', 'Content-Type: application/json',
         '-d', '@/tmp/lq.json'],
        capture_output=True, text=True, timeout=60
    )
    try:
        d = json.loads(r.stdout)
        frames = d.get('results', {}).get('A', {}).get('frames', [])
        lines = []
        for f in frames:
            vals = f.get('data', {}).get('values', [])
            if len(vals) > 2:
                lines.extend(vals[2])
        return lines
    except Exception:
        return []


def extract_json_from_message(msg):
    """Extract RESPONSE={...} JSON from LoggingFilter message."""
    m = re.search(r'RESPONSE=(\{.*\})', msg)
    if m:
        try:
            return json.loads(m.group(1))
        except Exception:
            raw = m.group(1).replace('\\"', '"')
            try:
                return json.loads(raw)
            except Exception:
                return None
    return None


def main():
    print("=" * 70)
    print("STEP 1: JWT/TOKEN CAPTURE FROM SIGNIN RESPONSES")
    print("=" * 70)

    # Query 1: signin responses
    print("\n--- Q1: /api/v1/auth/signin RESPONSE (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |= "/api/v1/auth/signin" |= "RESPONSE"', hours=720, max_lines=500)
    print(f"  lines: {len(lines)}")
    tokens_found = []
    for i, l in enumerate(lines[:50]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"\n  [{i+1}] ts={d.get('timestamp', '')}")
            print(f"      msg: {msg[:800]}")
            resp = extract_json_from_message(msg)
            if resp:
                print(f"      RESPONSE parsed: {json.dumps(resp)[:500]}")
                for key in ['token', 'accessToken', 'access_token', 'jwt', 'jwtToken', 'authToken', 'sessionToken', 'refreshToken']:
                    if key in resp:
                        tokens_found.append((key, resp[key]))
                        print(f"      *** TOKEN FOUND: {key}={resp[key]}")
            for pat in ['Bearer', 'authorization', 'token=', 'accessToken', 'jwt']:
                if pat.lower() in msg.lower():
                    print(f"      ** Contains '{pat}' in raw msg")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    print(f"\n  Tokens found: {len(tokens_found)}")
    for key, val in tokens_found:
        print(f"    {key}: {val}")

    # Query 2: signup responses
    print("\n--- Q2: /api/v1/auth/signup RESPONSE (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |= "/api/v1/auth/signup" |= "RESPONSE"', hours=720, max_lines=200)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:10]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"  [{i+1}] {msg[:600]}")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    # Query 3: current-user RESPONSE (full profile)
    print("\n--- Q3: /api/v1/auth/current-user RESPONSE (7d, 50 lines) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |= "current-user" |= "RESPONSE"', hours=168, max_lines=50)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:10]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            resp = extract_json_from_message(msg)
            if resp:
                result = resp.get('result', {})
                print(f"  [{i+1}] user={result.get('email', '')} role={result.get('role', '')} company={result.get('companyId', '')}")
            else:
                print(f"  [{i+1}] {msg[:400]}")
        except Exception:
            print(f"  [{i+1}] {s[:400]}")

    # Query 4: any Bearer/JWT in all prod-backend logs
    print("\n--- Q4: Bearer/JWT/token in logs (7d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |~ "(?i)(Bearer\\s+[A-Za-z0-9._-]|eyJ[A-Za-z0-9._-]+|authorization.*Bearer|jwt.*token)"', hours=168, max_lines=100)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:20]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            jwts = re.findall(r'eyJ[A-Za-z0-9._-]+', msg)
            bearers = re.findall(r'[Bb]earer\s+([A-Za-z0-9._-]+)', msg)
            if jwts or bearers:
                print(f"  [{i+1}] JWTs: {jwts[:3]}")
                print(f"        Bearers: {bearers[:3]}")
            else:
                print(f"  [{i+1}] {msg[:400]}")
        except Exception:
            print(f"  [{i+1}] {s[:400]}")

    print("\n" + "=" * 70)
    print("STEP 2: INTERNALTOKENFILTER REVERSE")
    print("=" * 70)

    # Query 5: /internal/ requests
    print("\n--- Q5: /internal/ requests (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |~ "/internal/"', hours=720, max_lines=200)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:20]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"  [{i+1}] {msg[:800]}")
            for h in re.findall(r'[Xx]-[A-Za-z-]+', msg):
                print(f"        header: {h}")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    # Query 6: InternalTokenFilter in logs
    print("\n--- Q6: InternalTokenFilter (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |~ "InternalTokenFilter"', hours=720, max_lines=100)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:10]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"  [{i+1}] {msg[:800]}")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    # Query 7: approve_user / verify_email token-based flows
    print("\n--- Q7: approve_user / verify_email (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |~ "(?i)(approve_user|verify_email|token.*valid|reset.*password)"', hours=720, max_lines=100)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:10]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"  [{i+1}] {msg[:800]}")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    # Query 8: any header with "token" or "auth" in name
    print("\n--- Q8: X-Auth / X-Token / X-Internal headers (30d) ---")
    lines = loki_query('{namespace="prod",app="prod-backend"} |~ "(?i)(x-auth|x-token|x-internal|internal-token|api-key|apikey|x-api)"', hours=720, max_lines=100)
    print(f"  lines: {len(lines)}")
    for i, l in enumerate(lines[:20]):
        s = str(l)
        try:
            d = json.loads(s)
            msg = d.get('message', '')
            print(f"  [{i+1}] {msg[:800]}")
        except Exception:
            print(f"  [{i+1}] {s[:500]}")

    print("\n" + "=" * 70)
    print("SUMMARY")
    print("=" * 70)
    print(f"\nTokens found in signin responses: {len(tokens_found)}")
    print("InternalTokenFilter observations:")
    print("  - filter position 7 in Spring Security chain (from actuator/prometheus)")
    print("  - 324 requests processed by InternalTokenFilter (from actuator/prometheus)")


if __name__ == "__main__":
    main()
