diff --git a/showcase/mon/README.md b/showcase/mon/README.md new file mode 100644 index 0000000..3bebb7f --- /dev/null +++ b/showcase/mon/README.md @@ -0,0 +1,171 @@ +# MON -- Website Reconstruction Engine + +MON is a modular Python framework for inspecting websites: crawling a +domain, extracting frontend structure, reverse-engineering backend API +calls from JavaScript, live-verifying those endpoints against the real +server, and exporting everything as a structured, documented, +machine-readable specification -- e.g. for feeding into an AI agent, or for +saving a local clone of the site. + +Network access (every `GET`/`POST` MON makes to the target site) uses a +deliberately simple, single-request-at-a-time fetcher: a plain +`requests.get`/`requests.post` per call, a mobile Chrome `User-Agent`, and +a bare timeout -- no shared session, no cookie jar, no automatic retries. +This is intentional: it's what makes MON reliable against sites that behave +oddly with persistent sessions or aggressive retry logic. + +## Install + +```bash +pip install -r requirements.txt +``` + +## Usage + +MON exposes exactly one public function. + +```python +from mon import inspect + +result = inspect( + domain="example.com", +) + +print(result.pages_crawled) +print(result.routes) +print(result.api_spec) +print(result.explorer) +print(result.explorer_visual) +``` + +### `inspect()` parameters + +| Parameter | Type | Default | Description | +|---|---|---|---| +| `domain` | `str` | *required* | Target domain, with or without a scheme (`example.com` or `https://example.com` both work). | +| `action` | `str \| list[str]` | `"all_data"` | One action name or a list of them. See **Actions** below. | +| `profile` | `str` | `"balanced"` | `"fast"`, `"balanced"`, or `"deep"` -- controls crawl depth and whether API endpoints get live-verified. See **Profiles** below. | +| `max_page` | `int \| "all"` | `"all"` | Max number of pages to crawl. `"all"` defers to the profile's own limit. Pass an `int` to override it directly. | +| `output_dir` | `str \| Path` | `"./data"` | Base directory where output is written. | +| `project_name` | `str \| None` | `None` | Subfolder name under `output_dir`. Defaults to the domain name; if that folder already exists, MON appends `_2`, `_3`, etc. so nothing is overwritten. | +| `output_format` | `str` | `"json"` | Format of the final summary report: `"json"` or `"markdown"`. | +| `response` | `bool` | `True` | Whether to print live progress to the console (`[+] Launching...`, `[📥 FETCHING]`, `[✔ DONE]`, etc.). Set `False` for silent runs. | +| `timeout` | `int` | `10` | Per-request timeout, in seconds, for every fetch. | +| `save` | `bool` | `True` | Whether to write anything to disk at all. Set `False` to only get the in-memory `InspectResult` back. | +| `verify_live_apis` | `bool` | `True` | Whether to send a real request to each reconstructed API endpoint to confirm it responds. Only takes effect if the chosen `profile` also enables live verification (see below). | + +### Profiles + +| Profile | Max pages | Live-verifies APIs? | When to use it | +|---|---|---|---| +| `fast` | 15 | No | Quick look at a site's shape without hammering its API. | +| `balanced` | 100 | Yes | Default. Good mix of coverage and speed. | +| `deep` | 500 | Yes | Large sites, or when you need the most complete route/API map possible. | + +## Architecture + +``` +User -> inspect() -> SDK -> Inspector -> Resolver -> Dispatcher -> Analyzers -> Context -> Output Writer -> InspectResult +``` + +- **SDK** (`mon/sdk.py`) -- the only public entry point. Builds an + `InspectConfig`, calls the Inspector, returns an `InspectResult`. +- **Config** (`mon/config.py`) -- validates every argument to `inspect()` + once, up front, into one immutable `InspectConfig` object that gets + threaded through the whole run. +- **Inspector** (`mon/engine/inspector.py`) -- orchestrates the run. Knows + nothing about HTML/JS/APIs itself. +- **Resolver** (`mon/engine/resolver.py`) -- expands composite actions + (e.g. `api_spec`) into their leaf actions and topologically sorts + analyzers by declared dependencies, so `crawler` always runs before + `html`/`javascript`, which always run before `api`. +- **Registry** (`mon/engine/registry.py`) -- maps action names to analyzer + classes. Adding a new analyzer never requires touching the Dispatcher. +- **Dispatcher** (`mon/engine/dispatcher.py`) -- executes the resolved + pipeline against one shared `InspectContext`. If one analyzer fails, the + rest still run -- the failure is recorded as a warning, not a crash. +- **Context** (`mon/engine/context.py`) -- the only channel analyzers use to + communicate (crawled pages, discovered links, reconstructed endpoints, + routes...). No analyzer ever imports or calls another analyzer directly. +- **Events** (`mon/engine/events.py`) -- analyzers never call `print()` + directly; they emit events (page fetched, page skipped, analyzer + started/finished/failed), and `ProgressManager` + (`mon/engine/progress.py`) subscribes to turn those into the console log + you see when `response=True`. +- **Fetcher** (`mon/network/fetcher.py`) -- the actual network layer. One + `Fetcher` instance per run, shared by every analyzer that needs to talk + to the target site. +- **Analyzers** (`mon/analyzers/`) -- one class per file, one responsibility + each: `crawler`, `html`, `javascript`, `api`, `routes`, `assets`, + `explorer`. +- **Parsers** (`mon/parsers/`) -- the actual link-extraction and + JS-static-analysis logic the analyzers call into. +- **Output Writer** (`mon/engine/output_writer.py`) -- saves the crawled + pages to disk as a local clone, plus `api_spec.json`, `explorer.json`, + `explorer_visual.txt`, and the final summary report. +- **Exporters** (`mon/exporters/`) -- turn an `InspectResult` into the + final summary report, `json` or `markdown`. + +## Actions + +Leaf actions (each maps to exactly one analyzer): + +| Action | What it does | +|---|---| +| `crawler` | Breadth-first crawl of the domain. Fetches every same-domain page it can reach, starting from `/`. Everything else depends on this. | +| `html` | Extracts the `` from every crawled HTML page. | +| `javascript` | Statically analyzes every crawled `.js` file to reconstruct backend API calls (`fetch`/`apiCall` sites, guessed payload keys, response-reading keys). | +| `api` | Turns the raw JS findings into `Endpoint` objects, each with a confidence score, and -- if the profile allows it -- live-verifies each one against the real server. | +| `routes` | Builds the combined route map: every frontend page plus every reconstructed API endpoint. | +| `assets` | Tallies the static assets (CSS, images, fonts, etc.) picked up during the crawl. | +| `explorer` | Builds `explorer.json` and the ASCII `explorer_visual.txt` tree, combining frontend routes and the "simulated backend API" tree. | + +Composite actions (expand into a group of leaf actions): + +| Action | Expands to | +|---|---| +| `all_data` | Every leaf action. | +| `api_spec` | `crawler`, `html`, `javascript`, `api` -- just the API reconstruction, no route map or explorer. | +| `explorer_visual` | `crawler`, `html`, `routes`, `explorer` -- just the site map, no API work. | +| `cloning` | `crawler`, `html`, `assets` -- just pull down a local copy of the site. | + +## InspectResult + +What `inspect()` returns: + +| Field | Type | Description | +|---|---|---| +| `domain` | `str` | The domain that was inspected. | +| `actions_run` | `tuple[str, ...]` | Which leaf actions actually executed. | +| `pages_crawled` | `int` | Total pages successfully fetched. | +| `api_spec` | `dict` | `{endpoint_url: {...}}` -- method, purpose, guessed payload keys, response schema, confidence score/reasons, and (if live-verified) a real response sample. | +| `routes` | `list[Route]` | Every frontend page and backend endpoint discovered. | +| `explorer` | `dict` | The structured route tree, same shape as `explorer.json`. | +| `explorer_visual` | `str` | The ASCII tree view, same content as `explorer_visual.txt`. | +| `assets_saved` | `int` | Count of static assets found. | +| `warnings` | `list[str]` | Anything that went wrong along the way (a failed analyzer, a skipped page) without aborting the whole run. | + +## Confidence scoring + +Every reconstructed API endpoint in `api_spec` carries a `confidence.score` +(0-100) and `confidence.reasons` -- a list of exactly why MON believes the +endpoint is real (e.g. *"Discovered via static JS analysis"*, *"Payload +keys matched from FormData/JSON body"*, *"Live-verified against server"*). +Nothing is asserted without a reason. + +## Output on disk + +When `save=True` (the default), a run against `example.com` produces: + +``` +data/example.com/ + clone/ raw fetched pages, laid out like the live site + api_spec.json + explorer.json + explorer_visual.txt + example.com_full_report.json (or .md, if output_format="markdown") +``` + +## License + +MIT -- see `LICENSE`. diff --git a/showcase/mon/assets/.gitkeep b/showcase/mon/assets/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/showcase/mon/assets/.gitkeep @@ -0,0 +1 @@ + diff --git a/showcase/mon/assets/poster.jpg b/showcase/mon/assets/poster.jpg new file mode 100644 index 0000000..a22d3d8 Binary files /dev/null and b/showcase/mon/assets/poster.jpg differ diff --git a/showcase/mon/sample_output/api_spec.json b/showcase/mon/sample_output/api_spec.json new file mode 100644 index 0000000..6a38034 --- /dev/null +++ b/showcase/mon/sample_output/api_spec.json @@ -0,0 +1,1368 @@ +{ + "/assets/api/get_auth_token.php": { + "function_purpose": "res", + "method": "GET", + "expected_payload_format": "Multipart FormData (multipart/form-data)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "token", + "transactions", + "userDetails", + "dataPrices", + "message", + "status" + ], + "extracted_response_schema_from_js": { + "token": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const res = await fetch('../api/get_auth_token.php');", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html><head>\n<title>404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/assets/api/user/auth/login.php": { + "function_purpose": "res", + "method": "POST", + "expected_payload_format": "Multipart FormData (multipart/form-data)", + "guessed_payload_keys": [ + "dataPrices", + "transactions", + "userDetails" + ], + "js_response_reading_keys": [ + "token", + "transactions", + "userDetails", + "dataPrices", + "message", + "status" + ], + "extracted_response_schema_from_js": { + "token": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const res = await fetch('../api/user/auth/login.php', {", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "electricityData", + "userDetails", + "dataPrices", + "message", + "status", + "cableData" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "electricityData": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "cableData": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/user.php?token=' + encodeURIComponent(token), {", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/electric/providers.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "token", + "customer_name", + "message", + "status", + "new_balance", + "data", + "units" + ], + "extracted_response_schema_from_js": { + "token": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "customer_name": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "units": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/electric/providers.php?token=' + encodeURIComponent(token), {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/electric/verify.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [ + "meter_number", + "provider_id", + "token" + ], + "js_response_reading_keys": [ + "token", + "customer_name", + "message", + "status", + "new_balance", + "data", + "units" + ], + "extracted_response_schema_from_js": { + "token": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "customer_name": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "units": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/electric/verify.php', {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/electric/buy.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [ + "amount", + "meter_number", + "pin", + "provider_id", + "token" + ], + "js_response_reading_keys": [ + "token", + "customer_name", + "message", + "status", + "new_balance", + "data", + "units" + ], + "extracted_response_schema_from_js": { + "token": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "customer_name": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "units": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/electric/buy.php', {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/ai/chat.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "payment_link", + "message", + "action", + "pending_id", + "status", + "new_balance" + ], + "extracted_response_schema_from_js": { + "payment_link": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "action": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "pending_id": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/ai/chat.php', {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Message is required" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/assets/api/ai/confirm.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "payment_link", + "message", + "action", + "pending_id", + "status", + "new_balance" + ], + "extracted_response_schema_from_js": { + "payment_link": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "action": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "pending_id": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('../api/ai/confirm.php', {", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/${API_BASE_URL}/${endpoint}": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch(`${API_BASE_URL}/${endpoint}`, options);", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/data/buy.php": { + "function_purpose": "unknown_function", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "apiCall('data/buy.php', 'POST', { phone, plan_code: planCode, pin });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/airtime/buy.php": { + "function_purpose": "unknown_function", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "apiCall('airtime/buy.php', 'POST', { phone, network, amount, pin });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/user.php": { + "function_purpose": "result", + "method": "GET", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [ + "dataPrices", + "transactions", + "userDetails" + ], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const result = await apiCall('user/user.php', 'POST', { action: 'get' });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required. Please login." + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/fund/initialize.php": { + "function_purpose": "initializePayment", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.initializePayment = async (amount) => apiCall('user/fund/initialize.php', 'POST', { amount });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/fund/verify.php": { + "function_purpose": "verifyPayment", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.verifyPayment = async (reference) => apiCall('user/fund/verify.php', 'POST', { reference });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/fund/pending.php": { + "function_purpose": "checkPendingFundingAPI", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "//window.checkPendingFundingAPI = async () => apiCall('user/fund/pending.php', 'POST', { action: 'check' });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/update_profile": { + "function_purpose": "updateUserProfile", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.updateUserProfile = async (name, email) => apiCall('user/update_profile', 'POST', { name, email });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "{\n \"status\": \"success\",\n \"message\": \"Profile updated successfully\",\n \"data\": {\n \"fullname\": \"Abba Moson\",\n \"email\": \"abba@moson.ng\"\n }\n}" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/change_password": { + "function_purpose": "changeUserPassword", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.changeUserPassword = async (currentPassword, newPassword) => apiCall('user/change_password', 'POST', { current_password: currentPassword, new_password: newPassword });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "{\n \"status\": \"success\",\n \"message\": \"Password changed successfully\"\n}" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/set_pin/pin.php": { + "function_purpose": "setTransactionPin", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.setTransactionPin = async (pin) => apiCall('user/set_pin/pin.php', 'POST', { pin });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/user/change_pin/pin.php": { + "function_purpose": "changeTransactionPin", + "method": "GET", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.changeTransactionPin = async (oldPin, newPin) => apiCall('user/change_pin/pin.php', 'POST', { old_pin: oldPin, new_pin: newPin });", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/ai/chat": { + "function_purpose": "sendChatMessage", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.sendChatMessage = async (message) => apiCall('ai/chat', 'POST', { message });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/providers": { + "function_purpose": "getCableProviders", + "method": "GET", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.getCableProviders = async () => apiCall('cable/providers', 'POST', {});", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "{\n \"status\": \"success\",\n \"data\": [\n { \"id\": 1, \"name\": \"DSTV\", \"code\": \"dstv\", \"plans\": [\n { \"id\": 101, \"name\": \"Compact\", \"price\": 7500, \"validity\": \"30 days\" },\n {" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/subscribe": { + "function_purpose": "subscribeCable", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.subscribeCable = async (provider, smartCard, planCode) => apiCall('cable/subscribe', 'POST', { provider, smart_card: smartCard, plan_code: planCode });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/electricity/providers": { + "function_purpose": "getElectricityProviders", + "method": "GET", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.getElectricityProviders = async () => apiCall('electricity/providers', 'POST', {});", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/electricity/pay": { + "function_purpose": "payElectricity", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "transactions", + "userDetails", + "dataPrices", + "message", + "status", + "data" + ], + "extracted_response_schema_from_js": { + "transactions": [ + { + "id": "TYPE_NUMBER", + "reference": "TYPE_STRING", + "amount": "TYPE_NUMBER", + "status": "TYPE_STRING" + } + ], + "userDetails": { + "id": "TYPE_NUMBER", + "name": "TYPE_STRING", + "email": "TYPE_STRING", + "token": "TYPE_STRING" + }, + "dataPrices": {}, + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "window.payElectricity = async (disco, meterNumber, meterType, amount) => apiCall('electricity/pay', 'POST', { disco, meter_number: meterNumber, meter_type: meterType, amount });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/js/api/user/verify_kyc.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "data", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('../api/user/verify_kyc.php', {", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/js/api/user/fund/pending.php": { + "function_purpose": "unknown_function", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "data", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "return await apiCall('user/fund/pending.php', 'POST', { action: 'check' });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/providers.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "data", + "new_balance", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/cable/providers.php?token=' + encodeURIComponent(token), {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/packages.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "data", + "new_balance", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch(`/api/cable/packages.php?provider_id=${providerId}&token=${encodeURIComponent(token)}`, {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/verify.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [ + "iuc_number", + "provider_id", + "token" + ], + "js_response_reading_keys": [ + "data", + "new_balance", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/cable/verify.php', {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/api/cable/buy.php": { + "function_purpose": "response", + "method": "POST", + "expected_payload_format": "Parameters (application/x-www-form-urlencoded)", + "guessed_payload_keys": [ + "iuc_number", + "package_id", + "pin", + "provider_id", + "token" + ], + "js_response_reading_keys": [ + "data", + "new_balance", + "status", + "message" + ], + "extracted_response_schema_from_js": { + "data": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "new_balance": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const response = await fetch('/api/cable/buy.php', {", + "live_verified": true, + "live_response_sample": { + "status": "error", + "message": "Authentication required." + }, + "confidence": { + "score": 90, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Payload keys matched from FormData/JSON body", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/js/api/developer/get_api_key.php": { + "function_purpose": "result", + "method": "GET", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "status", + "api_key", + "message" + ], + "extracted_response_schema_from_js": { + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "api_key": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const result = await apiCall('developer/get_api_key.php', 'POST', { pin });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + }, + "/js/api/developer/regenerate_api_key.php": { + "function_purpose": "result", + "method": "POST", + "expected_payload_format": "Raw JSON (application/json)", + "guessed_payload_keys": [], + "js_response_reading_keys": [ + "status", + "api_key", + "message" + ], + "extracted_response_schema_from_js": { + "status": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "api_key": "TYPE_UNKNOWN_DETERMINED_BY_JS", + "message": "TYPE_UNKNOWN_DETERMINED_BY_JS" + }, + "raw_js_context": "const result = await apiCall('developer/regenerate_api_key.php', 'POST', { pin });", + "live_verified": true, + "live_response_sample": { + "raw_non_json_sample": "\n\n404 Not Found\n\n

Not Found

\n

The requested URL was not found" + }, + "confidence": { + "score": 75, + "reasons": [ + "Discovered via static JS analysis (apiCall/fetch call site)", + "Success/error branches detected in JS", + "Live-verified against server" + ] + } + } +} \ No newline at end of file diff --git a/showcase/mon/sample_output/explorer.json b/showcase/mon/sample_output/explorer.json new file mode 100644 index 0000000..a5f6894 --- /dev/null +++ b/showcase/mon/sample_output/explorer.json @@ -0,0 +1,405 @@ +{ + "domain": "payfluxai.com.ng", + "website_routes": [ + { + "path": "/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "PayFlux AI – Buy Data, Airtime & Pay Bills Instantly in Nigeria" + }, + { + "path": "/document/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "PayFlux AI API Documentation" + }, + { + "path": "/register/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "Create Account | PayFlux AI" + }, + { + "path": "/favicon.ico", + "file": "favicon.ico", + "type": "ico", + "format": ".ico" + }, + { + "path": "/login/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "Login | PayFlux AI" + }, + { + "path": "/document/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "PayFlux AI API Documentation" + }, + { + "path": "/dashboard/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "PayFlux-AI | User Dashboard" + }, + { + "path": "/assets/scripts/autoTheme.js", + "file": "autoTheme.js", + "type": "js", + "format": ".js" + }, + { + "path": "/dashboard/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "PayFlux-AI | User Dashboard" + }, + { + "path": "/forgot-password/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "Forgot Password | PayFlux AI" + }, + { + "path": "/assets/scripts/login.js", + "file": "login.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/theme.js", + "file": "theme.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/data.js", + "file": "data.js", + "type": "js", + "format": ".js" + }, + { + "path": "/forgot-password/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "Forgot Password | PayFlux AI" + }, + { + "path": "/js/modules/cookie.js", + "file": "cookie.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/electricity.js", + "file": "electricity.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/other.js", + "file": "other.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/sidebar.js", + "file": "sidebar.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/security.js", + "file": "security.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/auth.js", + "file": "auth.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/user.js", + "file": "user.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/transactions.js", + "file": "transactions.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/toast.js", + "file": "toast.js", + "type": "js", + "format": ".js" + }, + { + "path": "/assets/scripts/payfluxai.js", + "file": "payfluxai.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/airtime.js", + "file": "airtime.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/utils.js", + "file": "utils.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/mainapi.js", + "file": "mainapi.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/balance.js", + "file": "balance.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/main.js", + "file": "main.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/wallet.js", + "file": "wallet.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/cable.js", + "file": "cable.js", + "type": "js", + "format": ".js" + }, + { + "path": "/js/modules/developer.js", + "file": "developer.js", + "type": "js", + "format": ".js" + }, + { + "path": "/login/", + "file": "index.html", + "type": "html", + "format": ".html", + "title": "Login | PayFlux AI" + }, + { + "path": "/assets/api/get_auth_token.php", + "file": "get_auth_token.php", + "type": "json", + "format": ".php" + }, + { + "path": "/assets/api/user/auth/login.php", + "file": "login.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user.php", + "file": "user.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/electric/providers.php", + "file": "providers.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/electric/verify.php", + "file": "verify.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/electric/buy.php", + "file": "buy.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/ai/chat.php", + "file": "chat.php", + "type": "json", + "format": ".php" + }, + { + "path": "/assets/api/ai/confirm.php", + "file": "confirm.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/${API_BASE_URL}/${endpoint}", + "file": "${endpoint}", + "type": "json", + "format": ".php" + }, + { + "path": "/api/data/buy.php", + "file": "buy.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/airtime/buy.php", + "file": "buy.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/user.php", + "file": "user.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/fund/initialize.php", + "file": "initialize.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/fund/verify.php", + "file": "verify.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/fund/pending.php", + "file": "pending.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/update_profile", + "file": "update_profile", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/change_password", + "file": "change_password", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/set_pin/pin.php", + "file": "pin.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/user/change_pin/pin.php", + "file": "pin.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/ai/chat", + "file": "chat", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/providers", + "file": "providers", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/subscribe", + "file": "subscribe", + "type": "json", + "format": ".php" + }, + { + "path": "/api/electricity/providers", + "file": "providers", + "type": "json", + "format": ".php" + }, + { + "path": "/api/electricity/pay", + "file": "pay", + "type": "json", + "format": ".php" + }, + { + "path": "/js/api/user/verify_kyc.php", + "file": "verify_kyc.php", + "type": "json", + "format": ".php" + }, + { + "path": "/js/api/user/fund/pending.php", + "file": "pending.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/providers.php", + "file": "providers.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/packages.php", + "file": "packages.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/verify.php", + "file": "verify.php", + "type": "json", + "format": ".php" + }, + { + "path": "/api/cable/buy.php", + "file": "buy.php", + "type": "json", + "format": ".php" + }, + { + "path": "/js/api/developer/get_api_key.php", + "file": "get_api_key.php", + "type": "json", + "format": ".php" + }, + { + "path": "/js/api/developer/regenerate_api_key.php", + "file": "regenerate_api_key.php", + "type": "json", + "format": ".php" + } + ] +} \ No newline at end of file diff --git a/showcase/mon/sample_output/explorer_visual.txt b/showcase/mon/sample_output/explorer_visual.txt new file mode 100644 index 0000000..eb20662 --- /dev/null +++ b/showcase/mon/sample_output/explorer_visual.txt @@ -0,0 +1,68 @@ +📂 payfluxai.com.ng (Enterprise Frontend Map Layout) +├── / 📌 (PayFlux AI – Buy Data, Airtime & Pay Bills Instantly in Nigeria) +├── /assets/scripts/autoTheme.js +├── /assets/scripts/login.js +├── /assets/scripts/payfluxai.js +├── /dashboard/ 📌 (PayFlux-AI | User Dashboard) +├── /dashboard/ 📌 (PayFlux-AI | User Dashboard) +├── /document/ 📌 (PayFlux AI API Documentation) +├── /document/ 📌 (PayFlux AI API Documentation) +├── /favicon.ico +├── /forgot-password/ 📌 (Forgot Password | PayFlux AI) +├── /forgot-password/ 📌 (Forgot Password | PayFlux AI) +├── /js/main.js +├── /js/mainapi.js +├── /js/modules/airtime.js +├── /js/modules/auth.js +├── /js/modules/balance.js +├── /js/modules/cable.js +├── /js/modules/cookie.js +├── /js/modules/data.js +├── /js/modules/developer.js +├── /js/modules/electricity.js +├── /js/modules/other.js +├── /js/modules/security.js +├── /js/modules/sidebar.js +├── /js/modules/theme.js +├── /js/modules/toast.js +├── /js/modules/transactions.js +├── /js/modules/user.js +├── /js/modules/utils.js +├── /js/modules/wallet.js +├── /login/ 📌 (Login | PayFlux AI) +├── /login/ 📌 (Login | PayFlux AI) +└── /register/ 📌 (Create Account | PayFlux AI) + +⚙️ Simulated Backend API Endpoint Tree +├── /api/${API_BASE_URL}/${endpoint} +├── /api/ai/chat +├── /api/ai/chat.php +├── /api/airtime/buy.php +├── /api/cable/buy.php +├── /api/cable/packages.php +├── /api/cable/providers +├── /api/cable/providers.php +├── /api/cable/subscribe +├── /api/cable/verify.php +├── /api/data/buy.php +├── /api/electric/buy.php +├── /api/electric/providers.php +├── /api/electric/verify.php +├── /api/electricity/pay +├── /api/electricity/providers +├── /api/user.php +├── /api/user/change_password +├── /api/user/change_pin/pin.php +├── /api/user/fund/initialize.php +├── /api/user/fund/pending.php +├── /api/user/fund/verify.php +├── /api/user/set_pin/pin.php +├── /api/user/update_profile +├── /api/user/user.php +├── /assets/api/ai/confirm.php +├── /assets/api/get_auth_token.php +├── /assets/api/user/auth/login.php +├── /js/api/developer/get_api_key.php +├── /js/api/developer/regenerate_api_key.php +├── /js/api/user/fund/pending.php +└── /js/api/user/verify_kyc.php \ No newline at end of file diff --git a/showcase/mon/showcase.json b/showcase/mon/showcase.json new file mode 100644 index 0000000..087f7b1 --- /dev/null +++ b/showcase/mon/showcase.json @@ -0,0 +1,54 @@ +{ + "slug": "mon", + "title": "MON - Autonomous Source Code & Architecture Auditor", + "tagline": "Clones repositories, analyzes backend architectures, and extracts technical metadata for code auditing", + "description": "MON is an autonomous static analysis engine that clones source code to discover endpoints, APIs, forms, routes, and tech stacks. It utilizes custom parsers and exporters to build a comprehensive map of any application architecture.", + "status": "live", + "topic": "security", + "topics": [ + "code-audit", + "developer-tools", + "static-analysis", + "web3-security" + ], + "builder": { + "name": "Mamman Chiroma", + "url": "https://github.com/mosonmcn" + }, + "links": { + "repo": "https://github.com/mosonmcn/MON", + "video": "https://x.com/MosonDev/status/2078572007227093352", + "videoLabel": "Watch MON Demo Video", + "feedback": "https://github.com/mosonmcn/MON/issues" + }, + "primitives": [ + "acp", + "wallet" + ], + "visual": { + "kind": "card", + "eyebrow": "Developer Tool", + "title": "MON: The Autonomous Code Cloner & Architecture Scanner", + "posterUrl": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/mon/assets/poster.jpg" + }, + "skills": [ + { + "name": "Code Architecture Discovery", + "href": "https://github.com/mosonmcn/MON", + "summary": "Runs deep static analysis to discover APIs, endpoints, and form schemas in any cloned Python or JS project.", + "install": "pip install -r requirements.txt && python -m mon.sdk" + } + ], + "artifacts": [ + { + "label": "MON Architecture Scan Sample Output", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/mon/sample_output", + "kind": "file" + } + ], + "feedbackPrompts": [ + "How easily does MON integrate with your current CI/CD pipelines?", + "Are there other specific web frameworks or languages you want the parsers to support?", + "How accurate is the tech-stack discovery on legacy codebases?" + ] +}