"""
Elasticsearch CVE lookup tool

This module send a request to the NVD CVE database and lists all the CVEs the Elasticsearch version running on the host
might be vulnerable to

Contains:
- Vuln class for performing the test
- run() function as an entry point for running the test
"""

import http
from http import HTTPStatus
import requests
from ptlibs import ptjsonlib
from ptlibs.ptprinthelper import ptprint


__TESTLABEL__ = "Elasticsearch CVE lookup"


class Vuln:
    """
    This class prints all CVEs that the host might be vulnerable to and adds them to the JSON output
    """
    def __init__(self, args: object, ptjsonlib: object, helpers: object, http_client: object, base_response: object) -> None:
        self.args = args
        self.ptjsonlib = ptjsonlib
        self.helpers = helpers
        self.http_client = http_client
        self.base_response = base_response
        self.helpers.print_header(__TESTLABEL__)


    def _print_cve(self, cve_list: list):
        """
        This method goes through the provided list of CVEs and prints them out to the terminal and also adds them to the JSON
        output
        """
        for cve in cve_list:
            cve_id = cve["cve"]["id"]
            ptprint(f"The host may be vulnerable to {cve_id} \thttps://nvd.nist.gov/vuln/detail/{cve_id}",
                    "VULN", not self.args.json, indent=8)

            es_node_key = self.helpers.check_node("swES")
            if es_node_key:
                self.ptjsonlib.add_vulnerability(f"PTV-{cve_id}", node_key=es_node_key)
            else:
                self.ptjsonlib.add_vulnerability(f"PTV-{cve_id}")


    def run(self) -> None:
        """
        Executes the Elasticsearch CVE lookup

        The test first sends a request to the NVD CVE API (https://nvd.nist.gov/developers/vulnerabilities) to look for vulnerabilities in the host's Elasticsearch version.
        It then goes through the response and prints the vulnerabilities with the _print_cve() method

        If we get a different HTTP response other than 200 OK, the test exits
        """
        es_version = self.base_response.json()["version"]["number"]
        nvd_url = f"https://services.nvd.nist.gov/rest/json/cves/2.0?cpeName=cpe:2.3:a:elastic:elasticsearch:{es_version}&isVulnerable"

        try:
            response = self.http_client.send_request(method="GET", url=nvd_url)
        except requests.exceptions.RequestException as e:
            self.ptjsonlib.end_error(f"Error retrieving response from NVD database:", details=e,
                                     condition=self.args.json)

        if response.status_code != HTTPStatus.OK:
            ptprint(f"Error retrieving response from NVD database. Received response: {response.status_code} {response.text}",
                    "ADDITIONS", self.args.verbose, indent=4, colortext=True)
            return

        response = response.json()
        cve_list = response.get("vulnerabilities", [])

        if cve_list:
            ptprint(f"Identified {response['totalResults']} possible vulnerabilities in Elasticsearch {es_version}", "VULN",
                    not self.args.json, indent=4)
            self._print_cve(cve_list)
        else:
            ptprint(f"Could not identify any publicly known vulnerabilities in Elasticsearch {es_version}",
                    "OK",
                    not self.args.json, indent=4)

def run(args, ptjsonlib, helpers, http_client, base_response):
    """Entry point for running the Vuln test"""
    Vuln(args, ptjsonlib, helpers, http_client, base_response).run()
