prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Yeti analyzer crash
  From the celery log:
  
  ```
  [2019-07-17 09:11:37,463: ERROR/ForkPoolWorker-1] Task timesketch.lib.tasks.run_sketch_analyzer[46d24990-12df-4c88-a79b-a3b5f1c04b01] raised unexpected: TypeError("unsupported operand type(s) for +: 'NoneType' and 'unicode'",)
  Traceback (most recent call last):
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/celery/app/trace.py", line 374, in trace_task
      R = retval = fun(*args, **kwargs)
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/__init__.py", line 181, in __call__
      return TaskBase.__call__(self, *args, **kwargs)
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/celery/app/trace.py", line 629, in __protected_call__
      return self.run(*args, **kwargs)
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/tasks.py", line 339, in run_sketch_analyzer
      result = analyzer.run_wrapper()
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/interface.py", line 37, in wrapper
      func_return = func(self, *args, **kwargs)
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/interface.py", line 403, in run_wrapper
      result = self.run()
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/yetiindicators.py", line 92, in run
      self.get_intrusion_sets()
    File "/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/yetiindicators.py", line 75, in get_intrusion_sets
      self.yeti_api_root + '/entities/filter/',
  TypeError: unsupported operand type(s) for +: 'NoneType' and 'unicode'
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `timesketch/lib/analyzers/yetiindicators.py`
  Content:
  ```
  1 """Index analyzer plugin for Yeti indicators."""
  2 from __future__ import unicode_literals
  3 
  4 from flask import current_app
  5 import requests
  6 
  7 from timesketch.lib.analyzers import interface
  8 from timesketch.lib.analyzers import manager
  9 from timesketch.lib import emojis
  10 
  11 
  12 def build_query_for_indicators(indicators):
  13     """Builds an Elasticsearch query for Yeti indicator patterns.
  14 
  15     Prepends and appends .* to the regex to be able to search within a field.
  16 
  17     Returns:
  18       The resulting ES query string.
  19     """
  20     query = []
  21     for domain in indicators:
  22         query.append('domain:/.*{0:s}.*/'.format(domain['pattern']))
  23     return ' OR '.join(query)
  24 
  25 
  26 class YetiIndicators(interface.BaseSketchAnalyzer):
  27     """Index analyzer for Yeti threat intel indicators."""
  28 
  29     NAME = 'yetiindicators'
  30     DEPENDENCIES = frozenset(['domain'])
  31 
  32     def __init__(self, index_name, sketch_id):
  33         """Initialize the Index Analyzer.
  34 
  35         Args:
  36             index_name: Elasticsearch index name
  37         """
  38         super(YetiIndicators, self).__init__(index_name, sketch_id)
  39         self.intel = {}
  40         self.yeti_api_root = current_app.config.get('YETI_API_ROOT')
  41         self.yeti_api_key = current_app.config.get('YETI_API_KEY')
  42         self.yeti_indicator_labels = current_app.config.get(
  43             'YETI_INDICATOR_LABELS', [])
  44 
  45     def get_bad_domain_indicators(self, entity_id):
  46         """Retrieves a list of indicators associated to a given entity.
  47 
  48         Args:
  49           entity_id (str): STIX ID of the entity to get associated inticators
  50                 from. (typically an Intrusion Set)
  51 
  52         Returns:
  53           A list of JSON objects describing a Yeti Indicator.
  54         """
  55         results = requests.post(
  56             self.yeti_api_root + '/entities/{0:s}/neighbors/'.format(entity_id),
  57             headers={'X-Yeti-API': self.yeti_api_key},
  58         )
  59         if results.status_code != 200:
  60             return []
  61         domain_indicators = []
  62         for neighbor in results.json().get('vertices', {}).values():
  63             if neighbor['type'] == 'x-regex' and \
  64                 set(self.yeti_indicator_labels) <= set(neighbor['labels']):
  65                 domain_indicators.append(neighbor)
  66 
  67         return domain_indicators
  68 
  69     def get_intrusion_sets(self):
  70         """Populates the intel attribute with data from Yeti.
  71 
  72         Retrieved intel consists of Intrusion sets and associated Indicators.
  73         """
  74         results = requests.post(
  75             self.yeti_api_root + '/entities/filter/',
  76             json={'name': '', 'type': 'intrusion-set'},
  77             headers={'X-Yeti-API': self.yeti_api_key},
  78         )
  79         if results.status_code != 200:
  80             return
  81         self.intel = {item['id']: item for item in results.json()}
  82         for _id in self.intel:
  83             self.intel[_id]['indicators'] = self.get_bad_domain_indicators(_id)
  84 
  85     def run(self):
  86         """Entry point for the analyzer.
  87 
  88         Returns:
  89             String with summary of the analyzer result
  90         """
  91 
  92         self.get_intrusion_sets()
  93         actors_found = []
  94         for intrusion_set in self.intel.values():
  95             if not intrusion_set['indicators']:
  96                 continue
  97 
  98             found = False
  99 
  100             for indicator in intrusion_set['indicators']:
  101                 query = build_query_for_indicators([indicator])
  102 
  103                 events = self.event_stream(query_string=query,
  104                                            return_fields=[])
  105 
  106                 name = intrusion_set['name']
  107                 for event in events:
  108                     found = True
  109                     event.add_emojis([emojis.get_emoji('SKULL')])
  110                     event.add_tags([name])
  111                     event.commit()
  112                     event.add_comment(
  113                         'Indicator "{0:s}" found for actor "{1:s}"'.format(
  114                             indicator['name'], name))
  115 
  116             if found:
  117                 actors_found.append(name)
  118                 self.sketch.add_view(
  119                     'Domain activity for actor {0:s}'.format(name),
  120                     self.NAME,
  121                     query_string=query)
  122 
  123         if actors_found:
  124             return '{0:d} actors were found! [{1:s}]'.format(
  125                 len(actors_found), ', '.join(actors_found))
  126         return 'No indicators were found in the timeline.'
  127 
  128 
  129 manager.AnalysisManager.register_analyzer(YetiIndicators)
  130
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/timesketch/lib/analyzers/yetiindicators.py b/timesketch/lib/analyzers/yetiindicators.py
  --- a/timesketch/lib/analyzers/yetiindicators.py
  +++ b/timesketch/lib/analyzers/yetiindicators.py
  @@ -88,6 +88,8 @@
           Returns:
               String with summary of the analyzer result
           """
  +        if not self.yeti_api_root or not self.yeti_api_key:
  +            return 'No Yeti configuration settings found, aborting.'
   
           self.get_intrusion_sets()
           actors_found = []
  
verification_info: {"golden_diff": "diff --git a/timesketch/lib/analyzers/yetiindicators.py b/timesketch/lib/analyzers/yetiindicators.py\n--- a/timesketch/lib/analyzers/yetiindicators.py\n+++ b/timesketch/lib/analyzers/yetiindicators.py\n@@ -88,6 +88,8 @@\n         Returns:\n             String with summary of the analyzer result\n         \"\"\"\n+        if not self.yeti_api_root or not self.yeti_api_key:\n+            return 'No Yeti configuration settings found, aborting.'\n \n         self.get_intrusion_sets()\n         actors_found = []\n", "issue": "Yeti analyzer crash\nFrom the celery log:\r\n\r\n```\r\n[2019-07-17 09:11:37,463: ERROR/ForkPoolWorker-1] Task timesketch.lib.tasks.run_sketch_analyzer[46d24990-12df-4c88-a79b-a3b5f1c04b01] raised unexpected: TypeError(\"unsupported operand type(s) for +: 'NoneType' and 'unicode'\",)\r\nTraceback (most recent call last):\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/celery/app/trace.py\", line 374, in trace_task\r\n    R = retval = fun(*args, **kwargs)\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/__init__.py\", line 181, in __call__\r\n    return TaskBase.__call__(self, *args, **kwargs)\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/celery/app/trace.py\", line 629, in __protected_call__\r\n    return self.run(*args, **kwargs)\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/tasks.py\", line 339, in run_sketch_analyzer\r\n    result = analyzer.run_wrapper()\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/interface.py\", line 37, in wrapper\r\n    func_return = func(self, *args, **kwargs)\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/interface.py\", line 403, in run_wrapper\r\n    result = self.run()\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/yetiindicators.py\", line 92, in run\r\n    self.get_intrusion_sets()\r\n  File \"/opt/timesketch/env/local/lib/python2.7/site-packages/timesketch/lib/analyzers/yetiindicators.py\", line 75, in get_intrusion_sets\r\n    self.yeti_api_root + '/entities/filter/',\r\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'unicode'\r\n```\n", "before_files": [{"content": "\"\"\"Index analyzer plugin for Yeti indicators.\"\"\"\nfrom __future__ import unicode_literals\n\nfrom flask import current_app\nimport requests\n\nfrom timesketch.lib.analyzers import interface\nfrom timesketch.lib.analyzers import manager\nfrom timesketch.lib import emojis\n\n\ndef build_query_for_indicators(indicators):\n    \"\"\"Builds an Elasticsearch query for Yeti indicator patterns.\n\n    Prepends and appends .* to the regex to be able to search within a field.\n\n    Returns:\n      The resulting ES query string.\n    \"\"\"\n    query = []\n    for domain in indicators:\n        query.append('domain:/.*{0:s}.*/'.format(domain['pattern']))\n    return ' OR '.join(query)\n\n\nclass YetiIndicators(interface.BaseSketchAnalyzer):\n    \"\"\"Index analyzer for Yeti threat intel indicators.\"\"\"\n\n    NAME = 'yetiindicators'\n    DEPENDENCIES = frozenset(['domain'])\n\n    def __init__(self, index_name, sketch_id):\n        \"\"\"Initialize the Index Analyzer.\n\n        Args:\n            index_name: Elasticsearch index name\n        \"\"\"\n        super(YetiIndicators, self).__init__(index_name, sketch_id)\n        self.intel = {}\n        self.yeti_api_root = current_app.config.get('YETI_API_ROOT')\n        self.yeti_api_key = current_app.config.get('YETI_API_KEY')\n        self.yeti_indicator_labels = current_app.config.get(\n            'YETI_INDICATOR_LABELS', [])\n\n    def get_bad_domain_indicators(self, entity_id):\n        \"\"\"Retrieves a list of indicators associated to a given entity.\n\n        Args:\n          entity_id (str): STIX ID of the entity to get associated inticators\n                from. (typically an Intrusion Set)\n\n        Returns:\n          A list of JSON objects describing a Yeti Indicator.\n        \"\"\"\n        results = requests.post(\n            self.yeti_api_root + '/entities/{0:s}/neighbors/'.format(entity_id),\n            headers={'X-Yeti-API': self.yeti_api_key},\n        )\n        if results.status_code != 200:\n            return []\n        domain_indicators = []\n        for neighbor in results.json().get('vertices', {}).values():\n            if neighbor['type'] == 'x-regex' and \\\n                set(self.yeti_indicator_labels) <= set(neighbor['labels']):\n                domain_indicators.append(neighbor)\n\n        return domain_indicators\n\n    def get_intrusion_sets(self):\n        \"\"\"Populates the intel attribute with data from Yeti.\n\n        Retrieved intel consists of Intrusion sets and associated Indicators.\n        \"\"\"\n        results = requests.post(\n            self.yeti_api_root + '/entities/filter/',\n            json={'name': '', 'type': 'intrusion-set'},\n            headers={'X-Yeti-API': self.yeti_api_key},\n        )\n        if results.status_code != 200:\n            return\n        self.intel = {item['id']: item for item in results.json()}\n        for _id in self.intel:\n            self.intel[_id]['indicators'] = self.get_bad_domain_indicators(_id)\n\n    def run(self):\n        \"\"\"Entry point for the analyzer.\n\n        Returns:\n            String with summary of the analyzer result\n        \"\"\"\n\n        self.get_intrusion_sets()\n        actors_found = []\n        for intrusion_set in self.intel.values():\n            if not intrusion_set['indicators']:\n                continue\n\n            found = False\n\n            for indicator in intrusion_set['indicators']:\n                query = build_query_for_indicators([indicator])\n\n                events = self.event_stream(query_string=query,\n                                           return_fields=[])\n\n                name = intrusion_set['name']\n                for event in events:\n                    found = True\n                    event.add_emojis([emojis.get_emoji('SKULL')])\n                    event.add_tags([name])\n                    event.commit()\n                    event.add_comment(\n                        'Indicator \"{0:s}\" found for actor \"{1:s}\"'.format(\n                            indicator['name'], name))\n\n            if found:\n                actors_found.append(name)\n                self.sketch.add_view(\n                    'Domain activity for actor {0:s}'.format(name),\n                    self.NAME,\n                    query_string=query)\n\n        if actors_found:\n            return '{0:d} actors were found! [{1:s}]'.format(\n                len(actors_found), ', '.join(actors_found))\n        return 'No indicators were found in the timeline.'\n\n\nmanager.AnalysisManager.register_analyzer(YetiIndicators)\n", "path": "timesketch/lib/analyzers/yetiindicators.py"}], "after_files": [{"content": "\"\"\"Index analyzer plugin for Yeti indicators.\"\"\"\nfrom __future__ import unicode_literals\n\nfrom flask import current_app\nimport requests\n\nfrom timesketch.lib.analyzers import interface\nfrom timesketch.lib.analyzers import manager\nfrom timesketch.lib import emojis\n\n\ndef build_query_for_indicators(indicators):\n    \"\"\"Builds an Elasticsearch query for Yeti indicator patterns.\n\n    Prepends and appends .* to the regex to be able to search within a field.\n\n    Returns:\n      The resulting ES query string.\n    \"\"\"\n    query = []\n    for domain in indicators:\n        query.append('domain:/.*{0:s}.*/'.format(domain['pattern']))\n    return ' OR '.join(query)\n\n\nclass YetiIndicators(interface.BaseSketchAnalyzer):\n    \"\"\"Index analyzer for Yeti threat intel indicators.\"\"\"\n\n    NAME = 'yetiindicators'\n    DEPENDENCIES = frozenset(['domain'])\n\n    def __init__(self, index_name, sketch_id):\n        \"\"\"Initialize the Index Analyzer.\n\n        Args:\n            index_name: Elasticsearch index name\n        \"\"\"\n        super(YetiIndicators, self).__init__(index_name, sketch_id)\n        self.intel = {}\n        self.yeti_api_root = current_app.config.get('YETI_API_ROOT')\n        self.yeti_api_key = current_app.config.get('YETI_API_KEY')\n        self.yeti_indicator_labels = current_app.config.get(\n            'YETI_INDICATOR_LABELS', [])\n\n    def get_bad_domain_indicators(self, entity_id):\n        \"\"\"Retrieves a list of indicators associated to a given entity.\n\n        Args:\n          entity_id (str): STIX ID of the entity to get associated inticators\n                from. (typically an Intrusion Set)\n\n        Returns:\n          A list of JSON objects describing a Yeti Indicator.\n        \"\"\"\n        results = requests.post(\n            self.yeti_api_root + '/entities/{0:s}/neighbors/'.format(entity_id),\n            headers={'X-Yeti-API': self.yeti_api_key},\n        )\n        if results.status_code != 200:\n            return []\n        domain_indicators = []\n        for neighbor in results.json().get('vertices', {}).values():\n            if neighbor['type'] == 'x-regex' and \\\n                set(self.yeti_indicator_labels) <= set(neighbor['labels']):\n                domain_indicators.append(neighbor)\n\n        return domain_indicators\n\n    def get_intrusion_sets(self):\n        \"\"\"Populates the intel attribute with data from Yeti.\n\n        Retrieved intel consists of Intrusion sets and associated Indicators.\n        \"\"\"\n        results = requests.post(\n            self.yeti_api_root + '/entities/filter/',\n            json={'name': '', 'type': 'intrusion-set'},\n            headers={'X-Yeti-API': self.yeti_api_key},\n        )\n        if results.status_code != 200:\n            return\n        self.intel = {item['id']: item for item in results.json()}\n        for _id in self.intel:\n            self.intel[_id]['indicators'] = self.get_bad_domain_indicators(_id)\n\n    def run(self):\n        \"\"\"Entry point for the analyzer.\n\n        Returns:\n            String with summary of the analyzer result\n        \"\"\"\n        if not self.yeti_api_root or not self.yeti_api_key:\n            return 'No Yeti configuration settings found, aborting.'\n\n        self.get_intrusion_sets()\n        actors_found = []\n        for intrusion_set in self.intel.values():\n            if not intrusion_set['indicators']:\n                continue\n\n            found = False\n\n            for indicator in intrusion_set['indicators']:\n                query = build_query_for_indicators([indicator])\n\n                events = self.event_stream(query_string=query,\n                                           return_fields=[])\n\n                name = intrusion_set['name']\n                for event in events:\n                    found = True\n                    event.add_emojis([emojis.get_emoji('SKULL')])\n                    event.add_tags([name])\n                    event.commit()\n                    event.add_comment(\n                        'Indicator \"{0:s}\" found for actor \"{1:s}\"'.format(\n                            indicator['name'], name))\n\n            if found:\n                actors_found.append(name)\n                self.sketch.add_view(\n                    'Domain activity for actor {0:s}'.format(name),\n                    self.NAME,\n                    query_string=query)\n\n        if actors_found:\n            return '{0:d} actors were found! [{1:s}]'.format(\n                len(actors_found), ', '.join(actors_found))\n        return 'No indicators were found in the timeline.'\n\n\nmanager.AnalysisManager.register_analyzer(YetiIndicators)\n", "path": "timesketch/lib/analyzers/yetiindicators.py"}]}