"""Offline BOLA regression exercise. Put access-fixture.py alongside this file."""
import argparse
import importlib.util
import json
import sys
from http.server import ThreadingHTTPServer
from pathlib import Path
from threading import Thread
from urllib.error import HTTPError
from urllib.request import Request, urlopen


def check(base, mode):
    def read(user, doc):
        url = f"{base}/documents/doc-{doc}?mode={mode}"
        try:
            response = urlopen(Request(url, headers={"X-Fixture-User": user}), timeout=4)
        except HTTPError as error:
            response = error
        with response:
            return response.status, json.load(response)

    for owner in ("a", "b"):
        status, body = read(owner, owner)
        if status != 200 or body.get("marker") != "synthetic-private-" + owner.upper():
            print("INCOMPLETE: owner control failed")
            return 2
    for caller, doc in (("a", "b"), ("b", "a")):
        status, body = read(caller, doc)
        if body.get("marker") == "synthetic-private-" + doc.upper():
            print(f"BLOCK: {caller} received the private marker for {doc}")
            return 1
        if status != 403 or body != {"error": "forbidden"}:
            print("INCOMPLETE: unexpected denial contract")
            return 2
    print("PASS: both owners retain access; both cross-owner reads are denied")
    return 0


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--mode", choices=("fixed", "vulnerable"), default="fixed")
    mode = parser.parse_args().mode
    spec = importlib.util.spec_from_file_location("fixture", Path(__file__).with_name("access-fixture.py"))
    fixture = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(fixture)
    with ThreadingHTTPServer(("127.0.0.1", 0), fixture.Handler) as server:
        worker = Thread(target=server.serve_forever, daemon=True)
        worker.start()
        try:
            return check("http://127.0.0.1:" + str(server.server_port), mode)
        finally:
            server.shutdown()
            worker.join()


if __name__ == "__main__":
    try:
        sys.exit(main())
    except (OSError, ValueError, AttributeError) as error:
        print("INCOMPLETE:", type(error).__name__, file=sys.stderr)
        sys.exit(2)
