#-------------------------------------------------------------------------------
# Name:         sfp_hunter
# Purpose:      Query hunter.io using their API.
#
# Author:      Steve Micallef <steve@binarypool.com>
#
# Created:     22/02/2017
# Copyright:   (c) Steve Micallef
# Licence:     GPL
#-------------------------------------------------------------------------------

import json
from sflib import SpiderFoot, SpiderFootPlugin, SpiderFootEvent

class sfp_hunter(SpiderFootPlugin):
    """Hunter.io:Footprint,Investigate,Passive:Search Engines:apikey:Check for e-mail addresses and names on hunter.io."""


    # Default options
    opts = { 
        "api_key": ""
    }

    # Option descriptions
    optdescs = {
        "api_key": "Hunter.io API key."
    }

    # Be sure to completely clear any class variables in setup()
    # or you run the risk of data persisting between scan runs.

    results = None
    errorState = False

    def setup(self, sfc, userOpts=dict()):
        self.sf = sfc
        self.results = self.tempStorage()
        self.errorState = False

        # Clear / reset any other class member variables here
        # or you risk them persisting between threads.

        for opt in userOpts.keys():
            self.opts[opt] = userOpts[opt]

    # What events is this module interested in for input
    def watchedEvents(self):
        return [ "DOMAIN_NAME", "INTERNET_NAME" ]

    # What events this module produces
    def producedEvents(self):
        return [ "EMAILADDR", "RAW_RIR_DATA" ]

    def query(self, t):
        ret = None

        url = "https://api.hunter.io/v2/domain-search?domain=" + t + "&api_key=" + self.opts['api_key']

        res = self.sf.fetchUrl(url, timeout=self.opts['_fetchtimeout'], 
            useragent="SpiderFoot")

        if res['code'] == "404":
            return None

        if not res['content']:
            return None

        try:
            ret = json.loads(res['content'])['data']
        except Exception as e:
            self.sf.error("Error processing JSON response from hunter.io: " + str(e), False)
            return None

        return ret

    # Handle events sent to this module
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        if self.errorState:
            return None

        self.sf.debug("Received event, " + eventName + ", from " + srcModuleName)

       # Don't look up stuff twice
        if self.results.has_key(eventData):
            self.sf.debug("Skipping " + eventData + " as already mapped.")
            return None
        else:
            self.results[eventData] = True

        if self.opts['api_key'] == "":
            self.sf.error("You enabled sfp_hunter but did not set an API key!", False)
            self.errorState = True
            return None

        data = self.query(eventData)
        if data == None:
            return None

        if 'emails' not in data:
            return None

        for email in data['emails']:
            # Notify other modules of what you've found
            e = SpiderFootEvent("EMAILADDR", email['value'], self.__name__, event)
            self.notifyListeners(e)

            if 'first_name' in email and 'last_name' in email:
                if email['first_name'] != None and email['last_name'] != None:
                    n = email['first_name'] + " " + email['last_name']
                    e = SpiderFootEvent("RAW_RIR_DATA", "Possible full name: " + n, 
                                        self.__name__, event)
                    self.notifyListeners(e)


# End of sfp_hunter class

@@ -1547,16 +1547,36 @@
 (self, t
+, offset=0, limit=10
 ):%0A     
@@ -1693,16 +1693,84 @@
 pi_key'%5D
+ + %5C%0A              %22&offset=%22 + str(offset) + %22&limit=%22 + str(limit)
 %0A%0A      
@@ -2048,16 +2048,8 @@
 t'%5D)
-%5B'data'%5D
 %0A   
@@ -2986,16 +2986,24 @@
 ventData
+, 0, 100
 )%0A      
@@ -3011,142 +3011,521 @@
  if 
-data == None:%0A            return None%0A%0A        if 'emails' not in data:%0A            return None%0A%0A        for email in data%5B'emails'%5D:%0A
+not data:%0A            return None%0A%0A        if %22data%22 not in data:%0A            return None%0A%0A        # Check if we have more results on further pages%0A        if %22meta%22 in data:%0A            maxgoal = data%5B'meta'%5D.get('results', 100)%0A        else:%0A            maxgoal = 100%0A%0A        rescount = len(data%5B'data'%5D.get('emails', list()))%0A        print %22RESCOUNT:%22 + str(rescount)%0A        print %22MAXGOAL: %22 + str(maxgoal)%0A        while rescount %3C= maxgoal:%0A            for email in data%5B'data'%5D.get('emails', list()):%0A    
     
@@ -3576,16 +3576,20 @@
 e found%0A
+    
         
@@ -3667,32 +3667,36 @@
 nt)%0A            
+ 
+   
 self.notifyListe
@@ -3716,16 +3716,20 @@
         
+   
+ 
 if 'firs
@@ -3771,16 +3771,20 @@
  email:%0A
+    
         
@@ -3874,16 +3874,20 @@
         
+ 
+   
 n = emai
@@ -3929,16 +3929,20 @@
 _name'%5D%0A
+    
         
@@ -4054,24 +4054,28 @@
             
+    
 self.__name_
@@ -4096,32 +4096,36 @@
                 
+  
+  
 self.notifyListe
@@ -4133,16 +4133,372 @@
 ers(e)%0A%0A
+            if rescount %3E= maxgoal:%0A                return None%0A%0A            data = self.query(eventData, rescount, 100)%0A            if data == None:%0A                return None%0A            if %22data%22 not in data:%0A                return None%0A%0A            rescount += len(data%5B'data'%5D.get('emails', list()))%0A            print %22NEWRESCOUNT:%22 + str(rescount)%0A%0A
 %0A# End o

Support pagination in Hunter.io