// oauth-plugin.ts
import type { SDK } from "caido:plugin";
import type { Request, Response } from "caido:utils";
import { promises as fs } from "fs";
import * as path from "path";
import os from "os";

export class redirectUriCheck {
  private requestMap = new Map<string, string>();

//   constructor(private sdk: SDK<any>) {}

  public async onRequest(sdk: SDK, req: Request) {
    try {
      const urlString = req.getUrl();
      const url = new URL(urlString);
      sdk.console.log(`[OAuthPlugin] Intercepted request: ${urlString}`);

      if (!url.pathname.includes("/authorize") && !url.pathname.includes("/auth")) return;

      const params = new URLSearchParams(url.search);
      const redirectUri = params.get("redirect_uri");
      if (!redirectUri) return;

      const reqId = req.getId();
      this.requestMap.set(reqId, redirectUri);

      const clientId = params.get("client_id") ?? "(missing)";
      const responseType = params.get("response_type") ?? "(missing)";
      const isScan = params.has("scan");
      if (isScan) return;

      const output = {
        original_url: urlString,
        client_id: clientId,
        redirect_uri: redirectUri,
        response_type: responseType,
      };

      try {
        const filePath = path.join(os.tmpdir(), "oauth-fuzz-input.json");
        await fs.writeFile(filePath, JSON.stringify(output, null, 2));
      } catch (err) {
        await sdk.findings.create({
          title: "[fs] Write Failed",
          description: `Could not write to file: ${err}`,
          request: req,
          reporter: "oauth-open-redirect-detector"
        });
      }

      await sdk.findings.create({
        title: "[ ] OAuth2 Authorization Request Collected",
        description: `client_id: ${clientId}\nredirect_uri: ${redirectUri}\nresponse_type: ${responseType}`,
        request: req,
        reporter: "oauth-open-redirect-detector"
      });

    } catch (err) {
        sdk.console.error(`Error in onRequest: ${err}`);
    }
  }

  public async onResponse(sdk: SDK, req: Request, resp: Response) {
    try {
      const reqId = req.getId();
      const url = new URL(req.getUrl());
      const status = resp.getCode();
      const location = resp.getHeader("location")?.[0];

      const params = new URLSearchParams(url.search);
      const isScan = params.has("scan");

      if (!isScan) {
        this.requestMap.delete(reqId);
        return;
      }

      if (status >= 300 && status < 400 && location) {
        const redirectUri = this.requestMap.get(reqId) ?? "(unknown)";

        await sdk.findings.create({
          title: "[+] Redirect URI Misconfiguration Detected",
          description: `Status: ${status}\nLocation: ${location}\nRequest URL: ${url.href}\nRedirect URI: ${redirectUri}`,
          request: req,
          reporter: "oauth-open-redirect-detector",
        });
      }

      this.requestMap.delete(reqId);
    } catch (err) {
      sdk.console.error(`Error in onResponse: ${err}`);
    }
  }
}
