From 945da91a68d4d3dcd776128f65bb0096da333e32 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Fri, 21 Jun 2024 20:44:58 -0700 Subject: [PATCH 01/22] xsoar: initial commit --- README.md | 2 +- automon/integrations/xsoar/__init__.py | 2 + automon/integrations/xsoar/client.py | 68 +++++++++++++++++++ automon/integrations/xsoar/config.py | 41 +++++++++++ .../integrations/xsoar/endpoints/__init__.py | 0 automon/integrations/xsoar/endpoints/v1.py | 9 +++ automon/integrations/xsoar/tests/__init__.py | 0 .../xsoar/tests/test_client_auth.py | 17 +++++ .../integrations/xsoar/tests/test_config.py | 15 ++++ env-example.sh | 5 ++ 10 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 automon/integrations/xsoar/__init__.py create mode 100644 automon/integrations/xsoar/client.py create mode 100644 automon/integrations/xsoar/config.py create mode 100644 automon/integrations/xsoar/endpoints/__init__.py create mode 100644 automon/integrations/xsoar/endpoints/v1.py create mode 100644 automon/integrations/xsoar/tests/__init__.py create mode 100644 automon/integrations/xsoar/tests/test_client_auth.py create mode 100644 automon/integrations/xsoar/tests/test_config.py diff --git a/README.md b/README.md index 4118d999..48e7bd73 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Github issues and feature requests welcomed. | Logging | sentryio | | MacOS | airport
macchanger
wdutil | | Python | logging
requests | -| SOAR | swimlane
splunk soar | +| SOAR | swimlane
splunk soar
xsoar | | Recon | nmap | | Test Automation | selenium | diff --git a/automon/integrations/xsoar/__init__.py b/automon/integrations/xsoar/__init__.py new file mode 100644 index 00000000..6a965d12 --- /dev/null +++ b/automon/integrations/xsoar/__init__.py @@ -0,0 +1,2 @@ +from .client import XSOARClient +from .config import XSOARConfig diff --git a/automon/integrations/xsoar/client.py b/automon/integrations/xsoar/client.py new file mode 100644 index 00000000..c06c4aeb --- /dev/null +++ b/automon/integrations/xsoar/client.py @@ -0,0 +1,68 @@ +from automon.log import logging +from automon.integrations.requestsWrapper import RequestsClient + +from .config import XSOARConfig +from .endpoints import v1 + +logger = logging.getLogger(__name__) +logger.setLevel(level=logging.DEBUG) + + +class XSOARClient(object): + """XSOAR REST API client + + referenc: https://cortex-panw.stoplight.io/docs/cortex-xsoar-8/kjn2q21a7yrbm-get-started-with-cortex-xsoar-8-ap-is + """ + + def __init__( + self, + host: str = None, + api_key: str = None, + api_key_id: str = None, + config: XSOARConfig = None + ): + self.config = config or XSOARConfig(host=host, api_key=api_key, api_key_id=api_key_id) + self._requests = RequestsClient() + + async def is_ready(self): + if self.config.is_ready(): + return True + return False + + async def auth(self): + return + + @property + def errors(self): + return self._requests.errors + + async def get(self, endpoint: str): + logger.info(dict( + endpoint=f'{self.config.host}/{endpoint}' + )) + response = await self._requests.get(url=f'{self.config.host}/{endpoint}', headers=self.config.headers) + + if response: + return response + + logger.error(self.errors) + raise Exception(self.errors) + + async def post(self, endpoint: str): + logger.info(dict( + endpoint=f'{self.config.host}/{endpoint}' + )) + response = self._requests.post(url=f'{self.config.host}/{endpoint}', headers=self.config.headers) + + if response: + return response + + logger.error(self.errors) + raise Exception(self.errors) + + async def reports(self): + reports = await self.get(endpoint=v1.Reports.reports) + logger.info(dict( + reports=self._requests.content + )) + return reports diff --git a/automon/integrations/xsoar/config.py b/automon/integrations/xsoar/config.py new file mode 100644 index 00000000..57c6b1a7 --- /dev/null +++ b/automon/integrations/xsoar/config.py @@ -0,0 +1,41 @@ +from automon import environ +from automon.log import logging + +logger = logging.getLogger(__name__) +logger.setLevel(level=logging.DEBUG) + + +class XSOARConfig(object): + """XSOAR REST API client config""" + + def __init__( + self, + host: str = None, + api_key: str = None, + api_key_id: str = None + ): + self.host = host or environ('XSOAR_FQDN') + self.api_key = api_key or environ('XSOAR_API_KEY') + self.api_key_id = api_key_id or environ('XSOAR_API_KEY_ID') + + def is_ready(self) -> bool: + if not self.host: + logger.error(f'missing XSOAR_FQDN') + + if not self.api_key: + logger.error(f'missing XSOAR_API_KEY') + + if not self.api_key_id: + logger.error(f'missing XSOAR_API_KEY_ID') + + if self.host and self.api_key and self.api_key_id: + return True + return False + + @property + def headers(self): + return { + 'Authorization': f'{self.api_key}', + 'x-xdr-auth-id': f'{self.api_key_id}', + "Content-Type": "application/json" + } diff --git a/automon/integrations/xsoar/endpoints/__init__.py b/automon/integrations/xsoar/endpoints/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/automon/integrations/xsoar/endpoints/v1.py b/automon/integrations/xsoar/endpoints/v1.py new file mode 100644 index 00000000..3ccb9458 --- /dev/null +++ b/automon/integrations/xsoar/endpoints/v1.py @@ -0,0 +1,9 @@ +class V1: + xsoar: str = 'xsoar' + public: str = f'{xsoar}/public' + v1: str = f'{public}/v1' + + +class Reports: + """xsoar/public/v1/reports""" + reports: str = f'{V1.v1}/reports' diff --git a/automon/integrations/xsoar/tests/__init__.py b/automon/integrations/xsoar/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/automon/integrations/xsoar/tests/test_client_auth.py b/automon/integrations/xsoar/tests/test_client_auth.py new file mode 100644 index 00000000..520ed624 --- /dev/null +++ b/automon/integrations/xsoar/tests/test_client_auth.py @@ -0,0 +1,17 @@ +import asyncio +import unittest + +from automon.integrations.xsoar import XSOARClient + + +class MyTestCase(unittest.TestCase): + test = XSOARClient() + + if asyncio.run(test.is_ready()): + def test_auth(self): + result = asyncio.run(self.test.reports()) + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/automon/integrations/xsoar/tests/test_config.py b/automon/integrations/xsoar/tests/test_config.py new file mode 100644 index 00000000..e496be05 --- /dev/null +++ b/automon/integrations/xsoar/tests/test_config.py @@ -0,0 +1,15 @@ +import unittest + +from automon.integrations.xsoar import XSOARConfig + + +class MyTestCase(unittest.TestCase): + test = XSOARConfig() + + if test.is_ready(): + def test_config(self): + self.assertTrue(self.test.is_ready()) + + +if __name__ == '__main__': + unittest.main() diff --git a/env-example.sh b/env-example.sh index 0be017cb..fb6ec32d 100644 --- a/env-example.sh +++ b/env-example.sh @@ -147,3 +147,8 @@ VDS_PASSWORD= # Wdutil WDUTIL_PASSWORD= + +# XSOAR +XSOAR_FQDN= +XSOAR_API_KEY= +XSOAR_API_KEY_ID= From 4eaba13f5558b9b5031fcf9a7b8776959c484a9c Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Sun, 23 Jun 2024 19:00:26 -0700 Subject: [PATCH 02/22] requests: linting --- automon/integrations/requestsWrapper/rest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/automon/integrations/requestsWrapper/rest.py b/automon/integrations/requestsWrapper/rest.py index ba3736a7..1a780327 100644 --- a/automon/integrations/requestsWrapper/rest.py +++ b/automon/integrations/requestsWrapper/rest.py @@ -6,6 +6,7 @@ logger = log.logging.getLogger(__name__) logger.setLevel(log.DEBUG) + class BaseRestClient: requests: RequestsClient config: RequestsConfig From fed29c1caf92d45804480070bac3b66e18a451b8 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Sun, 23 Jun 2024 18:55:30 -0700 Subject: [PATCH 03/22] requests: fix tests --- automon/integrations/requestsWrapper/tests/test_rest.py | 2 +- .../integrations/requestsWrapper/tests/test_rest_inherit.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/automon/integrations/requestsWrapper/tests/test_rest.py b/automon/integrations/requestsWrapper/tests/test_rest.py index cfd699b1..bf34afc4 100644 --- a/automon/integrations/requestsWrapper/tests/test_rest.py +++ b/automon/integrations/requestsWrapper/tests/test_rest.py @@ -9,7 +9,7 @@ class Client(unittest.TestCase): def test_get(self): self.assertTrue(asyncio.run(r.get('https://1.1.1.1'))) - self.assertTrue(r.requests.get('https://1.1.1.1')) + self.assertTrue(asyncio.run(r.requests.get('https://1.1.1.1'))) self.assertFalse(asyncio.run(r.get('x://127.0.0.1'))) diff --git a/automon/integrations/requestsWrapper/tests/test_rest_inherit.py b/automon/integrations/requestsWrapper/tests/test_rest_inherit.py index a0b3478a..112df0ee 100644 --- a/automon/integrations/requestsWrapper/tests/test_rest_inherit.py +++ b/automon/integrations/requestsWrapper/tests/test_rest_inherit.py @@ -4,16 +4,16 @@ from automon.integrations.requestsWrapper.rest import BaseRestClient -class Test(BaseRestClient): +class Inherit(BaseRestClient): def __init__(self): - BaseRestClient.__init__(self) + super().__init__() pass class Client(unittest.TestCase): def test_get(self): - self.assertTrue(asyncio.run(Test().get(url='https://1.1.1.1'))) + self.assertTrue(asyncio.run(Inherit().get(url='https://1.1.1.1'))) if __name__ == '__main__': From 0709c7c21c0f6961de42abe08c81835d0aeef8aa Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Sun, 23 Jun 2024 21:54:58 -0700 Subject: [PATCH 04/22] requests: add typing, log non http 200 as error --- automon/integrations/requestsWrapper/client.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/automon/integrations/requestsWrapper/client.py b/automon/integrations/requestsWrapper/client.py index f6aab814..e2f3aecf 100644 --- a/automon/integrations/requestsWrapper/client.py +++ b/automon/integrations/requestsWrapper/client.py @@ -15,10 +15,10 @@ def __init__(self, url: str = None, data: dict = None, headers: dict = None, self.config = config or RequestsConfig() - self.url = url - self.data = data - self.errors = None - self.headers = headers + self.url: str = url + self.data: dict = data + self.errors: bytes = b'' + self.headers: dict = headers self.response = None self.requests = requests self.session = self.requests.Session() @@ -122,6 +122,8 @@ async def get( if self.status_code == 200: return True + self.errors = self.content + return False except Exception as e: self.errors = e @@ -151,6 +153,8 @@ async def patch( if self.status_code == 200: return True + self.errors = self.content + return False except Exception as e: self.errors = e @@ -180,6 +184,8 @@ async def post( if self.status_code == 200: return True + self.errors = self.content + return False except Exception as e: self.errors = e @@ -209,6 +215,8 @@ async def put( if self.status_code == 200: return True + self.errors = self.content + return False except Exception as e: self.errors = e From 7688ab9a02ab90d84a5ef12ea493bbd3ca8da3fb Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Mon, 24 Jun 2024 00:36:32 -0700 Subject: [PATCH 05/22] github actions: add env var SELENIUM_CHROMEDRIVER_PATH for selenium testing otherwise selenium will try to download the driver itself, but it seems to have been failing, or something. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b1fc5dd..dbd6110c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: run: /bin/bash test.sh env: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SELENIUM_CHROMEDRIVER_PATH: /usr/bin/chromedriver docker-build: From 12d8cc5b4bdc356d41a193138503d74e8ef91b43 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Mon, 24 Jun 2024 00:36:32 -0700 Subject: [PATCH 06/22] github actions: add env var SELENIUM_CHROMEDRIVER_PATH for selenium testing otherwise selenium will try to download the driver itself, but it seems to have been failing, or something. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b1fc5dd..dbd6110c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: run: /bin/bash test.sh env: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SELENIUM_CHROMEDRIVER_PATH: /usr/bin/chromedriver docker-build: From 6e73e6e35c8ca939302db0c4f5ed9d063049ba25 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Mon, 24 Jun 2024 01:25:25 -0700 Subject: [PATCH 07/22] gihtub actions: update chromedriver 126.0.6478.63 --- docker/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/install.sh b/docker/install.sh index eb903f1e..a6f32687 100644 --- a/docker/install.sh +++ b/docker/install.sh @@ -10,7 +10,7 @@ google-chrome --version # install chromedriver cd /tmp/ # https://googlechromelabs.github.io/chrome-for-testing/#stable -wget -q https://storage.googleapis.com/chrome-for-testing-public/124.0.6367.91/linux64/chromedriver-linux64.zip +wget -q https://storage.googleapis.com/chrome-for-testing-public/126.0.6478.63/linux64/chromedriver-linux64.zip unzip chromedriver-linux64.zip sudo mv chromedriver-linux64/chromedriver /usr/bin/chromedriver chromedriver --version From ab8d653ba734fc0bc022b6ec876cb5608a844444 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Mon, 24 Jun 2024 01:25:25 -0700 Subject: [PATCH 08/22] gihtub actions: update chromedriver 126.0.6478.63 --- docker/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/install.sh b/docker/install.sh index eb903f1e..a6f32687 100644 --- a/docker/install.sh +++ b/docker/install.sh @@ -10,7 +10,7 @@ google-chrome --version # install chromedriver cd /tmp/ # https://googlechromelabs.github.io/chrome-for-testing/#stable -wget -q https://storage.googleapis.com/chrome-for-testing-public/124.0.6367.91/linux64/chromedriver-linux64.zip +wget -q https://storage.googleapis.com/chrome-for-testing-public/126.0.6478.63/linux64/chromedriver-linux64.zip unzip chromedriver-linux64.zip sudo mv chromedriver-linux64/chromedriver /usr/bin/chromedriver chromedriver --version From a0bfaac3fa76f8f0436332901ee68bd3eb58e936 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 03:15:47 -0700 Subject: [PATCH 09/22] selenium: update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index abcbe8e6..f64881d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,6 +56,7 @@ pytz>=2021.1 # selenium selenium>=3.141.0 +beautifulsoup4>=4.10.0 # sentry.io sentry-sdk>=1.5.1 From c7c39e939ed94d8bf40109134c2a28dc9458d4aa Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 03:18:28 -0700 Subject: [PATCH 10/22] selenium: raise exception on missing SELENIUM_CHROMEDRIVER_PATH --- automon/integrations/seleniumWrapper/webdriver_chrome.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automon/integrations/seleniumWrapper/webdriver_chrome.py b/automon/integrations/seleniumWrapper/webdriver_chrome.py index a1697694..ba2ae55b 100644 --- a/automon/integrations/seleniumWrapper/webdriver_chrome.py +++ b/automon/integrations/seleniumWrapper/webdriver_chrome.py @@ -56,7 +56,7 @@ def chromedriver_path(self): if os.path.exists(path): return path - logger.error('missing SELENIUM_CHROMEDRIVER_PATH') + raise Exception('missing SELENIUM_CHROMEDRIVER_PATH') @property def chromedriverVersion(self): From fe3f00b40e3b429433f4d758963bff97d5d6ff24 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 04:20:11 -0700 Subject: [PATCH 11/22] instagram: catch exception --- .../integrations/instagram/client_browser.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/automon/integrations/instagram/client_browser.py b/automon/integrations/instagram/client_browser.py index 51b0ad6c..805668df 100644 --- a/automon/integrations/instagram/client_browser.py +++ b/automon/integrations/instagram/client_browser.py @@ -27,8 +27,7 @@ def __init__(self, headless: bool = True): """Instagram Browser Client""" self.config = config or InstagramConfig(login=login, password=password) - self.browser = SeleniumBrowser() - self.browser.config.webdriver_wrapper = ChromeWrapper() + self.browser = None self.authenticated_browser = None self.useragent = None @@ -237,13 +236,19 @@ def login(self) -> str: return self.config.login async def start(self): - self.useragent = await self.browser.get_random_user_agent() + try: + self.browser = SeleniumBrowser() + self.browser.config.webdriver_wrapper = ChromeWrapper() + + self.useragent = await self.browser.get_random_user_agent() - if self.headless: - self.browser.config.webdriver_wrapper.in_headless() - self.browser.config.webdriver_wrapper.set_user_agent(self.useragent) - else: - self.browser.config.webdriver_wrapper.set_user_agent(self.useragent) + if self.headless: + self.browser.config.webdriver_wrapper.in_headless() + self.browser.config.webdriver_wrapper.set_user_agent(self.useragent) + else: + self.browser.config.webdriver_wrapper.set_user_agent(self.useragent) + except Exception as error: + logger.error(error) @property def urls(self): From 44e5802dfc71404ee5d11501fdb68aba8bc95f56 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 05:07:07 -0700 Subject: [PATCH 12/22] selenium: catch exception when running browser --- automon/integrations/seleniumWrapper/webdriver_chrome.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/automon/integrations/seleniumWrapper/webdriver_chrome.py b/automon/integrations/seleniumWrapper/webdriver_chrome.py index ba2ae55b..70fc171c 100644 --- a/automon/integrations/seleniumWrapper/webdriver_chrome.py +++ b/automon/integrations/seleniumWrapper/webdriver_chrome.py @@ -22,8 +22,6 @@ def __init__(self): self._ChromeService = None self._window_size = set_window_size() - self.update_paths(self.chromedriver_path) - def __repr__(self): if self._webdriver: return str(dict( @@ -313,6 +311,8 @@ def in_sandbox_disabled(self): async def run(self) -> bool: try: + self.update_paths(self.chromedriver_path) + if self.chromedriver_path: self._ChromeService = selenium.webdriver.ChromeService( executable_path=self.chromedriver_path From cf300f19153fd5219e264bad470d4d318ee8a037 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 05:22:30 -0700 Subject: [PATCH 13/22] selenium: fix def start never awaited --- automon/integrations/seleniumWrapper/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index f0edcb04..0e97e213 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -601,7 +601,7 @@ async def set_window_position(self, x: int = 0, y: int = 0): async def start(self): """alias to run""" - return self.run() + return await self.run() async def wait_for( self, From 11b9b0bc7049bef8f95f43f8fb1ffcad06bd03e1 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 16:22:54 -0700 Subject: [PATCH 14/22] selenium: fix click with async with async you can't chain methods --- automon/integrations/seleniumWrapper/browser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index 0e97e213..27ff1267 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -187,7 +187,8 @@ async def action_click( logger.debug(str(dict( xpath=xpath, ))) - return await self.find_element(value=xpath, by=self.by.XPATH, **kwargs).click() + element = await self.find_element(value=xpath, by=self.by.XPATH, **kwargs) + return element.click() except Exception as error: raise Exception(error) From d7bec9d388147bfc3e577eef5d3b79b7f9f48f13 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 16:53:38 -0700 Subject: [PATCH 15/22] selenium: cookie in json file --- automon/integrations/seleniumWrapper/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index 27ff1267..08147e7b 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -58,7 +58,7 @@ def by(self) -> By: def config(self): return self._config - async def cookie_file_to_dict(self, file: str = 'cookies.txt') -> list: + async def cookie_file_to_dict(self, file: str = 'cookies.json') -> list: logger.debug(dict( cookie_file_to_dict=file )) @@ -290,7 +290,7 @@ async def delete_all_cookies(self) -> None: async def _url_filename(self, url: str): parsed = await self.urlparse(url) hostname = parsed.hostname - cookie_file = f'cookies-{hostname}.txt' + cookie_file = f'cookies-{hostname}.json' logger.debug(dict( _url_filename=cookie_file )) From 59f4e80fecfc67f607b079626874cb19bede4557 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 17:01:29 -0700 Subject: [PATCH 16/22] selenium: fix type secret --- automon/integrations/seleniumWrapper/browser.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index 08147e7b..2944b28c 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -201,11 +201,13 @@ async def action_type( """perform keyboard command""" if secret: - key = f'*' * len(key) - - logger.debug(str(dict( - send_keys=key, - ))) + logger.debug(dict( + send_keys=f'*' * len(key), + )) + else: + logger.debug(dict( + send_keys=key, + )) try: return selenium.webdriver.common.action_chains.ActionChains( From cb7b0ab4c07b37df1df609240933187acc5c5ead Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 18:38:53 -0700 Subject: [PATCH 17/22] selenium: fix find_xpath --- automon/integrations/seleniumWrapper/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index 2944b28c..71f76c00 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -391,7 +391,7 @@ async def find_xpath( current_url=self.current_url, value=value, ))) - return self.find_element(value=value, by=by, **kwargs) + return await self.find_element(value=value, by=by, **kwargs) async def get(self, url: str, **kwargs) -> bool: """get url""" From c75edfacacfa022d753469626ef842dbec66383a Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 18:39:01 -0700 Subject: [PATCH 18/22] selenium: add find_elements --- automon/integrations/seleniumWrapper/browser.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index 71f76c00..fd8963ff 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -380,6 +380,19 @@ async def find_element( ))) return self.webdriver.find_element(value=value, by=by, **kwargs) + async def find_elements( + self, + value: str, + by: By.ID = By.ID, + **kwargs + ) -> selenium.webdriver.Chrome.find_elements: + """find elements""" + logger.info(str(dict( + current_url=self.current_url, + value=value, + ))) + return self.webdriver.find_elements(value=value, by=by, **kwargs) + async def find_xpath( self, value: str, From 42005d141f7898c407bcaef0fd7db92e735ca2e0 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 22:31:16 -0700 Subject: [PATCH 19/22] selenium: add action_type_up, action_type_down --- .../integrations/seleniumWrapper/browser.py | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index fd8963ff..c3dbd214 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -184,9 +184,7 @@ async def action_click( ) -> selenium.webdriver.Chrome.find_element: """perform mouse command""" try: - logger.debug(str(dict( - xpath=xpath, - ))) + logger.debug(dict(xpath=xpath)) element = await self.find_element(value=xpath, by=self.by.XPATH, **kwargs) return element.click() @@ -196,18 +194,14 @@ async def action_click( async def action_type( self, key: str or Keys, - secret: bool = True, + secret: bool = False, ) -> selenium.webdriver.common.action_chains.ActionChains: """perform keyboard command""" if secret: - logger.debug(dict( - send_keys=f'*' * len(key), - )) + logger.debug(dict(send_keys=f'*' * len(f'{key}'))) else: - logger.debug(dict( - send_keys=key, - )) + logger.debug(dict(send_keys=key)) try: return selenium.webdriver.common.action_chains.ActionChains( @@ -216,6 +210,44 @@ async def action_type( except Exception as error: raise Exception(error) + async def action_type_up( + self, + key: str or Keys, + secret: bool = False, + ) -> selenium.webdriver.common.action_chains.ActionChains: + """release key""" + + if secret: + logger.debug(dict(send_keys=f'*' * len(f'{key}'))) + else: + logger.debug(dict(send_keys=key)) + + try: + return selenium.webdriver.common.action_chains.ActionChains( + self.webdriver).key_up(key).perform() + + except Exception as error: + raise Exception(error) + + async def action_type_down( + self, + key: str or Keys, + secret: bool = False, + ) -> selenium.webdriver.common.action_chains.ActionChains: + """hold key down""" + + if secret: + logger.debug(dict(send_keys=f'*' * len(f'{key}'))) + else: + logger.debug(dict(send_keys=key)) + + try: + return selenium.webdriver.common.action_chains.ActionChains( + self.webdriver).key_down(key).perform() + + except Exception as error: + raise Exception(error) + async def add_cookie(self, cookie_dict: dict) -> bool: result = self.webdriver.add_cookie(cookie_dict=cookie_dict) From 6347a02501e31c47ff3e93d3382bf8173f28edf4 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Tue, 2 Jul 2024 22:32:02 -0700 Subject: [PATCH 20/22] selenium: update set_window_size --- automon/integrations/seleniumWrapper/webdriver_chrome.py | 1 + 1 file changed, 1 insertion(+) diff --git a/automon/integrations/seleniumWrapper/webdriver_chrome.py b/automon/integrations/seleniumWrapper/webdriver_chrome.py index 70fc171c..79eaec79 100644 --- a/automon/integrations/seleniumWrapper/webdriver_chrome.py +++ b/automon/integrations/seleniumWrapper/webdriver_chrome.py @@ -372,6 +372,7 @@ def set_user_agent(self, user_agent: str): return self def set_window_size(self, *args, **kwargs): + """has to be set after setting webdriver""" self._window_size = set_window_size(*args, **kwargs) width, height = self.window_size self.webdriver.set_window_size(width=width, height=height) From 0c92e39271486f7088977d9462876ac716426e2d Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Wed, 3 Jul 2024 21:53:21 -0700 Subject: [PATCH 21/22] selenium: add find_anything --- .../integrations/seleniumWrapper/browser.py | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index c3dbd214..d912b70b 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -399,6 +399,75 @@ async def error_parsing(error) -> tuple: return error, None, None + async def find_anything( + self, + value: str, + case_insensitivity: bool = True, + contains: bool = True, + **kwargs + ) -> selenium.webdriver.Chrome.find_element: + """fuzzy search through everything + + find all tags + find all matches within meta data + """ + logger.info(dict( + current_url=self.current_url, + value=value, + case_insensitivity=case_insensitivity, + contains=contains, + kwargs=kwargs, + )) + + by_types = [ + self.by.TAG_NAME, + ] + + MATCHED = [] + + for by in by_types: + elements = self.webdriver.find_elements(value='*', by=by) + for element in elements: + dirs = dir(element) + dir_meta = [] + for dir_ in dirs: + try: + dir_meta.append( + getattr(element, f'{dir_}') + ) + + MATCH = f'{value}' + AGAINST = f'''{getattr(element, f'{dir_}')}''' + + if case_insensitivity: + MATCH = f'{value}'.lower() + AGAINST = f'''{getattr(element, f'{dir_}')}'''.lower() + + except: + pass + + FOUND = None + + if MATCH == AGAINST and not contains: + FOUND = element + + if MATCH in AGAINST and contains: + FOUND = element + + if FOUND and FOUND not in MATCHED: + logger.info(dict( + MATCH=MATCH, + AGAINST=AGAINST, + attribute=dir_, + element=element, + )) + MATCHED.append(FOUND) + + pass + pass + + return MATCHED + async def find_element( self, value: str, From 98fb6b1055415a09e31d9ed59b9bb75905acd855 Mon Sep 17 00:00:00 2001 From: naisanzaa Date: Wed, 3 Jul 2024 22:39:49 -0700 Subject: [PATCH 22/22] selenium: fix action_click to use element --- automon/integrations/seleniumWrapper/browser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/automon/integrations/seleniumWrapper/browser.py b/automon/integrations/seleniumWrapper/browser.py index d912b70b..3a67abf5 100644 --- a/automon/integrations/seleniumWrapper/browser.py +++ b/automon/integrations/seleniumWrapper/browser.py @@ -6,6 +6,7 @@ import tempfile import selenium import selenium.webdriver +import selenium.webdriver.remote.webelement from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys @@ -180,12 +181,10 @@ def _screenshot_name(self, prefix=None): async def action_click( self, - xpath: str, **kwargs - ) -> selenium.webdriver.Chrome.find_element: - """perform mouse command""" + element: selenium.webdriver.remote.webelement.WebElement, **kwargs): + """perform mouse click""" try: - logger.debug(dict(xpath=xpath)) - element = await self.find_element(value=xpath, by=self.by.XPATH, **kwargs) + logger.debug(dict(element=element)) return element.click() except Exception as error: