diff --git a/api_client.py b/api_client.py index 638307c..5949d91 100644 --- a/api_client.py +++ b/api_client.py @@ -160,6 +160,7 @@ def add_siem_logeer_handler(self, logdir): logging_handler = logging.FileHandler( os.path.join(logdir, self.config.filename), "a", encoding="utf-8" ) + logging_handler.append_nul = self.config.append_nul == "true" SIEM_LOGGER.addHandler(logging_handler) def get_past_datetime(self, hours): @@ -263,7 +264,7 @@ def call_endpoint(self, api_host, default_headers, args): events = json.loads(events_response) return events - def get_alerts_or_events_req_args(self, params): + def get_alerts_or_events_req_args(self, params, endpoint_name): """Convert the params to query string Arguments: params {dict}: params object @@ -281,6 +282,7 @@ def get_alerts_or_events_req_args(self, params): ) else: args = "&".join(["%s=%s" % (k, v) for k, v in params.items()]) + args+='&from_date_offset_minutes='+str(self.config.events_from_date_offset_minutes if endpoint_name=="events" else self.config.alerts_from_date_offset_minutes) return args def make_token_request(self, endpoint_name, token): @@ -315,7 +317,7 @@ def make_token_request(self, endpoint_name, token): while True: - args = self.get_alerts_or_events_req_args(params) + args = self.get_alerts_or_events_req_args(params, endpoint_name) events = self.call_endpoint(token.url, default_headers, args) if "items" in events and len(events["items"]) > 0: @@ -363,7 +365,7 @@ def make_credentials_request(self, endpoint_name, tenant_obj): while True: - args = self.get_alerts_or_events_req_args(params) + args = self.get_alerts_or_events_req_args(params, endpoint_name) data_region_url = tenant_obj["apiHost"] if "idType" not in tenant_obj else tenant_obj["apiHosts"]["dataRegion"] events = self.call_endpoint(data_region_url, default_headers, args) if "items" in events and len(events["items"]) > 0: diff --git a/config.ini b/config.ini index 45957c5..bb7ad0b 100755 --- a/config.ini +++ b/config.ini @@ -33,6 +33,14 @@ endpoint = event address = /var/run/syslog facility = daemon socktype = udp +append_nul = false # cache file full or relative path (with a ".json" extension) -state_file_path = state/siem_sophos.json \ No newline at end of file +state_file_path = state/siem_sophos.json + +# Delay the data collection by X minute to avoid events missing issue from Sophos API +# The issue could be due to some specific host being ahead in time for a few minute and Sophos Central would consider events received from that host as a checkpoint. +events_from_date_offset_minutes = 0 + +# Delay the data collection by X minute. +alerts_from_date_offset_minutes = 0 \ No newline at end of file diff --git a/tests/unit/test_api_client.py b/tests/unit/test_api_client.py index 956b2e5..0541575 100644 --- a/tests/unit/test_api_client.py +++ b/tests/unit/test_api_client.py @@ -55,6 +55,9 @@ def __init__(self): self.token_info = "" self.auth_url = "" self.api_host = "" + self.append_nul = False + self.events_from_date_offset_minutes = 0 + self.alerts_from_date_offset_minutes = 0 class TestApiClient(unittest.TestCase): @@ -220,14 +223,17 @@ def test_request_url(self, mock_urlrequest): def test_get_alerts_or_events_req_args(self): self.api_client.options.light = True params = {"limit": 1000, "cursor": False} - response = self.api_client.get_alerts_or_events_req_args(params) + response = self.api_client.get_alerts_or_events_req_args(params, "events") self.assertIn( "limit=1000&cursor=False&exclude_types=Event::Endpoint::NonCompliant", response, ) self.api_client.options.light = False - response = self.api_client.get_alerts_or_events_req_args(params) - self.assertEqual(response, "limit=1000&cursor=False") + response = self.api_client.get_alerts_or_events_req_args(params, "events") + self.assertEqual(response, "limit=1000&cursor=False&from_date_offset_minutes=0") + + response = self.api_client.get_alerts_or_events_req_args(params, "alerts") + self.assertEqual(response, "limit=1000&cursor=False&from_date_offset_minutes=0") def test_make_token_request(self): mock_response = {