#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Source file for the Exploit-DB information
#   Note: This information has to be mapped to refmap, as the source
#         does not contain cve IDs
#
# Software is free software released under the "Modified BSD license"
#
# Copyright (c) 2016 	Pieter-Jan Moreels - pieterjan.moreels@gmail.com

# Sources
SOURCE_NAME  = 'exploit-db'
SOURCE_FILE1 = "https://github.com/offensive-security/exploit-database/raw/master/files_exploits.csv"
SOURCE_FILE2 = "https://vulners.com/api/v3/archive/collection/?type=exploitdb&api_key={}"
SOURCE_ID    = "EDB-ID:%s"

# Imports
import csv
import zipfile
import json

from collections import defaultdict
from io          import StringIO
from lib.Config  import Configuration as conf
from lib.Source  import Source

def add_if(_, entry, item, name=None):
    if not name: name=item
    if entry.get(item): _[name] = entry[item]

def clean_date(_, item):
    if _.get(item): _[item] = _[item].split('T')[0]

class ExploitDB(Source):
  def __init__(self):
    self.name = SOURCE_NAME
    self.cves = defaultdict(list)
    self.exploits = {}

    # Source 1 (Exploit db github)
    source_file2 = SOURCE_FILE2.format(conf.readSetting( "vulners", "api_key", ""))
    _file, r = conf.getFeedData(SOURCE_NAME, SOURCE_FILE1)
    exploits={}
    exploitcsv = csv.DictReader(StringIO(_file.decode('utf-8')), delimiter=',')
    for row in exploitcsv:
      self.exploits[row['id']] = row

    # Source 2 (Vulners)
    _file, r = conf.getFeedData(SOURCE_NAME, source_file2)
    data = json.loads(str(_file.read(), 'utf-8'))
    for entry in data:
      edb = {}
      source = entry['_source']
      add_if(edb, source, 'published')
      add_if(edb, source, 'modified')
      add_if(edb, source, 'lastseen', 'last seen')
      add_if(edb, source, 'id')
      add_if(edb, source, 'title')
      add_if(edb, source, 'description')
      add_if(edb, source, 'references')
      add_if(edb, source, 'reporter')
      add_if(edb, source, 'sourceHref', 'source')

      for date in ['published', 'modified', 'last seen']: clean_date(edb, date)
      if edb:
        for CVE in source['cvelist']: self.cves[CVE].append(edb)


  def updateRefs(self, cveID, cveData):
    # Map exploit-db id's to refmap id's
    for exploitID in cveData.get('refmap', {}).get(SOURCE_NAME, []):
      if SOURCE_NAME not in cveData: cveData[SOURCE_NAME] = []
      _found = False
      for entry in cveData[SOURCE_NAME]:
        if entry.get('id') == SOURCE_ID%exploitID:
          if exploitID in self.exploits.keys():
            edb = self.exploits[exploitID]
            entry = entry.update({'file':     edb['file'],     'type': edb['type'],
                                  'platform': edb['platform'], 'port': edb['port']})
            _found = True
      if not _found:
        cveData[SOURCE_NAME].append({'id': SOURCE_ID%exploitID})


  def cleanUp(self, cveID, cveData):
    if cveData.get('refmap', {}).get(SOURCE_NAME):
      del cveData['refmap'][SOURCE_NAME]


  def getSearchables(self):
    return ['author', 'file', 'id', 'type']
