--
-- (C) 2013-24 - ntop.org
--
-- **********************************************************

local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path

local json = require("dkjson")

local cve_utils = {}

-- **********************************************************

-- Example CVE-2023-28531
local function retrieveCVE(cve_id)
   local base_path = dirs.workingdir.."/cve/"
   local cve_path  = base_path .. cve_id

   if(not(ntop.exists(cve_path))) then
      if(not(ntop.exists(base_path))) then
	 ntop.mkdir(base_path)
      end
      
      -- Retrieve the CVE
      local rsp = ntop.httpGet("https://services.nvd.nist.gov/rest/json/cves/2.0?cveId="..cve_id)

      if(rsp and (rsp.RESPONSE_CODE == 200)) then
	 local handle = io.open(cve_path, "w")

	 if(handle ~= nil) then
	    local result = handle:write(rsp.CONTENT)
	    handle:close()
	 end

	 return(json.decode(rsp.CONTENT))
      end
   end

   if(ntop.exists(cve_path)) then
      local handle = io.open(cve_path, "r")
      local result = handle:read("*a")      
      handle:close()

      return(json.decode(result))
   else
      return(nil)
   end
end

-- **********************************************************

-- Retrieve full CVE information
function cve_utils.getCVE(cve_id)
   local cve = retrieveCVE(cve_id)
   local rsp = {}
   
   if(cve == nil) then
      return(nil)
   end

   for _,v in pairs(cve.vulnerabilities) do
      local c = v.cve

      rsp.published           = c.published

      if(c.metrics.cvssMetricV31 ~= nil) then
	 for _,v1 in pairs(c.metrics.cvssMetricV31) do
	    rsp.baseScore           = v1.cvssData.baseScore
	    rsp.exploitabilityScore = v1.exploitabilityScore	    
	    break
	 end
   elseif(c.metrics.cvssMetricV2 ~= nil) then
      for _,v1 in pairs(c.metrics.cvssMetricV2) do
         rsp.baseScore           = v1.cvssData.baseScore
         rsp.exploitabilityScore = v1.exploitabilityScore	    
         break
      end
   end

      for _,d in pairs(c.descriptions) do
	 rsp.description = d.value
	 break
      end
      
      rsp.references          = {}

      for _,d in pairs(c.references) do
	 table.insert(rsp.references, d.url)
      end

      break
   end
   
   return(rsp)
end

-- **********************************************************

function cve_utils.getCVEscore(cve_id)
   local cve = cve_utils.getCVE(cve_id)
   
   if((cve ~= nil) and (cve.baseScore ~= nil)) then
      return(tonumber(cve.baseScore))
   else
      -- must be a number
      return 0
   end
end

-- **********************************************************

-- Function to retrieve url for CVE doc.
function cve_utils.getDocURL(cve_id, scan_type) 
   -- IMPORTANT: The retrieved value must match the value in 
      -- http_src/services/context/ntopng_global_services.js for the 'get_cve_details_url' function.
   if (scan_type == 'cve') then
      return(string.format("https://nvd.nist.gov/vuln/detail/%s",cve_id))
   elseif (scan_type =='openvas') then
      return(string.format("https://vulners.com/openvas/OPENVAS:%s",cve_id))
   end
end

-- **********************************************************

-- Function to select first 5 CVEs.
function cve_utils.getFirst5(cves, scan_type, print_result)
   local result_string = ""
   local i = 0

   for _,vs in ipairs(cves) do
      if (i<5) then
         
          local cve_details = split(vs,"|")
          local cve_score = tonumber(cve_details[2])
          local cve_id = cve_details[1]

          local badge_type = "";
          if (cve_score == 0) then
              badge_type = "bg-success";
          elseif(cve_score < 3.9) then
              badge_type = "bg-secondary";
          elseif(cve_score < 7) then
              badge_type = "bg-warning";
          else
              badge_type = "bg-danger";
          end

          local url = cve_utils.getDocURL(cve_id, scan_type)
          local element = '<a href='..url..'><span class="badge '..badge_type..'">'..cve_id..'</span></a>'
          if (print_result) then
            print(element..' ')
          else
            result_string = string.format("%s%s",ternary(result_string~="",result_string..",",result_string),element)
          end
      else
          if(print_result) then

            print('...')
          else
            result_string = string.format("%s%s",result_string,"...")
          end
          break 
      end
      i = i + 1
  end

  if (not print_result) then
   return result_string
  end
end


return cve_utils
