From 9640d762e0d8aef9b256e61ce99c3ed4c73b5113 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 10 Jul 2024 10:52:08 -0500 Subject: [PATCH] wip chase sms 2fa --- chase2fa.py | 19 +++++++++++++++++++ xactfetch.py | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 chase2fa.py diff --git a/chase2fa.py b/chase2fa.py new file mode 100644 index 0000000..f179c5c --- /dev/null +++ b/chase2fa.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +import re + +import httpx + +stream = httpx.stream( + 'GET', + 'https://ntfy.pyrocufflink.blue/chase2fa/raw', + timeout=httpx.Timeout(5, read=None), +) +with stream as r: + for line in r.iter_lines(): + line = line.strip() + if not line: + continue + m = re.search(r'\d{4,}', line) + if m: + print(m.group(0)) + break diff --git a/xactfetch.py b/xactfetch.py index d3a0a04..3ce1b28 100644 --- a/xactfetch.py +++ b/xactfetch.py @@ -551,11 +551,8 @@ class Chase: with self.saved_cookies.open(encoding='utf-8') as f: cookies = await asyncio.to_thread(json.load, f) await self.page.context.add_cookies(cookies) - except: - log.warning( - 'Could not load saved cookies, ' - 'SMS verification will be required!' - ) + except Exception as e: + log.debug('Failed to load saved cookies: %s', e) else: log.info('Successfully loaded saved cookies') @@ -587,9 +584,39 @@ class Chase: await logonbox.get_by_role('button', name='Sign in').click() log.debug('Waiting for page load') await self.page.wait_for_load_state() - await self.page.get_by_role('button', name='Pay Card').wait_for( - timeout=120000 + logonframe = self.page.frame_locator('iframe[title="logon"]') + t_2fa = asyncio.create_task( + logonframe.get_by_role( + 'heading', name="We don't recognize this device" + ).wait_for() ) + t_finished = asyncio.create_task( + self.page.get_by_role('button', name='Pay Card').wait_for() + ) + done, pending = await asyncio.wait( + (t_2fa, t_finished), + return_when=asyncio.FIRST_COMPLETED, + ) + for t in pending: + t.cancel() + for t in done: + await t + if t_2fa in done: + log.warning('Device verification (SMS 2-factor auth) required') + await logonframe.get_by_label('Tell us how: Choose one').click() + await logonframe.locator( + '#container-1-simplerAuth-dropdownoptions-styledselect' + ).click() + otp_task = asyncio.create_task(self.get_secret('bank.chase.otp')) + await logonframe.get_by_role('button', name='Next').click() + log.info('Waiting for SMS verification code') + otp = await otp_task + log.debug('Filling verification code form') + await logonframe.get_by_label('One-time code').fill(otp) + await logonframe.get_by_label('Password').fill(password) + await logonframe.get_by_role('button', name='Next').click() + await self.page.wait_for_load_state() + await self.page.get_by_role('button', name='Pay Card').wait_for() log.info('Successfully logged in to Chase') self._logged_in = True