diff --git a/CHANGES b/CHANGES index fd35d6c..bb9bdbd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +1.25.1 +------- +- Make request method kwargs only and add params + 1.25.0 ------- - Add support for Python 3.14 diff --git a/intezer_sdk/__init__.py b/intezer_sdk/__init__.py index 8de33c0..760870c 100644 --- a/intezer_sdk/__init__.py +++ b/intezer_sdk/__init__.py @@ -1 +1 @@ -__version__ = '1.25.0' +__version__ = '1.25.1' diff --git a/intezer_sdk/_account_api.py b/intezer_sdk/_account_api.py index 67b8abd..d31892d 100644 --- a/intezer_sdk/_account_api.py +++ b/intezer_sdk/_account_api.py @@ -11,7 +11,7 @@ def __init__(self, api: IntezerApiClient | None): self.api = api or get_global_api() def get_my_quota(self, raise_on_no_file_quota=False, raise_on_no_endpoint_quota=False) -> dict: - response = self.api.request_with_refresh_expired_access_token('GET', '/current-quota-usage') + response = self.api.request_with_refresh_expired_access_token(method='GET', path='/current-quota-usage') raise_for_status(response) result = response.json()['result'] if raise_on_no_file_quota and result['file_scans']['quota'] - result['file_scans']['usage'] <= 0: @@ -21,12 +21,12 @@ def get_my_quota(self, raise_on_no_file_quota=False, raise_on_no_endpoint_quota= return result def get_my_account(self) -> dict: - response = self.api.request_with_refresh_expired_access_token('GET', '/accounts/me') + response = self.api.request_with_refresh_expired_access_token(method='GET', path='/accounts/me') raise_for_status(response) return response.json()['result'] def get_account(self, account_id: str) -> dict | None: - response = self.api.request_with_refresh_expired_access_token('GET', f'/accounts/{account_id}') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/accounts/{account_id}') if response.status_code == HTTPStatus.NOT_FOUND: return None @@ -34,6 +34,6 @@ def get_account(self, account_id: str) -> dict | None: return response.json()['result'] def get_organization_accounts(self) -> list[dict]: - response = self.api.request_with_refresh_expired_access_token('GET', f'/accounts') + response = self.api.request_with_refresh_expired_access_token(method='GET', path='/accounts') raise_for_status(response) return response.json()['result'] diff --git a/intezer_sdk/_api.py b/intezer_sdk/_api.py index 799efcf..14d07f1 100644 --- a/intezer_sdk/_api.py +++ b/intezer_sdk/_api.py @@ -56,7 +56,7 @@ def analyze_by_hash(self, data['file_name'] = file_name data['hash'] = file_hash - response = self.api.request_with_refresh_expired_access_token('POST', '/analyze-by-hash', data) + response = self.api.request_with_refresh_expired_access_token(method='POST', path='/analyze-by-hash', data=data) self._assert_analysis_response_status_code(response) return self._get_analysis_id_from_response(response) @@ -92,7 +92,7 @@ def analyze_by_download_url(self, **additional_parameters) data['download_url'] = download_url - response = self.api.request_with_refresh_expired_access_token('POST', '/analyze-by-url', data) + response = self.api.request_with_refresh_expired_access_token(method='POST', path='/analyze-by-url', data=data) self._assert_analysis_response_status_code(response) return self._get_analysis_id_from_response(response) @@ -108,7 +108,7 @@ def _analyze_file_stream(self, file_stream: BinaryIO, file_name: str, options: d """ file = {'file': (file_name, file_stream)} - response = self.api.request_with_refresh_expired_access_token('POST', '/analyze', options, files=file) + response = self.api.request_with_refresh_expired_access_token(method='POST', path='/analyze', data=options, files=file) self._assert_analysis_response_status_code(response) return self._get_analysis_id_from_response(response) @@ -175,7 +175,7 @@ def get_latest_analysis(self, self.api.on_premise_version > OnPremiseVersion.V22_10)): options['should_get_only_composed_analysis'] = composed_only - response = self.api.request_with_refresh_expired_access_token('GET', f'/files/{file_hash}', options) + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/files/{file_hash}', data=options) if response.status_code == HTTPStatus.NOT_FOUND: return None @@ -192,7 +192,7 @@ def get_file_analysis_response(self, analyses_id: str, ignore_not_found: bool) - :param ignore_not_found: Whether to ignore not found errors. :return: The analysis response. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/analyses/{analyses_id}') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/analyses/{analyses_id}') self._assert_result_response(ignore_not_found, response) return response @@ -209,7 +209,7 @@ def get_url_analysis_response(self, analyses_id: str, ignore_not_found: bool) -> :param ignore_not_found: Whether to ignore not found errors. :return: The analysis response. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/url/{analyses_id}') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/url/{analyses_id}') self._assert_result_response(ignore_not_found, response) return response @@ -222,7 +222,7 @@ def get_endpoint_analysis_response(self, analyses_id: str, ignore_not_found: boo :param ignore_not_found: Whether to ignore not found errors. :return: The analysis response. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/endpoint-analyses/{analyses_id}') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/endpoint-analyses/{analyses_id}') self._assert_result_response(ignore_not_found, response) return response @@ -237,9 +237,9 @@ def get_endpoint_sub_analyses(self, analyses_id: str, verdicts: list[str] | None """ data = dict(verdicts=verdicts) if verdicts is not None else None response = self.api.request_with_refresh_expired_access_token( - 'GET', - f'/endpoint-analyses/{analyses_id}/sub-analyses', - data + method='GET', + path=f'/endpoint-analyses/{analyses_id}/sub-analyses', + data=data ) self._assert_result_response(False, response) @@ -254,9 +254,9 @@ def create_endpoint_scan(self, scanner_info: dict) -> dict[str, str]: """ if not self.api.on_premise_version or self.api.on_premise_version > OnPremiseVersion.V22_10: scanner_info['scan_type'] = consts.SCAN_TYPE_OFFLINE_ENDPOINT_SCAN - response = self.api.request_with_refresh_expired_access_token('POST', - 'scans', - scanner_info, + response = self.api.request_with_refresh_expired_access_token(method='POST', + path='scans', + data=scanner_info, base_url=self.api.base_url) raise_for_status(response) @@ -294,7 +294,7 @@ def get_iocs(self, analyses_id: str) -> dict | None: :param analyses_id: The id of the analysis to get the IOCs of. :return: The IOCs. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/analyses/{analyses_id}/iocs') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/analyses/{analyses_id}/iocs') raise_for_status(response) return response.json()['result'] @@ -306,7 +306,7 @@ def get_detection_result_url(self, analyses_id: str) -> str | None: :param analyses_id: The id of the analysis to get the detection result url of. :return: The detection result url. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/analyses/{analyses_id}/detect') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/analyses/{analyses_id}/detect') if response.status_code == HTTPStatus.CONFLICT: return None raise_for_status(response) @@ -321,8 +321,8 @@ def get_dynamic_ttps(self, analyses_id: str) -> dict | None: :return: The dynamic TTPs. """ self.assert_on_premise_above_v21_11() - response = self.api.request_with_refresh_expired_access_token('GET', - f'/analyses/{analyses_id}/dynamic-ttps') + response = self.api.request_with_refresh_expired_access_token(method='GET', + path=f'/analyses/{analyses_id}/dynamic-ttps') raise_for_status(response) return response.json()['result'] @@ -334,7 +334,7 @@ def get_family_info(self, family_id: str) -> dict | None: :param family_id: The id of the family to get the info of. :return: The family info. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/families/{family_id}/info') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/families/{family_id}/info') if response.status_code == HTTPStatus.NOT_FOUND: return None @@ -348,9 +348,9 @@ def get_family_by_name(self, family_name: str) -> dict[str, Any] | None: :param family_name: The name of the family to get. :return: The family. """ - response = self.api.request_with_refresh_expired_access_token('GET', - '/families', - {'family_name': family_name}) + response = self.api.request_with_refresh_expired_access_token(method='GET', + path='/families', + data={'family_name': family_name}) if response.status_code == HTTPStatus.NOT_FOUND: return None @@ -365,7 +365,7 @@ def get_sub_analyses_by_id(self, analysis_id: str) -> list[dict] | None: :return: The sub analyses. """ response = self.api.request_with_refresh_expired_access_token( - 'GET', f'/analyses/{analysis_id}/sub-analyses' + method='GET', path=f'/analyses/{analysis_id}/sub-analyses' ) raise_for_status(response) @@ -382,7 +382,7 @@ def get_sub_analysis_code_reuse_by_id(self, :return: The code reuse sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'GET', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/code-reuse', + method='GET', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/code-reuse', ) if response.status_code == HTTPStatus.CONFLICT: @@ -401,7 +401,7 @@ def get_sub_analysis_metadata_by_id(self, composed_analysis_id: str, sub_analysi :return: The metadata of the sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'GET', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/metadata' + method='GET', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/metadata' ) raise_for_status(response) @@ -420,8 +420,8 @@ def get_sub_analysis_related_files_by_family_id(self, :return: The related files of the sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'POST', - f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/code-reuse/families/{family_id}/find-related-files' + method='POST', + path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/code-reuse/families/{family_id}/find-related-files' ) raise_for_status(response) @@ -437,7 +437,7 @@ def get_sub_analysis_account_related_samples_by_id(self, composed_analysis_id: s :return: The account related samples of the sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'POST', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/get-account-related-samples' + method='POST', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/get-account-related-samples' ) raise_for_status(response) @@ -454,7 +454,7 @@ def get_sub_analysis_capabilities_by_id(self, composed_analysis_id: str, sub_ana """ self.assert_on_premise_above_v21_11() response = self.api.request_with_refresh_expired_access_token( - 'POST', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/capabilities', + method='POST', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/capabilities', ) raise_for_status(response) @@ -470,7 +470,7 @@ def generate_sub_analysis_vaccine_by_id(self, composed_analysis_id: str, sub_ana :return: The vaccine of the sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'POST', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/generate-vaccine') + method='POST', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/generate-vaccine') raise_for_status(response) @@ -485,7 +485,7 @@ def get_strings_by_id(self, composed_analysis_id: str, sub_analysis_id: str) -> :return: The strings of the sub analysis. """ response = self.api.request_with_refresh_expired_access_token( - 'POST', f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/strings' + method='POST', path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/strings' ) raise_for_status(response) @@ -497,9 +497,9 @@ def get_string_related_samples_by_id(self, sub_analysis_id: str, string_value: str) -> str: response = self.api.request_with_refresh_expired_access_token( - 'POST', - f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/string-related-samples', - {'string_value': string_value} + method='POST', + path=f'/analyses/{composed_analysis_id}/sub-analyses/{sub_analysis_id}/string-related-samples', + data={'string_value': string_value} ) raise_for_status(response) @@ -508,7 +508,7 @@ def get_string_related_samples_by_id(self, def get_code_reuse_by_code_block(self, sha256: str): response = self.api.request_with_refresh_expired_access_token( - 'POST', f'/files/{sha256}/code-reuse-by-code-block' + method='POST', path=f'/files/{sha256}/code-reuse-by-code-block' ) if response.status_code == HTTPStatus.NOT_FOUND: @@ -527,7 +527,7 @@ def get_url_result(self, url: str) -> dict: :param url: The url to get the result of. :return: The response data from the url. """ - response = self.api.request_with_refresh_expired_access_token('GET', url) + response = self.api.request_with_refresh_expired_access_token(method='GET', path=url) raise_for_status(response) result = response.json() @@ -564,8 +564,8 @@ def download_file_by_sha256(self, json_data = {'password_protected': password_protected} if password_protected else None - response = self.api.request_with_refresh_expired_access_token('GET', - f'/files/{sha256}/download', + response = self.api.request_with_refresh_expired_access_token(method='GET', + path=f'/files/{sha256}/download', stream=bool(path), data=json_data) @@ -635,7 +635,7 @@ def index_by_sha256(self, sha256: str, index_as: IndexType, family_name: str = N if family_name: data['family_name'] = family_name - response = self.api.request_with_refresh_expired_access_token('POST', f'/files/{sha256}/index', data) + response = self.api.request_with_refresh_expired_access_token(method='POST', path=f'/files/{sha256}/index', data=data) self._assert_index_response_status_code(response) return self._get_index_id_from_response(response) @@ -646,7 +646,7 @@ def unset_index_by_sha256(self, sha256: str): :param sha256: The sha256 hash of the file """ - response = self.api.request_with_refresh_expired_access_token('DELETE', f'/files/{sha256}/index') + response = self.api.request_with_refresh_expired_access_token(method='DELETE', path=f'/files/{sha256}/index') if response.status_code == HTTPStatus.NOT_FOUND: raise errors.HashDoesNotExistError(response) raise_for_status(response) @@ -667,9 +667,9 @@ def index_by_file(self, file_path: str, index_as: IndexType, family_name: str = with open(file_path, 'rb') as file_to_upload: file = {'file': (os.path.basename(file_path), file_to_upload)} - response = self.api.request_with_refresh_expired_access_token('POST', - '/files/index', - data, + response = self.api.request_with_refresh_expired_access_token(method='POST', + path='/files/index', + data=data, files=file) self._assert_index_response_status_code(response) @@ -778,7 +778,7 @@ def get_index_response(self, index_id: str) -> Response: :param index_id: The id of the index. :return: The index response. """ - response = self.api.request_with_refresh_expired_access_token('GET', f'/files/index/{index_id}') + response = self.api.request_with_refresh_expired_access_token(method='GET', path=f'/files/index/{index_id}') raise_for_status(response) return response @@ -792,9 +792,9 @@ def analyze_url(self, url: str, **additional_parameters) -> str | None: :return: The analysis id. """ self.assert_any_on_premise('analyze-url') - response = self.api.request_with_refresh_expired_access_token('POST', - '/url', - dict(url=url, **additional_parameters)) + response = self.api.request_with_refresh_expired_access_token(method='POST', + path='/url', + data=dict(url=url, **additional_parameters)) self._assert_analysis_response_status_code(response) return self._get_analysis_id_from_response(response) diff --git a/intezer_sdk/_endpoint_analysis_api.py b/intezer_sdk/_endpoint_analysis_api.py index ee60fb3..0689f9f 100644 --- a/intezer_sdk/_endpoint_analysis_api.py +++ b/intezer_sdk/_endpoint_analysis_api.py @@ -17,8 +17,8 @@ def __init__(self, scan_id: str, api: IntezerApiClient, max_upload_retries: int self.base_url = f"{api.base_url.replace('/api/', '')}/scans/scans/{scan_id}" self.max_upload_retries = max_upload_retries - def request_with_refresh_expired_access_token(self, *args, **kwargs): - return self.api.request_with_refresh_expired_access_token(base_url=self.base_url, *args, **kwargs) + def request_with_refresh_expired_access_token(self, **kwargs): + return self.api.request_with_refresh_expired_access_token(base_url=self.base_url, **kwargs) def send_host_info(self, host_info: dict): response = self.request_with_refresh_expired_access_token(path='/host-info', diff --git a/intezer_sdk/api.py b/intezer_sdk/api.py index 681f99b..de327c0 100644 --- a/intezer_sdk/api.py +++ b/intezer_sdk/api.py @@ -96,9 +96,11 @@ def __init__(self, self.user_agent = user_agent def _request(self, + *, method: str, path: str, data: dict = None, + params: dict = None, headers: dict = None, files: dict = None, stream: bool = None, @@ -115,6 +117,7 @@ def _request(self, url, files=files, data=data or {}, + params=params, headers=headers or {}, stream=stream, timeout=timeout_in_seconds or self.timeout_in_seconds @@ -125,6 +128,7 @@ def _request(self, url, files=files, data=data, + params=params, headers=headers or {}, stream=stream, timeout=timeout_in_seconds or self.timeout_in_seconds @@ -134,6 +138,7 @@ def _request(self, method, url, json=data or {}, + params=params, headers=headers, stream=stream, timeout=timeout_in_seconds or self.timeout_in_seconds @@ -148,9 +153,11 @@ def _refresh_token_if_needed(self): self._set_access_token() def request_with_refresh_expired_access_token(self, + *, method: str, path: str, data: dict = None, + params: dict = None, headers: dict = None, files: dict = None, stream: bool = None, @@ -159,11 +166,11 @@ def request_with_refresh_expired_access_token(self, for retry_count in range(self.max_retry): try: self._refresh_token_if_needed() - response = self._request(method, path, data, headers, files, stream, base_url, timeout_in_seconds) + response = self._request(method=method, path=path, data=data, params=params, headers=headers, files=files, stream=stream, base_url=base_url, timeout_in_seconds=timeout_in_seconds) if response.status_code == HTTPStatus.UNAUTHORIZED: self._set_access_token() - response = self._request(method, path, data, headers, files, stream, base_url, timeout_in_seconds) + response = self._request(method=method, path=path, data=data, params=params, headers=headers, files=files, stream=stream, base_url=base_url, timeout_in_seconds=timeout_in_seconds) return response except ConnectionError: @@ -427,7 +434,7 @@ def get_dynamic_ttps(self, analyses_id: str) -> dict | None: @deprecated('IntezerApi is deprecated and will be removed in the future') def get_family_info(self, family_id: str) -> dict | None: - response = self.request_with_refresh_expired_access_token('GET', '/families/{}/info'.format(family_id)) + response = self.request_with_refresh_expired_access_token(method='GET', path='/families/{}/info'.format(family_id)) if response.status_code == HTTPStatus.NOT_FOUND: return None @@ -436,7 +443,7 @@ def get_family_info(self, family_id: str) -> dict | None: @deprecated('IntezerApi is deprecated and will be removed in the future') def get_family_by_name(self, family_name: str) -> dict[str, Any] | None: - response = self.request_with_refresh_expired_access_token('GET', '/families', {'family_name': family_name}) + response = self.request_with_refresh_expired_access_token(method='GET', path='/families', data={'family_name': family_name}) if response.status_code == HTTPStatus.NOT_FOUND: return None diff --git a/tests/unit/base_test.py b/tests/unit/base_test.py index 91b976e..890617e 100644 --- a/tests/unit/base_test.py +++ b/tests/unit/base_test.py @@ -43,7 +43,7 @@ def test_renew_token(self): mock.add('POST', url=f'{self.full_url}/some-route', status=HTTPStatus.OK) - response = api.request_with_refresh_expired_access_token('POST', '/some-route') + response = api.request_with_refresh_expired_access_token(method='POST', path='/some-route') response.raise_for_status() time.sleep(0.2) mock.reset() @@ -55,7 +55,7 @@ def test_renew_token(self): status=HTTPStatus.OK, json={'result': 'access-token', 'expire_at': time.time()}) - response = api.request_with_refresh_expired_access_token('POST', '/some-route') + response = api.request_with_refresh_expired_access_token(method='POST', path='/some-route') response.raise_for_status() def test_api_raise_insufficient_permissions_error_when_insufficient_permissions_received(self): @@ -73,7 +73,7 @@ def test_api_raise_insufficient_permissions_error_when_insufficient_permissions_ f'{self.full_url}/some-route', status=HTTPStatus.FORBIDDEN, json={'error': 'Insufficient Permissions'}) - response = api.request_with_refresh_expired_access_token('GET', '/some-route') + response = api.request_with_refresh_expired_access_token(method='GET', path='/some-route') with self.assertRaises(errors.InsufficientPermissionsError): raise_for_status(response) @@ -94,7 +94,7 @@ def test_api_raise_invalid_api_key_error_when_unauthorized_received(self): url=f'{self.full_url}/get-access-token', status=HTTPStatus.OK, json={'result': 'access-token', 'expire_at': 2166920067}) - response = api.request_with_refresh_expired_access_token('GET', '/some-route') + response = api.request_with_refresh_expired_access_token(method='GET', path='/some-route') with self.assertRaises(errors.InvalidApiKeyError): raise_for_status(response)