/*
 * Universal OkHttp Response Interceptor
 * Hooks OkHttp's response chain to capture ALL HTTP responses.
 * Works with Spirit, Delta, United (all use OkHttp/Retrofit).
 *
 * Sends captured data to a local server via Frida's send().
 */

Java.perform(function() {
    console.log("[*] OkHttp Response Interceptor starting...");

    // Filter: only capture responses from these domains
    var targetDomains = [
        "api.spirit.com",
        "www.delta.com",
        "mobileapi.united.com",
        "content.spirit.com",
        "content.delta.com"
    ];

    // Filter: only capture these API paths
    var targetPaths = [
        // Spirit
        "/customermobileprod/",
        "/v1/getboastatus",
        "/v1/getboaparameters",
        "/v2/Token",
        "/v3/mytrips",
        "/v1/booking",
        "/v3/GetFlightInfoBI",
        "/v5/Flight/Search",

        // Delta
        "/api/mobile/asl",
        "/api/mobile/getFlightStatus",
        "/api/mobile/getFlightStatusByLeg",
        "/api/mobile/login",
        "/api/mobile/getDashboard",
        "/api/mobile/getUpgradeEligibilityInfo",

        // United
        "/standbylistservice/",
        "/upgradelistservice/",
        "/flightstatusservice/",
        "/checkinservice/",
        "/passriderlistservice/"
    ];

    function shouldCapture(url) {
        var domainMatch = false;
        var pathMatch = false;

        for (var i = 0; i < targetDomains.length; i++) {
            if (url.indexOf(targetDomains[i]) !== -1) {
                domainMatch = true;
                break;
            }
        }

        if (!domainMatch) return false;

        for (var j = 0; j < targetPaths.length; j++) {
            if (url.indexOf(targetPaths[j]) !== -1) {
                pathMatch = true;
                break;
            }
        }

        return pathMatch;
    }

    // === Hook OkHttp3 RealCall.getResponseWithInterceptorChain ===
    try {
        var OkHttpClient = Java.use("okhttp3.OkHttpClient");
        var Request = Java.use("okhttp3.Request");
        var Response = Java.use("okhttp3.Response");
        var ResponseBody = Java.use("okhttp3.ResponseBody");
        var BufferClass = Java.use("okio.Buffer");
        var MediaType = Java.use("okhttp3.MediaType");

        // Hook the Interceptor.Chain.proceed to capture request+response
        var RealInterceptorChain = Java.use("okhttp3.internal.http.RealInterceptorChain");

        RealInterceptorChain.proceed.overload("okhttp3.Request").implementation = function(request) {
            var url = request.url().toString();
            var response = this.proceed(request);

            if (shouldCapture(url)) {
                try {
                    var method = request.method();
                    var reqBody = null;

                    // Capture request body
                    if (request.body() !== null) {
                        var reqBuffer = BufferClass.$new();
                        request.body().writeTo(reqBuffer);
                        reqBody = reqBuffer.readUtf8();
                    }

                    // Capture request headers
                    var reqHeaders = {};
                    var headerNames = request.headers();
                    for (var i = 0; i < headerNames.size(); i++) {
                        reqHeaders[headerNames.name(i)] = headerNames.value(i);
                    }

                    // Capture response
                    var statusCode = response.code();
                    var respBody = null;
                    var respHeaders = {};

                    // Response headers
                    var respHeaderObj = response.headers();
                    for (var j = 0; j < respHeaderObj.size(); j++) {
                        respHeaders[respHeaderObj.name(j)] = respHeaderObj.value(j);
                    }

                    // Response body (need to peek without consuming)
                    var body = response.body();
                    if (body !== null) {
                        var source = body.source();
                        source.request(Long.MAX_VALUE);
                        var buffer = source.getBuffer().clone();
                        respBody = buffer.readUtf8();
                    }

                    var captured = {
                        type: "HTTP_RESPONSE",
                        timestamp: new Date().toISOString(),
                        method: method,
                        url: url,
                        status: statusCode,
                        requestHeaders: reqHeaders,
                        requestBody: reqBody,
                        responseHeaders: respHeaders,
                        responseBody: respBody
                    };

                    // Send to Frida host
                    send(captured);

                    console.log("[+] CAPTURED: " + method + " " + url + " -> " + statusCode + " (" + (respBody ? respBody.length : 0) + " chars)");

                } catch(e) {
                    console.log("[-] Capture error for " + url + ": " + e);
                }
            }

            return response;
        };

        console.log("[+] OkHttp RealInterceptorChain.proceed hooked");

    } catch(e) {
        console.log("[-] OkHttp3 hook failed: " + e);
        console.log("[*] Trying alternative hook...");

        // Alternative: Hook at a higher level
        try {
            var Interceptor = Java.use("okhttp3.Interceptor");
            // This approach hooks via adding our own interceptor
            console.log("[*] Alternative approach needed - see app-specific hooks");
        } catch(e2) {
            console.log("[-] Alternative also failed: " + e2);
        }
    }

    // === Also hook Retrofit response callbacks ===
    try {
        var CallbackClass = Java.use("retrofit2.OkHttpCall");
        CallbackClass.parseResponse.implementation = function(rawResponse) {
            var response = this.parseResponse(rawResponse);
            try {
                var url = rawResponse.request().url().toString();
                if (shouldCapture(url)) {
                    var body = response.body();
                    if (body !== null) {
                        console.log("[+] Retrofit response: " + url);
                        console.log("[+] Body class: " + body.getClass().getName());
                        console.log("[+] Body: " + body.toString().substring(0, Math.min(500, body.toString().length)));

                        send({
                            type: "RETROFIT_RESPONSE",
                            timestamp: new Date().toISOString(),
                            url: url,
                            bodyClass: body.getClass().getName(),
                            body: body.toString()
                        });
                    }
                }
            } catch(e) {
                // Ignore parse errors
            }
            return response;
        };
        console.log("[+] Retrofit parseResponse hooked");
    } catch(e) {
        console.log("[-] Retrofit hook failed: " + e);
    }

    // === Java Long for buffer request ===
    var Long = Java.use("java.lang.Long");
    Long.MAX_VALUE.value;

    console.log("[*] OkHttp Response Interceptor ready. Waiting for traffic...");
});
