11"""Client for the CATALYST API."""
22
33import logging
4+ import time
45import uuid
56from datetime import datetime
67from typing import Dict , List , Optional , Tuple
@@ -17,7 +18,7 @@ class CatalystClient:
1718
1819 def __init__ (
1920 self ,
20- api_key : str ,
21+ api_key : str = None ,
2122 base_url : str = "https://prod.blindspot.prodaft.com/api" ,
2223 proxy_url : Optional [str ] = None ,
2324 logger : Optional [logging .Logger ] = None ,
@@ -62,6 +63,7 @@ def __init__(
6263 # extra config params
6364 self .create_observables = create_observables
6465 self .create_indicators = create_indicators
66+ self ._last_request_time = 0
6567
6668 def _handle_request (
6769 self , method : str , endpoint : str , params : Dict = None , data : Dict = None
@@ -83,6 +85,18 @@ def _handle_request(
8385 """
8486 url = f"{ self .base_url } /{ endpoint .lstrip ('/' )} "
8587
88+ if not self .catalyst_authenticated :
89+ current_time = time .time ()
90+ time_since_last_request = current_time - self ._last_request_time
91+ if time_since_last_request < 20 :
92+ sleep_time = 20 - time_since_last_request
93+ if self .logger :
94+ self .logger .debug (
95+ f"Sleeping for { sleep_time :.2f} seconds between requests" # noqa: E231
96+ )
97+ time .sleep (sleep_time )
98+ self ._last_request_time = time .time ()
99+
86100 try :
87101 self .logger .debug (f"Making { method } request to { url } " )
88102 response = self .session .request (
@@ -499,7 +513,12 @@ def create_report_from_member_content_with_references(
499513 entity_id = threat_actor .get ("id" )
500514 entity_value = threat_actor .get ("value" )
501515 context = threat_actor .get ("context" )
502-
516+ if not self .catalyst_authenticated :
517+ if self .logger :
518+ self .logger .debug (
519+ f"Skipping threat actor { entity_value } because user is not authenticated... This will be implemented in the future."
520+ )
521+ continue
503522 if entity_id and entity_value :
504523 try :
505524 # Fetch detailed information for the threat actor
@@ -518,101 +537,6 @@ def create_report_from_member_content_with_references(
518537 report_reference = external_reference ,
519538 )
520539
521- # Process relationships from detailed threat actor data regardless of type
522- """
523- # 1. Process attack patterns
524- attack_pattern_data = detailed_threat_actor.get("attack_patterns", [])
525- if isinstance(attack_pattern_data, list):
526- for attack_pattern in attack_pattern_data:
527- pattern_id = attack_pattern.get("id")
528- pattern_name = attack_pattern.get("name")
529-
530- if pattern_id and pattern_name:
531- # Create the attack pattern
532- attack_pattern_obj = self.converter.create_attack_pattern(
533- pattern_id,
534- pattern_name,
535- attack_pattern.get("description"),
536- report_reference=external_reference,
537- )
538- related_objects.append(attack_pattern_obj)
539- collected_object_refs.append(attack_pattern_obj.id)
540-
541- # Create relationship
542- rel = self._create_relationship_objects(
543- ta_object.id,
544- attack_pattern_obj.id,
545- "uses",
546- external_reference
547- )
548- related_objects.append(rel)
549- collected_object_refs.append(rel.id)
550-
551- if self.logger:
552- self.logger.debug(f"Added attack pattern {pattern_name} used by {entity_value}")
553-
554- # 2. Process campaigns
555- campaign_data = detailed_threat_actor.get("campaigns", [])
556- if isinstance(campaign_data, list):
557- for campaign in campaign_data:
558- campaign_id = campaign.get("id")
559- campaign_name = campaign.get("name")
560-
561- if campaign_id and campaign_name:
562- # Create the campaign
563- campaign_obj = self.converter.create_campaign(
564- campaign_id,
565- campaign_name,
566- campaign.get("description"),
567- report_reference=external_reference,
568- )
569- related_objects.append(campaign_obj)
570- collected_object_refs.append(campaign_obj.id)
571-
572- # Create relationship with appropriate relationship type
573- rel = self._create_relationship_objects(
574- ta_object.id,
575- campaign_obj.id,
576- "attributed-to",
577- external_reference
578- )
579- related_objects.append(rel)
580- collected_object_refs.append(rel.id)
581-
582- if self.logger:
583- self.logger.debug(f"Added campaign {campaign_name} attributed to {entity_value}")
584-
585- # 3. Process countries/suspected origins
586- origin_data = detailed_threat_actor.get("suspected_origins", [])
587- if isinstance(origin_data, list):
588- for country in origin_data:
589- country_id = country.get("id")
590- country_name = country.get("name")
591-
592- if country_id and country_name:
593- # Create the location
594- location_obj = self.converter.create_country_location(
595- country_id,
596- country_name,
597- None,
598- report_reference=external_reference,
599- )
600- related_objects.append(location_obj)
601- collected_object_refs.append(location_obj.id)
602-
603- # Create relationship
604- rel = self._create_relationship_objects(
605- ta_object.id,
606- location_obj.id,
607- "originates-from",
608- external_reference
609- )
610- related_objects.append(rel)
611- collected_object_refs.append(rel.id)
612-
613- if self.logger:
614- self.logger.debug(f"Added suspected origin {country_name} for {entity_value}")
615- """
616540 is_abstract = detailed_threat_actor .get (
617541 "is_abstract" , False
618542 )
0 commit comments