Exemplo n.º 1
0
class Mitre:
    def __init__(self, config):
        # Initialize config
        self.config = config

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/mitre.log',
            True
        )

    def set_config(self, config):
        self.config = config

    def get_config(self):
        return self.config['mitre']

    def run(self):
        http = urllib3.PoolManager()
        with http.request('GET', self.config['mitre']['enterprise_file_url'], preload_content=False) as r, open('./enterprise.json', 'wb') as out_file:
            shutil.copyfileobj(r, out_file)

        self.opencti.stix2_import_bundle_from_file('./enterprise.json', True, self.config['mitre']['entities'])
        os.remove('./enterprise.json')
Exemplo n.º 2
0
    def __init__(self, verbose=True):
        # Initialize logger
        self.logger = Logger(
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log')

        # Load configuration
        self.config = yaml.load(
            open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log',
            self.config['opencti']['verbose'])

        # Initialize the RabbitMQ connection
        credentials = pika.PlainCredentials(
            self.config['rabbitmq']['username'],
            self.config['rabbitmq']['password'])
        connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=self.config['rabbitmq']['hostname'],
                                      port=self.config['rabbitmq']['port'],
                                      virtual_host='/',
                                      credentials=credentials))
        self.channel = connection.channel()
        self.channel.exchange_declare(exchange='opencti',
                                      exchange_type='topic',
                                      durable=True)
        self.channel.queue_declare('opencti-export', durable=True)
        self.channel.queue_bind(exchange='opencti',
                                queue='opencti-export',
                                routing_key='export.*.*')
Exemplo n.º 3
0
    def __init__(self, config):
        # Initialize config
        self.config = config

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/openctidata.log',
            True
        )
Exemplo n.º 4
0
class WorkerImport:
    def __init__(self, verbose=True):
        # Initialize logger
        self.logger = Logger(
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log')

        # Load configuration
        self.config = yaml.load(
            open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log',
            self.config['opencti']['verbose'])

        # Initialize the RabbitMQ connection
        credentials = pika.PlainCredentials(
            self.config['rabbitmq']['username'],
            self.config['rabbitmq']['password'])
        connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=self.config['rabbitmq']['hostname'],
                                      port=self.config['rabbitmq']['port'],
                                      virtual_host='/',
                                      credentials=credentials))
        self.channel = connection.channel()
        self.channel.exchange_declare(exchange='opencti',
                                      exchange_type='topic',
                                      durable=True)
        self.channel.queue_declare('opencti-import', durable=True)
        self.channel.queue_bind(exchange='opencti',
                                queue='opencti-import',
                                routing_key='import.*.*')

    def import_action(self, ch, method, properties, body):
        try:
            data = json.loads(body)
            self.logger.log('Receiving new action of type: { ' + data['type'] +
                            ' }')
            if data['type'] == 'import.stix2.bundle':
                self.opencti.stix2_import_bundle(
                    base64.b64decode(data['content']).decode('utf-8'))
        except Exception as e:
            self.logger.log('An unexpected error occurred: { ' + str(e) + ' }')
            return False

    def consume(self):
        self.channel.basic_consume(queue='opencti-import',
                                   on_message_callback=self.import_action,
                                   auto_ack=True)
        self.channel.start_consuming()
Exemplo n.º 5
0
    def __init__(self, config):
        # Initialize config
        self.config = config

        # Initialize MISP
        self.misp = PyMISP(self.config['misp']['url'], self.config['misp']['key'], False, 'json')

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/misp.log',
            True
        )
Exemplo n.º 6
0
    def __init__(self, verbose=True):
        # Initialize logger
        self.logger = Logger(
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log')

        # Load configuration
        self.config = yaml.load(
            open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log',
            self.config['opencti']['verbose'])
Exemplo n.º 7
0
class Openctidata:
    def __init__(self, config):
        # Initialize config
        self.config = config

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/openctidata.log',
            True
        )

    def set_config(self, config):
        self.config = config

    def get_config(self):
        return self.config['openctidata']

    def run(self):
        if 'sector' in self.config['openctidata']['entities']:
            sectors_data = urllib.request.urlopen(self.config['openctidata']['sectors_file_url']).read()
            sectors = json.loads(sectors_data)
            for sector in sectors:
                sector_id = self.opencti.create_identity_if_not_exists(
                    'Sector',
                    sector['name'],
                    sector['description']
                )['id']
                self.opencti.update_stix_domain_entity_field(
                    sector_id,
                    'name', sector['name']
                )
                self.opencti.update_stix_domain_entity_field(
                    sector_id,
                    'description',
                    sector['description']
                )
                for subsector in sector['subsectors']:
                    subsector_id = self.opencti.create_identity_if_not_exists(
                        'Sector',
                        subsector['name'],
                        subsector['description']
                    )['id']
                    self.opencti.update_stix_domain_entity_field(
                        subsector_id,
                        'name',
                        subsector['name']
                    )
                    self.opencti.update_stix_domain_entity_field(
                        subsector_id,
                        'description',
                        subsector['description']
                    )
                    # Temporary for fixing multiple relations of previous version
                    old_relations = self.opencti.get_stix_relations(sector_id, subsector_id)
                    for old_relation in old_relations:
                        self.opencti.delete_relation(old_relation['id'])

                    self.opencti.create_relation_if_not_exists(
                        sector_id,
                        'sector',
                        subsector_id,
                        'sector',
                        'gathering',
                        'Subsector from OpenCTI connector',
                        '1900-01-01T00:00:00.000Z',
                        '1900-01-01T00:00:00.000Z',
                        5
                    )
Exemplo n.º 8
0
class Misp:
    def __init__(self, config):
        # Initialize config
        self.config = config

        # Initialize MISP
        self.misp = PyMISP(self.config['misp']['url'], self.config['misp']['key'], False, 'json')

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/misp.log',
            True
        )

    def set_config(self, config):
        self.config = config

    def get_config(self):
        return self.config['misp']

    def run(self):
        result = self.misp.search('events', tags=[self.config['misp']['tag']])

        for event in result['response']:
            # Default values
            author_id = self.opencti.create_identity_if_not_exists(
                'Organization',
                event['Event']['Orgc']['name'],
                ''
            )['id']
            event_threats = self.prepare_threats(event['Event']['Galaxy'])
            event_markings = self.resolve_markings(event['Event']['Tag'])

            # Create the external reference of the event
            external_reference_id = self.opencti.create_external_reference_if_not_exists(
                self.config['misp']['name'],
                self.config['misp']['url'] + '/events/view/' + event['Event']['uuid'],
                event['Event']['uuid'])['id']

            # Create the report of the event
            report_id = self.opencti.create_report_if_not_exists_from_external_reference(
                external_reference_id,
                event['Event']['info'],
                event['Event']['info'],
                parse(event['Event']['date']).strftime('%Y-%m-%dT%H:%M:%SZ'),
                'external'
            )['id']
            self.opencti.update_stix_domain_entity_created_by_ref(report_id, author_id)

            # Add markings to report
            for marking in event_markings:
                self.opencti.add_marking_definition_if_not_exists(report_id, marking)

            # Add entities to report
            for threat in event_threats:
                self.opencti.add_object_ref_to_report_if_not_exists(report_id, threat['id'])

            # Get all attributes
            for attribute in event['Event']['Attribute']:
                self.process_attribute(report_id, author_id, event_threats, event_markings, attribute)
            # get all attributes of object
            for object in event['Event']['Object']:
                for attribute in object['Attribute']:
                    self.process_attribute(report_id, author_id, event_threats, event_markings, attribute)

            self.misp.tag(event['Event']['uuid'], 'OpenCTI: Imported')
            self.misp.untag(event['Event']['uuid'], self.config['misp']['tag'])

    def process_attribute(self, report_id, author_id, event_threats, event_markings, attribute):
        type = self.resolve_type(attribute['type'], attribute['value'])
        if type is not None:
            # Default values
            attribute_threats = self.prepare_threats(attribute['Galaxy'])
            if 'Tag' in attribute:
                attribute_markings = self.resolve_markings(attribute['Tag'])
            else:
                attribute_markings = []

            # Check necessary threats
            if len(event_threats) == 0 and len(attribute_threats) == 0:
                attribute_threats.append({'type': 'Threat-Actor', 'id': self.opencti.create_threat_actor_if_not_exists(
                    'Unknown threats',
                    'All unknown threats are representing by this pseudo threat actors.'
                )['id']})

            # Create observable
            observable_id = self.opencti.create_stix_observable_if_not_exists(
                type,
                attribute['value'],
                attribute['comment']
            )['id']
            self.opencti.update_stix_observable_created_by_ref(observable_id, author_id)

            # Add observable to report
            self.opencti.add_object_ref_to_report_if_not_exists(report_id, observable_id)

            # Add threats to reports
            for threat in attribute_threats:
                self.opencti.add_object_ref_to_report_if_not_exists(report_id, threat['id'])

            # Add threats to observables
            for threat in event_threats:
                relation_id = self.opencti.create_relation_if_not_exists(
                    observable_id,
                    'Observable',
                    threat['id'],
                    threat['type'],
                    'indicates',
                    attribute['comment'],
                    datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime('%Y-%m-%dT%H:%M:%SZ'),
                    datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime('%Y-%m-%dT%H:%M:%SZ'),
                    2
                )['id']
                self.opencti.add_object_ref_to_report_if_not_exists(report_id, relation_id)
            for threat in attribute_threats:
                relation_id = self.opencti.create_relation_if_not_exists(
                    observable_id,
                    'Observable',
                    threat['id'],
                    threat['type'],
                    'indicates',
                    attribute['comment'],
                    datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime('%Y-%m-%dT%H:%M:%SZ'),
                    datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime('%Y-%m-%dT%H:%M:%SZ'),
                    2
                )['id']
                self.opencti.add_object_ref_to_report_if_not_exists(report_id, relation_id)

            # Add markings to observable
            if len(attribute_markings) > 0:
                for marking in attribute_markings:
                    self.opencti.add_marking_definition_if_not_exists(observable_id, marking)
                    self.opencti.add_marking_definition_if_not_exists(observable_id, marking)
            else:
                for marking in event_markings:
                    self.opencti.add_marking_definition_if_not_exists(observable_id, marking)

    def prepare_threats(self, galaxies):
        threats = []
        for galaxy in galaxies:
            if galaxy['name'] == 'Intrusion Set':
                for galaxy_entity in galaxy['GalaxyCluster']:
                    threats.append({
                        'type': 'Intrusion-Set',
                        'id': self.opencti.create_intrusion_set_if_not_exists(
                            galaxy_entity['value'],
                            galaxy_entity['description']
                        )['id']
                    })
            if galaxy['name'] == 'Threat Actor':
                for galaxy_entity in galaxy['GalaxyCluster']:
                    threats.append({
                        'type': 'Intrusion-Set',
                        'id': self.opencti.create_intrusion_set_if_not_exists(
                            galaxy_entity['value'],
                            galaxy_entity['description']
                        )['id']
                    })
            if galaxy['name'] == 'Malware':
                for galaxy_entity in galaxy['GalaxyCluster']:
                    threats.append({
                        'type': 'Malware',
                        'id': self.opencti.create_malware_if_not_exists(
                            galaxy_entity['value'],
                            galaxy_entity['description']
                        )['id']
                    })
            if galaxy['name'] == 'Tool':
                for galaxy_entity in galaxy['GalaxyCluster']:
                    threats.append({
                        'type': 'Tool',
                        'id': self.opencti.create_tool_if_not_exists(
                            galaxy_entity['value'],
                            galaxy_entity['description']
                        )['id']
                    })
        return threats

    def resolve_type(self, type, value):
        types = {
            'ip-src': 'IPv4-Addr',
            'ip-dst': 'IPv4-Addr',
            'domain': 'Domain',
            'hostname': 'Domain',
            'url': 'URL',
            'md5': 'File-MD5',
            'sha1': 'File-SHA1',
            'sha256': 'File-SHA256'
        }
        if type in types:
            resolved_type = types[type]
            if resolved_type == 'IPv4-Addr' and len(value) > 16:
                return 'IPv6-Addr'
            else:
                return resolved_type
        else:
            return None

    def resolve_markings(self, tags):
        markings = []
        for tag in tags:
            if tag['name'] == 'tlp:white':
                markings.append(self.opencti.get_marking_definition_by_definition('TLP', 'TLP:WHITE')['id'])
            if tag['name'] == 'tlp:green':
                markings.append(self.opencti.get_marking_definition_by_definition('TLP', 'TLP:GREEN')['id'])
            if tag['name'] == 'tlp:amber':
                markings.append(self.opencti.get_marking_definition_by_definition('TLP', 'TLP:AMBER')['id'])
            if tag['name'] == 'tlp:red':
                markings.append(self.opencti.get_marking_definition_by_definition('TLP', 'TLP:RED')['id'])
        return markings
Exemplo n.º 9
0
class ConnectorsScheduler:
    def __init__(self, verbose=True):

        # Initialize connectors object
        self.connectors = {}

        # Initialize logger
        self.logger = Logger(
            os.path.dirname(os.path.abspath(__file__)) + '/scheduler.log')

        # Load configuration
        self.config = yaml.load(
            open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/scheduler.log',
            self.config['opencti']['verbose'])

    def send_stix2_bundle(self, bundle):
        self.logger.log('Sending a message to the import workers')
        # Prepare
        message = {
            'type': 'import.stix2.bundle',
            'content': base64.b64encode(bundle.encode('utf-8')).decode('utf-8')
        }

        # Initialize the RabbitMQ connection
        credentials = pika.PlainCredentials(
            self.config['rabbitmq']['username'],
            self.config['rabbitmq']['password'])
        connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=self.config['rabbitmq']['hostname'],
                                      port=self.config['rabbitmq']['port'],
                                      virtual_host='/',
                                      credentials=credentials))
        channel = connection.channel()
        channel.exchange_declare(exchange='opencti',
                                 exchange_type='topic',
                                 durable=True)
        channel.basic_publish('opencti', 'import.stix2.bundle',
                              json.dumps(message))
        connection.close()

    def init_connectors(self):
        self.logger.log('Configuring connectors')
        connectors = self.opencti.get_connectors()
        for connector in connectors:
            try:
                if connector['config'] is not None:
                    connector_config = json.loads(
                        base64.b64decode(connector['config']))
                    config = self.config

                    # First time, load code, create instance
                    if connector['identifier'] not in self.connectors:
                        config[connector['identifier']] = connector_config
                        connector_module = importlib.import_module(
                            'connectors.' + connector['identifier'] + '.' +
                            connector['identifier'])
                        connector_class = getattr(
                            connector_module,
                            connector['identifier'].capitalize())
                        self.connectors[connector['identifier']] = {
                            "config": config,
                            "instance": connector_class(config, self)
                        }
                        self.logger.log('Connector ' +
                                        connector['identifier'] +
                                        ' initialized')
                        self.schedule_connectors()
                    # Code is already there, just reconfigure
                    else:
                        # If cron changed, reschedule
                        current_config = self.connectors[
                            connector['identifier']]['instance'].get_config()
                        if connector_config['cron'] != current_config['cron']:
                            self.logger.log('Connector ' +
                                            connector['identifier'] +
                                            ' has to be rescheduled')
                            self.schedule_connectors()

                        # Reconfigure
                        config[connector['identifier']] = connector_config
                        self.connectors[connector['identifier']][
                            'instance'].set_config(config)
                        self.connectors[
                            connector['identifier']]['config'] = config
                        self.logger.log('Connector ' +
                                        connector['identifier'] +
                                        ' configured')

                    # Manual trigger of the connector
                    if 'triggered' in connector_config and connector_config[
                            'triggered'] is True:
                        connector_config['triggered'] = False
                        self.opencti.update_connector_config(
                            connector['identifier'], connector_config)
                        self.run_connector(connector['identifier'])
            except Exception as e:
                self.logger.log('Unable to initialize ' +
                                connector['identifier'] + ': {' + str(e) + '}')

    def run_connector(self, identifier):
        try:
            if 'active' in self.connectors[identifier]['config'][
                    identifier] and self.connectors[identifier]['config'][
                        identifier]['active'] is True:
                self.logger.log('Running ' + identifier)
                self.connectors[identifier]['instance'].run()
        except Exception as e:
            self.logger.log('Unable to run ' + identifier + ': {' + str(e) +
                            '}')

    def schedule_connectors(self):
        schedule.clear()
        self.logger.log('Scheduling connectors')
        schedule.every(1).minutes.do(self.init_connectors)
        for identifier, connector in self.connectors.items():
            connector_config = connector['instance'].get_config()
            if connector_config['cron'] == 'realtime':
                schedule.every(1).minutes.do(self.run_connector,
                                             identifier=identifier)
            elif connector_config['cron'] == 'hourly':
                schedule.every(1).hours.do(self.run_connector,
                                           identifier=identifier)
            elif connector_config['cron'] == 'daily':
                schedule.every().day.at("02:30").do(self.run_connector,
                                                    identifier=identifier)
            elif connector_config['cron'] == 'weekly':
                schedule.every().wednesday.at("04:30").do(
                    self.run_connector, identifier=identifier)
            elif connector_config['cron'] == 'monthly':
                schedule.every(30).day.at("04:30").do(self.run_connector,
                                                      identifier=identifier)

    def run(self):
        while True:
            schedule.run_pending()
            time.sleep(1)

    def init(self):
        self.init_connectors()
        self.schedule_connectors()
        self.run()
Exemplo n.º 10
0
class WorkerExport:
    def __init__(self, verbose=True):
        # Initialize logger
        self.logger = Logger(
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log')

        # Load configuration
        self.config = yaml.load(
            open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/logs/worker.log',
            self.config['opencti']['verbose'])

    def export_action(self, ch, method, properties, body):
        try:
            data = json.loads(body)
            self.logger.log('Receiving new action of type: { ' + data['type'] +
                            ' }')
            bundle = None
            if data['type'] == 'export.stix2.simple':
                bundle = self.opencti.stix2_export_entity(
                    data['entity_type'], data['entity_id'], 'simple')
            if data["type"] == 'export.stix2.full':
                bundle = self.opencti.stix2_export_entity(
                    data['entity_type'], data['entity_id'], 'full')

            if bundle is not None:
                bundle = base64.b64encode(
                    bytes(json.dumps(bundle, indent=4),
                          'utf-8')).decode('utf-8')
                self.opencti.push_stix_domain_entity_export(
                    data['entity_id'], data['export_id'], bundle)
        except Exception as e:
            self.logger.log('An unexpected error occurred: { ' + str(e) + ' }')
            return False

    def consume(self):
        # Initialize the RabbitMQ connection
        credentials = pika.PlainCredentials(
            self.config['rabbitmq']['username'],
            self.config['rabbitmq']['password'])
        connection = pika.BlockingConnection(
            pika.ConnectionParameters(host=self.config['rabbitmq']['hostname'],
                                      port=self.config['rabbitmq']['port'],
                                      virtual_host='/',
                                      credentials=credentials))
        channel = connection.channel()
        channel.exchange_declare(exchange='opencti',
                                 exchange_type='topic',
                                 durable=True)
        channel.queue_declare('opencti-export', durable=True)
        channel.queue_bind(exchange='opencti',
                           queue='opencti-export',
                           routing_key='export.*.*')
        channel.basic_consume(queue='opencti-export',
                              on_message_callback=self.export_action,
                              auto_ack=True)
        channel.start_consuming()
Exemplo n.º 11
0
class ConnectorsScheduler:
    def __init__(self, verbose=True):

        # Initialize connectors object
        self.connectors = {}

        # Initialize logger
        self.logger = Logger(os.path.dirname(os.path.abspath(__file__)) + '/scheduler.log')

        # Load configuration
        self.config = yaml.load(open(os.path.dirname(os.path.abspath(__file__)) + '/config.yml'))

        # Initialize OpenCTI client
        self.opencti = OpenCTI(
            self.config['opencti']['api_url'],
            self.config['opencti']['api_key'],
            os.path.dirname(os.path.abspath(__file__)) + '/scheduler.log',
            self.config['opencti']['verbose']
        )

    def init_connectors(self):
        self.logger.log('Configuring connectors')
        connectors = self.opencti.get_connectors()
        for connector in connectors:
            if connector['config'] is not None:
                connector_config = json.loads(base64.b64decode(connector['config']))
                config = self.config
                config[connector['identifier']] = connector_config

                if connector['identifier'] not in self.connectors:
                    connector_module = importlib.import_module('connectors.' + connector['identifier'] + '.' + connector['identifier'])
                    connector_class = getattr(connector_module, connector['identifier'].capitalize())
                    self.connectors[connector['identifier']] = {"config": config, "instance": connector_class(config)}
                    self.logger.log('Connector ' + connector['identifier'] + ' initialized')
                else:
                    self.connectors[connector['identifier']]['instance'].set_config(config)
                    self.connectors[connector['identifier']]['config'] = config
                    self.logger.log('Connector ' + connector['identifier'] + ' configured')

                if 'triggered' in connector_config and connector_config['triggered'] is True:
                    connector_config['triggered'] = False
                    self.opencti.update_connector_config(connector['identifier'], connector_config)
                    self.run_connector(connector['identifier'])

    def run_connector(self, identifier):
        try:
            if 'active' in self.connectors[identifier]['config'][identifier] and self.connectors[identifier]['config'][identifier]['active'] is True:
                self.logger.log('Running ' + identifier)
                self.connectors[identifier]['instance'].run()
        except Exception as e:
            self.logger.log('Unable to run ' + identifier + ': {' + str(e) + '}')

    def run_connectors(self):
        self.logger.log('Starting connectors')
        schedule.every(1).minutes.do(self.init_connectors)
        for identifier, connector in self.connectors.items():
            connector_config = connector['instance'].get_config()
            if connector_config['cron'] == 'realtime':
                schedule.every(1).minutes.do(self.run_connector, identifier=identifier)
            elif connector_config['cron'] == 'daily':
                schedule.every().day.at("02:30").do(self.run_connector, identifier=identifier)
            elif connector_config['cron'] == 'weekly':
                schedule.every().wednesday.at("04:30").do(self.run_connector, identifier=identifier)
            elif connector_config['cron'] == 'monthly':
                schedule.every(30).day.at("04:30").do(self.run_connector, identifier=identifier)
        while True:
            schedule.run_pending()
            time.sleep(1)

    def init(self):
        self.init_connectors()
        self.run_connectors()