#!/usr/bin/env python3
"""Agent for testing Broken Function Level Authorization (BFLA) in APIs."""

import argparse
import json
from datetime import datetime, timezone

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False


ADMIN_ENDPOINTS = [
    "/admin", "/admin/users", "/admin/settings", "/admin/config",
    "/api/admin/users", "/api/v1/admin", "/api/internal",
    "/manage", "/management", "/dashboard/admin",
    "/api/users/all", "/api/config", "/api/debug",
]

HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"]


def test_endpoint_access(base_url, endpoint, token, method="GET"):
    """Test if an endpoint is accessible with given credentials."""
    if not HAS_REQUESTS:
        return None
    url = f"{base_url.rstrip('/')}{endpoint}"
    headers = {"Authorization": f"Bearer {token}"} if token else {}
    try:
        resp = requests.request(method, url, headers=headers, timeout=10, verify=False)
        return {
            "endpoint": endpoint,
            "method": method,
            "status_code": resp.status_code,
            "response_size": len(resp.content),
            "accessible": resp.status_code < 400,
        }
    except requests.RequestException:
        return None


def test_method_switching(base_url, endpoint, token):
    """Test if changing HTTP method bypasses authorization."""
    results = []
    for method in HTTP_METHODS:
        result = test_endpoint_access(base_url, endpoint, token, method)
        if result and result["accessible"]:
            results.append(result)
    return results


def test_privilege_escalation(base_url, low_priv_token, endpoints=None):
    """Test if low-privilege user can access admin endpoints."""
    findings = []
    test_endpoints = endpoints or ADMIN_ENDPOINTS
    for ep in test_endpoints:
        result = test_endpoint_access(base_url, ep, low_priv_token)
        if result and result["accessible"]:
            findings.append({
                "vulnerability": "BFLA",
                "endpoint": ep,
                "status_code": result["status_code"],
                "response_size": result["response_size"],
                "severity": "HIGH",
            })
    return findings


def test_idor_via_function(base_url, token, user_id, target_user_id):
    """Test function-level auth by accessing another user's admin functions."""
    findings = []
    endpoints = [
        f"/api/users/{target_user_id}",
        f"/api/users/{target_user_id}/settings",
        f"/api/users/{target_user_id}/role",
    ]
    for ep in endpoints:
        for method in ["GET", "PUT", "DELETE"]:
            result = test_endpoint_access(base_url, ep, token, method)
            if result and result["accessible"]:
                findings.append({
                    "vulnerability": "BFLA+IDOR",
                    "endpoint": ep,
                    "method": method,
                    "own_user_id": user_id,
                    "target_user_id": target_user_id,
                })
    return findings


def main():
    parser = argparse.ArgumentParser(
        description="Test Broken Function Level Authorization (authorized testing only)"
    )
    parser.add_argument("--url", required=True, help="Base API URL")
    parser.add_argument("--token", help="Low-privilege user JWT token")
    parser.add_argument("--endpoints", nargs="*", help="Custom admin endpoints to test")
    parser.add_argument("--user-id", help="Current user ID")
    parser.add_argument("--target-id", help="Target user ID for IDOR test")
    parser.add_argument("--output", "-o", help="Output JSON report")
    args = parser.parse_args()

    print("[*] BFLA Testing Agent")
    print("[!] For authorized security testing only")
    report = {"timestamp": datetime.now(timezone.utc).isoformat(), "target": args.url, "findings": []}

    escalation = test_privilege_escalation(args.url, args.token, args.endpoints)
    report["findings"].extend(escalation)
    print(f"[*] Privilege escalation findings: {len(escalation)}")

    if args.user_id and args.target_id:
        idor = test_idor_via_function(args.url, args.token, args.user_id, args.target_id)
        report["findings"].extend(idor)
        print(f"[*] IDOR findings: {len(idor)}")

    report["risk_level"] = "CRITICAL" if report["findings"] else "LOW"

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"[*] Report saved to {args.output}")
    else:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
