Files
reverse-skills-max/vendor-new/js-reverse-automation--skill/js-reverse-automation/scripts/check_delivery_contract.py

112 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""回归检查生成的 JSRPC/Flask/Burp 交付契约。"""
from __future__ import annotations
import argparse
import importlib.util
import json
from pathlib import Path
from typing import Any
from urllib.parse import urlencode
def load_module(path: Path):
spec = importlib.util.spec_from_file_location("jsra_delivery_contract_proxy", path)
if spec is None or spec.loader is None:
raise RuntimeError(f"无法加载代理:{path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def check_endpoint_normalization(module) -> dict[str, Any]:
calls: list[str] = []
class FakeResponse:
def raise_for_status(self) -> None:
return None
def json(self) -> dict[str, Any]:
return {"data": {"requestBody": "loginId=admin&password2=ENC"}}
def fake_get(url: str, **_: Any) -> FakeResponse:
calls.append(url)
return FakeResponse()
original_get = module.requests.get
try:
module.requests.get = fake_get
transform = module.CONFIG["transforms"][0]
module.jsrpc_call(transform.get("action", module.CONFIG["jsrpc"]["action"]), "123456", transform)
finally:
module.requests.get = original_get
if len(calls) != 1 or not calls[0].endswith("/go") or calls[0].endswith("/go/go"):
raise AssertionError(f"JSRPC endpoint 归一化失败:{calls}")
return {"ok": True, "called": calls[0]}
def check_packet_modes(module) -> dict[str, Any]:
transform = module.CONFIG["transforms"][0]
path = str(transform.get("path") or transform.get("id") or "password")
field = path.removeprefix("$.").split(".")[-1]
if transform.get("delivery_mode") == "request_body":
fake_result = f"loginId=admin&{field}=ENC(123456)"
expected_body = fake_result
else:
fake_result = "ENC(123456)"
expected_body = f"loginId=admin&{urlencode({field: 'ENC(123456)'})}"
module.jsrpc_call = lambda _action, _value, _transform: fake_result
client = module.app.test_client()
raw_packet = (
"POST /newlogin/login.do?appName=arena&fromSite=77 HTTP/1.1\r\n"
"Host: 127.0.0.1:8123\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Connection: close\r\n\r\n"
f"loginId=admin&{field}=123456"
)
packet_response = client.post("/encode", data=raw_packet, content_type="application/octet-stream")
packet_text = packet_response.get_data(as_text=True)
if packet_response.status_code != 200:
raise AssertionError(f"整包模式失败:HTTP {packet_response.status_code}: {packet_text}")
if expected_body not in packet_text:
raise AssertionError(f"整包模式没有替换 body:{packet_text}")
expected_length = len(expected_body.encode())
if f"Content-Length: {expected_length}" not in packet_text:
raise AssertionError(f"整包模式没有同步 Content-Length:{packet_text}")
wrapper_response = client.post(
"/encode",
data={"dataBody": f"loginId=admin&{field}=123456", "requestorresponse": "request"},
content_type="application/x-www-form-urlencoded",
)
wrapper_text = wrapper_response.get_data(as_text=True)
expected_wrapper = expected_body
if wrapper_response.status_code != 200 or wrapper_text != expected_wrapper:
raise AssertionError(f"dataBody wrapper 失败:HTTP {wrapper_response.status_code}: {wrapper_text}")
return {"ok": True, "packet_status": packet_response.status_code, "wrapper_status": wrapper_response.status_code}
def main() -> int:
parser = argparse.ArgumentParser(description="Validate generated Flask delivery contracts.")
parser.add_argument("--proxy", required=True, help="Generated flask_proxy.py path.")
parser.add_argument("--output", required=True, help="JSON report path.")
args = parser.parse_args()
module = load_module(Path(args.proxy))
result = {
"passed": True,
"proxy": str(Path(args.proxy).resolve()),
"endpoint_normalization": check_endpoint_normalization(module),
"packet_modes": check_packet_modes(module),
"live_action_required": True,
}
output = Path(args.output)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps(result, ensure_ascii=False))
return 0
if __name__ == "__main__":
raise SystemExit(main())