def health(): key = get_key() if key is None: raise AuthenticationRequiredError url = current_app.config['AVOTX_URL'] headers = {'User-Agent': current_app.config['CTR_USER_AGENT']} client = Client(key, url, headers=headers) _ = client.query('/api/v1/user/me') return jsonify_data({'status': 'ok'})
def observe(self, client: Client, limit: Optional[int] = None) -> Bundle: """Build a CTIM bundle for the current observable.""" bundle = Bundle() # Implement a workaround instead of using the "/api/v1/search/pulses" # endpoint as it works too slow and is not really optimizable... category = { 'ip': 'IPv4', 'ipv6': 'IPv6', }.get( self.type(), self.category(), ) endpoint = (f'/api/v1/indicators/{category}/' f"{quote(self.value, safe='@:')}/general") data = client.query(endpoint) if data is None: return bundle # Make sure to filter out redundant pulses that do not match anyway. pulses = [ pulse for pulse in data['pulse_info']['pulses'] if data['base_indicator']['type'] in pulse['indicator_type_counts'] ] if not pulses: return bundle def indicator_for(pulse, page=1): # This limit provides a decent tradeoff between the number of # requests to be made and the size of each response coming back. limit = 10000 endpoint = f"/api/v1/pulses/{pulse['id']}/indicators" params = {'sort': '-created', 'limit': limit, 'page': page} data = client.query(endpoint, params=params) for indicator in data['results']: if indicator['indicator'] == self.value: return indicator if data['next'] is None: return None return indicator_for(pulse, page=(page + 1)) with ThreadPoolExecutor(max_workers=get_workers(pulses)) as executor: iterator = executor.map(indicator_for, pulses) indicators = [] while True: try: indicator = next(iterator) except RelayError: continue except StopIteration: break else: if indicator is None: continue indicators.append(indicator) indicators.sort(key=itemgetter('created'), reverse=True) if limit is None: limit = len(indicators) indicators = indicators[:limit] observable = self.json() for indicator in indicators: pulse = next(pulse for pulse in pulses if pulse['id'] == indicator['pulse_key']) # Enrich each AVOTX pulse with some additional context in order to # simplify further mapping of that pulse into CTIM entities. pulse['indicator'] = indicator pulse['observable'] = observable pulse['url'] = client.url sighting = Sighting.map(pulse) indicator = Indicator.map(pulse) relationship = Relationship.map(sighting, indicator) bundle.add(sighting) bundle.add(indicator) bundle.add(relationship) return bundle