diff --git a/bbot/modules/censys.py b/bbot/modules/censys.py index cb8a7c956..3779363fa 100644 --- a/bbot/modules/censys.py +++ b/bbot/modules/censys.py @@ -15,25 +15,21 @@ class censys(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_id": "", "api_secret": "", "max_pages": 5} + options = {"api_key": "", "max_pages": 5} options_desc = { - "api_id": "Censys.io API ID", - "api_secret": "Censys.io API Secret", + "api_key": "Censys.io API Key in the format of 'key:secret'", "max_pages": "Maximum number of pages to fetch (100 results per page)", } base_url = "https://search.censys.io/api" async def setup(self): - self.api_id = self.config.get("api_id", "") - self.api_secret = self.config.get("api_secret", "") - self.auth = (self.api_id, self.api_secret) self.max_pages = self.config.get("max_pages", 5) return await super().setup() async def ping(self): url = f"{self.base_url}/v1/account" - resp = await self.helpers.request(url, auth=self.auth) + resp = await self.api_request(url) d = resp.json() assert isinstance(d, dict), f"Invalid response from {url}: {resp}" quota = d.get("quota", {}) @@ -41,6 +37,11 @@ async def ping(self): allowance = int(quota.get("allowance", 0)) assert used < allowance, "No quota remaining" + def prepare_api_request(self, url, kwargs): + api_id, api_secret = self.api_key.split(":", 1) + kwargs["auth"] = (api_id, api_secret) + return url, kwargs + async def query(self, query): results = set() cursor = "" @@ -52,11 +53,10 @@ async def query(self, query): } if cursor: json_data.update({"cursor": cursor}) - resp = await self.helpers.request( + resp = await self.api_request( url, method="POST", json=json_data, - auth=self.auth, ) if resp is None: @@ -96,7 +96,3 @@ async def query(self, query): break return results - - @property - def auth_secret(self): - return self.api_id and self.api_secret diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index eb895b0ea..0099d1e07 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -11,36 +11,34 @@ class passivetotal(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"username": "", "api_key": ""} - options_desc = {"username": "RiskIQ Username", "api_key": "RiskIQ API Key"} + options = {"api_key": ""} + options_desc = {"api_key": "PassiveTotal API Key in the format of 'username:api_key'"} base_url = "https://api.passivetotal.org/v2" async def setup(self): - self.username = self.config.get("username", "") - self.api_key = self.config.get("api_key", "") - self.auth = (self.username, self.api_key) return await super().setup() async def ping(self): url = f"{self.base_url}/account/quota" - j = (await self.api_request(url, auth=self.auth)).json() + j = (await self.api_request(url)).json() limit = j["user"]["limits"]["search_api"] used = j["user"]["counts"]["search_api"] assert used < limit, "No quota remaining" + def prepare_api_request(self, url, kwargs): + api_username, api_key = self.api_key.split(":", 1) + kwargs["auth"] = (api_username, api_key) + return url, kwargs + async def abort_if(self, event): # RiskIQ is famous for their junk data return await super().abort_if(event) or "unresolved" in event.tags async def request_url(self, query): url = f"{self.base_url}/enrichment/subdomains?query={self.helpers.quote(query)}" - return await self.api_request(url, auth=self.auth) + return await self.api_request(url) def parse_results(self, r, query): for subdomain in r.json().get("subdomains", []): yield f"{subdomain}.{query}" - - @property - def auth_secret(self): - return self.username and self.api_key diff --git a/bbot/test/test_step_2/module_tests/test_module_censys.py b/bbot/test/test_step_2/module_tests/test_module_censys.py index 51a2d054b..14e72921e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys.py @@ -2,11 +2,12 @@ class TestCensys(ModuleTestBase): - config_overrides = {"modules": {"censys": {"api_id": "api_id", "api_secret": "api_secret"}}} + config_overrides = {"modules": {"censys": {"api_key": "api_id:api_secret"}}} async def setup_before_prep(self, module_test): module_test.httpx_mock.add_response( url="https://search.censys.io/api/v1/account", + match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ "email": "info@blacklanternsecurity.com", "login": "nope", @@ -17,6 +18,7 @@ async def setup_before_prep(self, module_test): ) module_test.httpx_mock.add_response( url="https://search.censys.io/api/v2/certificates/search", + match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, match_content=b'{"q": "names: blacklanternsecurity.com", "per_page": 100}', json={ "code": 200, @@ -45,6 +47,7 @@ async def setup_before_prep(self, module_test): ) module_test.httpx_mock.add_response( url="https://search.censys.io/api/v2/certificates/search", + match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, match_content=b'{"q": "names: blacklanternsecurity.com", "per_page": 100, "cursor": "NextToken"}', json={ "code": 200, diff --git a/bbot/test/test_step_2/module_tests/test_module_passivetotal.py b/bbot/test/test_step_2/module_tests/test_module_passivetotal.py index 9048a41e0..55be61346 100644 --- a/bbot/test/test_step_2/module_tests/test_module_passivetotal.py +++ b/bbot/test/test_step_2/module_tests/test_module_passivetotal.py @@ -2,15 +2,17 @@ class TestPassiveTotal(ModuleTestBase): - config_overrides = {"modules": {"passivetotal": {"username": "jon@bls.fakedomain", "api_key": "asdf"}}} + config_overrides = {"modules": {"passivetotal": {"api_key": "jon@bls.fakedomain:asdf"}}} async def setup_before_prep(self, module_test): module_test.httpx_mock.add_response( url="https://api.passivetotal.org/v2/account/quota", + match_headers={"Authorization": "Basic am9uQGJscy5mYWtlZG9tYWluOmFzZGY="}, json={"user": {"counts": {"search_api": 10}, "limits": {"search_api": 20}}}, ) module_test.httpx_mock.add_response( url="https://api.passivetotal.org/v2/enrichment/subdomains?query=blacklanternsecurity.com", + match_headers={"Authorization": "Basic am9uQGJscy5mYWtlZG9tYWluOmFzZGY="}, json={"subdomains": ["asdf"]}, )