From d12815fddb0ccf8ed131e10b96ec8c6bee1547c0 Mon Sep 17 00:00:00 2001 From: Rob D'Aveta Date: Thu, 26 Sep 2024 09:49:53 -0400 Subject: [PATCH 1/5] added domain inv endpoint --- ppp_connectors/spycloud.py | 44 +++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/ppp_connectors/spycloud.py b/ppp_connectors/spycloud.py index d12db18..136cbdc 100644 --- a/ppp_connectors/spycloud.py +++ b/ppp_connectors/spycloud.py @@ -141,7 +141,7 @@ def spycloud_ato_phone_number(phone_number:str, **kwargs: Dict[str, Any]) -> Res search for the sha1, sha256, or sha512 hash of the phone number. Returns: - Response: requests.Respone json response from the request + Response: requests.Response json response from the request """ # Define required environment variables @@ -165,6 +165,16 @@ def spycloud_ato_phone_number(phone_number:str, **kwargs: Dict[str, Any]) -> Res return result def spycloud_ato_breach_catalog(query:str, **kwargs: Dict[str, Any]) -> Response: + """List or Query the Breach Catalog + + + Args: + query (str): Query value to search the breach catalog for. + + + Returns: + Response: requests.Response json response from the request + """ # Define required environment variables required_vars: List[str] = [ @@ -187,4 +197,36 @@ def spycloud_ato_breach_catalog(query:str, **kwargs: Dict[str, Any]) -> Response result: Response = make_request(method=method, url=url, headers=headers, params=params) + return result + +def spycloud_inv_domains(domain:str, **kwargs: Dict[str, Any]) -> Response: + """Get Domain Breach Data + + + Args: + domain (str): Domain name to search for. You can also search for the sha1, sha256, or + sha512 hash of the domain. + + Returns: + Response: requests.Response json response from the request + """ + + # Define required environment variables + required_vars: List[str] = [ + 'SPYCLOUD_API_INV_KEY' + ] + + # Check and ensure that required variables are present, exits if not + check_required_env_vars(env_config, required_vars) + + method: str = 'get' + url: str = f'https://api.spycloud.io/investigations-v2/breach/data/domains/{domain}' + headers: Dict = { + 'accept': 'application/json', + 'x-api-key': env_config['SPYCLOUD_API_ATO_KEY'] + } + params: Dict = dict(kwargs) + + result: Response = make_request(method=method, url=url, headers=headers, params=params) + return result \ No newline at end of file From daea9b3c4da7c5b22ff231caef6f020cf67f27f6 Mon Sep 17 00:00:00 2001 From: Rob D'Aveta Date: Thu, 26 Sep 2024 10:12:05 -0400 Subject: [PATCH 2/5] fixed typo --- ppp_connectors/spycloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppp_connectors/spycloud.py b/ppp_connectors/spycloud.py index 136cbdc..0259be3 100644 --- a/ppp_connectors/spycloud.py +++ b/ppp_connectors/spycloud.py @@ -223,7 +223,7 @@ def spycloud_inv_domains(domain:str, **kwargs: Dict[str, Any]) -> Response: url: str = f'https://api.spycloud.io/investigations-v2/breach/data/domains/{domain}' headers: Dict = { 'accept': 'application/json', - 'x-api-key': env_config['SPYCLOUD_API_ATO_KEY'] + 'x-api-key': env_config['SPYCLOUD_API_INV_KEY'] } params: Dict = dict(kwargs) From bf299ae826bcafe5fa1ecce88ca3a8fa9f9d58cd Mon Sep 17 00:00:00 2001 From: Rob D'Aveta Date: Thu, 26 Sep 2024 13:36:36 -0400 Subject: [PATCH 3/5] condense investigations functions into one function because i am all that is man --- ppp_connectors/spycloud.py | 47 +++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/ppp_connectors/spycloud.py b/ppp_connectors/spycloud.py index 0259be3..e262db1 100644 --- a/ppp_connectors/spycloud.py +++ b/ppp_connectors/spycloud.py @@ -1,5 +1,6 @@ from typing import Dict, Any, List from requests import Response +import sys from .broker import make_request from .helpers import check_required_env_vars, combine_env_configs @@ -199,17 +200,7 @@ def spycloud_ato_breach_catalog(query:str, **kwargs: Dict[str, Any]) -> Response return result -def spycloud_inv_domains(domain:str, **kwargs: Dict[str, Any]) -> Response: - """Get Domain Breach Data - - - Args: - domain (str): Domain name to search for. You can also search for the sha1, sha256, or - sha512 hash of the domain. - - Returns: - Response: requests.Response json response from the request - """ +def spycloud_inv_search(search_type: str, query:str, **kwargs: Dict[str, Any]) -> Response: # Define required environment variables required_vars: List[str] = [ @@ -219,8 +210,37 @@ def spycloud_inv_domains(domain:str, **kwargs: Dict[str, Any]) -> Response: # Check and ensure that required variables are present, exits if not check_required_env_vars(env_config, required_vars) + # These are valid endpoints and their corresponding full URLs. We'll use these + # to check that the user passed a valid 'search_type' parameter + base_url: str = 'https://api.spycloud.io/investigations-v2/breach/data' + valid_endpoints: Dict[str, str] = { + 'domain': f'{base_url}/domains', + 'email': f'{base_url}/emails', + 'ip': f'{base_url}/ips', + 'infected-machine-id': f'{base_url}/infected-machine-ids', + 'log-id': f'{base_url}/log-ids', + 'password': f'{base_url}/passwords', + 'username': f'{base_url}/usernames', + 'email-username': f'{base_url}/email-usernames', + 'phone-number': f'{base_url}/phone-numbers', + 'social-handle': f'{base_url}/social-handles', + 'bank-number': f'{base_url}/bank-numbers', + 'cc-number': f'{base_url}/cc-numbers', + 'drivers-license': f'{base_url}/drivers-licenses', + 'national-id': f'{base_url}/national-ids', + 'passport-number': f'{base_url}/passport-numbers', + 'ssn': f'{base_url}/social-security-numbers', + } + + # Completely exit if they supply an invalid search_type + if search_type not in valid_endpoints: + print(f'[!] Error: {search_type} is not a valid search type. Must be one of ' + f'{", ".join(valid_endpoints.keys())}', file=sys.stderr) + sys.exit(1) + method: str = 'get' - url: str = f'https://api.spycloud.io/investigations-v2/breach/data/domains/{domain}' + url: str = f'{valid_endpoints[search_type]}/{query}' + headers: Dict = { 'accept': 'application/json', 'x-api-key': env_config['SPYCLOUD_API_INV_KEY'] @@ -229,4 +249,5 @@ def spycloud_inv_domains(domain:str, **kwargs: Dict[str, Any]) -> Response: result: Response = make_request(method=method, url=url, headers=headers, params=params) - return result \ No newline at end of file + return result + From f5e8e2718afb6438bcd63a775e3047ecdc8a7dc2 Mon Sep 17 00:00:00 2001 From: Rob D'Aveta Date: Thu, 26 Sep 2024 13:40:34 -0400 Subject: [PATCH 4/5] updated error message --- ppp_connectors/spycloud.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ppp_connectors/spycloud.py b/ppp_connectors/spycloud.py index e262db1..15ec503 100644 --- a/ppp_connectors/spycloud.py +++ b/ppp_connectors/spycloud.py @@ -234,7 +234,7 @@ def spycloud_inv_search(search_type: str, query:str, **kwargs: Dict[str, Any]) - # Completely exit if they supply an invalid search_type if search_type not in valid_endpoints: - print(f'[!] Error: {search_type} is not a valid search type. Must be one of ' + print(f'[!] Error: "{search_type}" is not a valid search type. Must be one of ' f'{", ".join(valid_endpoints.keys())}', file=sys.stderr) sys.exit(1) @@ -249,5 +249,4 @@ def spycloud_inv_search(search_type: str, query:str, **kwargs: Dict[str, Any]) - result: Response = make_request(method=method, url=url, headers=headers, params=params) - return result - + return result \ No newline at end of file From 3084ddd5cc236d28c98460965e77ae160d90200e Mon Sep 17 00:00:00 2001 From: Rob D'Aveta Date: Thu, 26 Sep 2024 13:42:59 -0400 Subject: [PATCH 5/5] bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f43bd7..ea20ab7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "ppp-connectors" packages = [{ include = "ppp_connectors" }] -version = "0.3.0" +version = "0.3.1" description = "A simple, lightweight set of connectors and functions to various APIs, controlled by a central broker." authors = [ "Rob D'Aveta ",