Repository: smicallef/spiderfoot
File: modules/sfp_grayhatwarfare.py (Python)

Code before:
    def watchedEvents(self):
        return [
            "DOMAIN_NAME",
        ]

    # What events this module produces
    def producedEvents(self):
        return [
            'CLOUD_STORAGE_BUCKET',
            'CLOUD_STORAGE_BUCKET_OPEN',
            'RAW_RIR_DATA'
        ]

    # Query Grayhat Warfare
    def query(self, keyword, start):
        queryString = f"https://buckets.grayhatwarfare.com/api/v1/buckets/{start}/{self.opts['per_page']}?access_token={self.opts['api_key']}&keywords={keyword}"

        headers = {
            'Accept': 'application/json',
        }

        res = self.sf.fetchUrl(queryString,
                               headers=headers,
                               timeout=15,
                               useragent=self.opts['_useragent'],
                               verify=True)

        time.sleep(self.opts['pause'])

        if res['code'] != "200":
            self.sf.error("Unable to fetch data from Grayhat Warfare API.")
            self.errorState = True
            return None

        if res['content'] is None:
            self.sf.debug('No response from Grayhat Warfare API.')
            return None

        try:
            return json.loads(res['content'])
        except Exception as e:
            self.sf.debug(f"Error processing JSON response: {e}")
            return None

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

        if eventData in self.results:

Review comment (security):
The usual code pattern is to `import urllib` and use `urllib.parse.urlencode` to prevent issues with encoding.

```suggestion
        params = urllib.parse.urlencode({
            'keywords': keyword.encode('raw_unicode_escape'),
            'access_token': self.opts['api_key']
        })

        headers = {
            'Accept': 'application/json',
        }

        res = self.sf.fetchUrl(
            f"https://buckets.grayhatwarfare.com/api/v1/buckets/{start}/{self.opts['per_page']}?{params}",
            headers=headers,
            timeout=15,
            useragent=self.opts['_useragent'],
            verify=True
        )
```

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

    # What events this module produces
    def producedEvents(self):
        return [
            'CLOUD_STORAGE_BUCKET',
            'CLOUD_STORAGE_BUCKET_OPEN',
            'RAW_RIR_DATA'
        ]

    # Query Grayhat Warfare
    def query(self, keyword, start):
        params = urllib.parse.urlencode({
            'keywords': keyword.encode('raw_unicode_escape'),
            'access_token': self.opts['api_key']
        })

        headers = {
            'Accept': 'application/json',
        }

        res = self.sf.fetchUrl(
            f"https://buckets.grayhatwarfare.com/api/v1/buckets/{start}/{self.opts['per_page']}?{params}",
            headers=headers,
            timeout=15,
            useragent=self.opts['_useragent'],
            verify=True
        )

        time.sleep(self.opts['pause'])

        if res['code'] != "200":
            self.sf.error("Unable to fetch data from Grayhat Warfare API.")
            self.errorState = True
            return None

        if res['content'] is None:
            self.sf.debug('No response from Grayhat Warfare API.')
            return None

        try:
            return json.loads(res['content'])
        except Exception as e:
            self.sf.debug(f"Error processing JSON response: {e}")
            return None

    # Handle events sent to this module