Exemple #1
0
async def get_updates():
    session = get_session(request)
    fetch_time: float = time.time()
    form: dict = await request.form
    if not is_logged_in(session):
        return _response({"error": "not_authenticated"}, code=403)
    chat_id: str = form.get("chat_id")
    fetch_from: int = form.get("fetch_from")
    full_fetch: bool = fetch_from == 0 or fetch_from == "0"
    _chat_data: chatData = check_chat_data(id_=chat_id)
    chats: dict = _chat_data.chats
    updates: dict = _chat_data.updates
    for k, v in chats.items():
        if v.get("sender") != session["user"] and not v.get("rstamp"):
            chats[k]["read"] = True
            stamp: float = time.time() * 1000
            chats[k]["rstamp"] = stamp
    _chat_data.chats = chats
    flag_modified(_chat_data, "chats")
    # pylint: disable=E1101
    db.session.merge(_chat_data)
    db.session.commit()
    # pylint: enable=E1101
    data: dict = get_data_from(chats, fetch_from, session["user"], "messages")
    return _response({
        "update_data": updates,
        "message_data": data,
        "newest_message_id": fetch_from,
        "full_fetch": full_fetch,
        "sp": time.time() - fetch_time,
    })
Exemple #2
0
 async def cred_check(self, _session: dict) -> bool:
     if not is_logged_in(_session):
         await self.send_message(
             {"error": "Not Authenticated..did you clear your cookies?"})
         return False
     self.user: str = _session["user"]
     return True
 def wrapper(*args, **kwargs):
     agent_name = request.headers.get('X-API-USER', None)
     authorization = request.headers.get('X-API-TOKEN', 'Acdlsdksl')
     if authorization and is_logged_in(agent_name, authorization):
         return method(*args, **kwargs)
     else:
         return unauthenticated()
Exemple #4
0
async def api_tools():
    session = get_session(request)
    if not is_logged_in(session):
        return _response("__error__",
                         headers={"content-type": "data/plain"},
                         code=403)
    return _response(f')}}]{session["user"]}',
                     headers={"content-type": "data/plain"})
def main_loop(driver, args):
    log.info('Reading slot preferences from conf')
    slot_prefs = get_prefs_from_conf()
    log.info('Navigating to ' + config.BASE_URL)
    driver.get(config.BASE_URL)

    if args.force_login or not os.path.exists(config.PKL_PATH):
        # Login and capture Amazon session data...
        wait_for_auth(driver)
    else:
        # ...or load from storage
        load_session_data(driver)
        driver.refresh()
        if is_logged_in(driver):
            log.info('Successfully logged in via stored session data')
        else:
            log.error('Error logging in with stored session data')
            wait_for_auth(driver)
    site_config = config.SiteConfig(args.service)
    # Navigate to slot select
    build_route(site_config, 'SLOT_SELECT').navigate(driver)
    slots = slots_available(driver, slot_prefs)
    if slots:
        annoy()
        alert('Delivery slots available. What do you need me for?', 'Sosumi')
    while not slots:
        log.info('No slots found :( waiting...')
        jitter(25)
        driver.refresh()
        slots = slots_available(driver, slot_prefs)
        if slots:
            alert('Delivery slots found')
            message_body = generate_message(slots, args.service, args.checkout)
            send_sms(message_body)
            send_telegram(message_body)
            if not args.checkout:
                break
            checked_out = False
            log.info('Attempting to select slot and checkout')
            while not checked_out:
                try:
                    log.info('Selecting slot: ' + slots[0].full_name)
                    slots[0].select(driver)
                    build_route(site_config, 'CHECKOUT').navigate(driver)
                    checked_out = True
                    alert('Checkout complete', 'Hero')
                except RouteRedirectException:
                    log.warning('Checkout failed: Redirected to slot select')
                    slots = slots_available(driver, slot_prefs)
                    if not slots:
                        break
Exemple #6
0
async def make_notif():
    form = await request.form
    session = get_session(request)
    if not is_logged_in(session) or not form.get("token"):
        return "NO"
    token = form.get("token")
    user = userData.query.filter(
        func.lower(userData.user) == func.lower(session["user"])).first()
    if not user:
        return "ERROR:USER NOT IN DB", 500
    user.notification_id = token
    # pylint: disable=E1101
    db.session.commit()
    # pylint: enable=E1101
    return "OK"
Exemple #7
0
async def get_chat_ids():
    session = get_session(request)
    form = await request.form
    idx = form.get("chat_id")
    if not idx or not is_logged_in(session):
        return _response({"error": "Invalid Credentials"}, code=401)
    data = check_chat_data(id_=idx)
    if not data:
        return _response({"error": "Invalid ID"}, code=403)
    if session["user"] not in (data.user1, data.user2):
        return _response({"error": "InvalidID"}, code=403)
    user1 = data.user1 if not data.user1 == session["user"] else data.user2
    chat_id = data.id_
    _socket = sockets_get(user1)
    userHasSocket: str = "online" if _socket else "offline"
    return _response({
        "is_online": userHasSocket,
        "chat_id": chat_id,
        "chat_with": user1,
        "HERE": session["user"],
    })
Exemple #8
0
async def instants():
    form = await request.get_json()
    session = get_session(request)
    if not is_logged_in(session):
        return "{}", 403
    details = form.get("details")
    _chat_id = details.get("chat_id")
    _data = details.get("data")
    _new_msg_id = alter_chat_data(_data, _chat_id, True)
    ws_obj = sockets_get(_data.get("receiver"))
    if ws_obj:
        await ws_obj.send(
            json.dumps({
                "meta": {
                    "from": session.get("user"),
                    "sessid": secrets.token_urlsafe(10),
                },
                "data": {
                    "msgid": _new_msg_id
                },
                "type": "get-update",
            }))
    return _response({"type": "new_message", "data": _new_msg_id})
Exemple #9
0
def web_automation(driver, merchant: Merchant, amount):
    driver.get(
        'https://www.easypaymetrocard.com/vector/forte/cgi_bin/forteisapi.dll?ServiceName=ETCAccountWebSO&TemplateName=accounts/PrePaidPayment.html'
    )
    time.sleep(5)  # wait for page to load or redirect to login page
    logged_in = utils.is_logged_in(driver,
                                   timeout=90,
                                   logged_out_element=(By.ID, 'iPassword'),
                                   logged_in_element=(By.ID, 'securitycode'))

    if not logged_in:
        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants

        try:  # some websites will have the username auto-filled in due to a previous login
            if hasattr(merchant, 'usr'):
                driver.find_element_by_id('username').send_keys(merchant.usr)
        except ElementNotInteractableException:
            pass
        try:  # only one of .usr and .accountnumber should exist
            if hasattr(merchant, 'accountnumber'):
                driver.find_element_by_id('iAccountNumber').send_keys(
                    merchant.accountnumber)
        except ElementNotInteractableException:
            pass

        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants
        driver.find_element_by_id('iPassword').send_keys(merchant.psw)
        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants
        driver.find_element_by_xpath("//input[@type='submit']").click()

        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.LINK_TEXT, 'One Time Payment')))

    driver.get(
        'https://www.easypaymetrocard.com/vector/forte/cgi_bin/forteisapi.dll?ServiceName=ETCAccountWebSO&TemplateName=accounts/PrePaidPayment.html'
    )

    assert merchant.card in [
        "Primary", "Secondary"
    ], "Only supports existing Primary or Secondary card"
    card_xpath = "//input[@value='{}']".format(merchant.card)
    driver.find_element_by_xpath(card_xpath).click()
    time.sleep(2)
    driver.find_element_by_id("securitycode").send_keys(merchant.cvv)
    time.sleep(2)
    driver.find_element_by_id("iAmount").send_keys(utils.cents_to_str(amount))
    time.sleep(2)
    driver.find_element_by_id("Address1").send_keys(merchant.address1)
    time.sleep(2)
    driver.find_element_by_id("Address2").send_keys(merchant.address2)
    time.sleep(2)
    driver.find_element_by_id("City").send_keys(merchant.city)
    time.sleep(2)
    driver.find_element_by_id("usStates").send_keys(merchant.state)
    time.sleep(2)
    driver.find_element_by_id("iZip").send_keys(merchant.zip)
    time.sleep(2)
    driver.find_element_by_xpath("//input[@type='submit']").click()

    try:
        WebDriverWait(driver, 30).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH, "//*[contains(text(),'successfully processed')]")))
    except TimeoutException:
        return Result.unverified  # Purchase command was executed, yet we are unable to verify that it was successfully executed.
        # since debbit may have spent money but isn't sure, we log the error and stop any further payments for this merchant until the user intervenes

    time.sleep(
        5)  # sleep for a bit to show user that payment screen is reached
    return Result.success
Exemple #10
0
def web_automation(driver, merchant, amount):
    driver.get('http://payments.xfinity.com/')

    logged_in = utils.is_logged_in(driver,
                                   timeout=90,
                                   logged_out_element=(By.ID, 'user'),
                                   logged_in_element=(By.ID, 'customAmount'))

    if not logged_in:
        driver.find_element_by_id('user').send_keys(merchant.usr)
        driver.find_element_by_id('passwd').send_keys(merchant.psw)
        driver.find_element_by_id('sign_in').click()

        try:  # first time run captcha
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'nucaptcha-answer')))
            LOGGER.info('captcha detected')
            input('''
Detected first time run captcha. Please follow these one-time steps. Future runs won't need this.

1. Open the Firefox window that debbit created.
2. Enter your user, pass, and the moving characters manually.
3. Click the "Sign In" button.
4. Click on this terminal window and hit "Enter" to continue running debbit.
''')
        except TimeoutException:
            pass

        WebDriverWait(driver, 90).until(
            expected_conditions.element_to_be_clickable(
                (By.ID, 'customAmount')))

    if driver.find_elements_by_id('no'):  # survey pop-up
        driver.find_element_by_id('no').click()

    cur_balance = driver.find_element_by_xpath(
        "//span[contains(text(), '$')]").text
    if utils.str_to_cents(cur_balance) == 0:
        LOGGER.error('xfinity balance is zero, will try again later.')
        return Result.skipped
    elif utils.str_to_cents(cur_balance) < amount:
        amount = utils.str_to_cents(cur_balance)

    driver.find_element_by_id('customAmount').send_keys(
        utils.cents_to_str(amount))
    driver.find_element_by_xpath("//span[contains(text(),'nding in " +
                                 merchant.card[-4:] + "')]").click()
    driver.find_element_by_xpath("//span[contains(text(),'nding in " +
                                 merchant.card[-4:] + "')]").click()
    driver.find_element_by_xpath(
        "//button[contains(text(),'Continue')]").click()
    driver.find_element_by_xpath(
        "//button[contains(text(),'Submit Payment')]").click()

    try:
        WebDriverWait(driver, 90).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH,
                 "//*[contains(text(),'Your payment was successful')]")))
    except TimeoutException:
        return Result.unverified

    return Result.success
Exemple #11
0
    log.info('Reading slot preferences from conf')
    slot_prefs = get_prefs_from_conf()
    log.info('Invoking Selenium Chrome webdriver')
    driver = webdriver.Chrome()
    log.info('Navigating to ' + config.BASE_URL)
    driver.get(config.BASE_URL)

    if args.force_login or not os.path.exists(config.PKL_PATH):
        # Login and capture Amazon session data...
        wait_for_auth(driver)
    else:
        # ...or load from storage
        load_session_data(driver)
        driver.refresh()
        if is_logged_in(driver):
            log.info('Successfully logged in via stored session data')
        else:
            log.error('Error logging in with stored session data')
            wait_for_auth(driver)
    # v-- Change this dynamically when more site configs exist
    site_config = config.WholeFoods
    # Navigate from BASE_URL to SLOT_URL
    site_config.Routes.SLOT_SELECT.navigate(driver)
    # Check for delivery slots
    slots = slots_available(driver, site_config, slot_prefs)
    if slots:
        annoy()
        alert('Delivery slots available. What do you need me for?', 'Sosumi')
    while not slots:
        log.info('No slots found :( waiting...')
Exemple #12
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.optimum.net/pay-bill/payment-options/')

    logged_in = utils.is_logged_in(driver,
                                   timeout=90,
                                   logged_out_element=(By.ID,
                                                       'loginPagePassword'),
                                   logged_in_element=(By.ID,
                                                      'otherAmountInput'))

    if not logged_in:
        try:  # if first run, fill in username. If subsequent run, username may already be filled in.
            driver.find_element_by_id('loginPageUsername').send_keys(
                merchant.usr)
        except ElementNotInteractableException:
            pass

        driver.find_element_by_id('loginPagePassword').send_keys(merchant.psw)
        driver.find_element_by_xpath(
            "//button[contains(text(),'Sign in to Optimum.net')]").click()
        WebDriverWait(driver, 90).until(
            expected_conditions.element_to_be_clickable(
                (By.ID, 'otherAmountInput')))

    cur_balance = driver.find_element_by_xpath(
        "//span[@class='payment--radio--bold ng-binding']").text
    LOGGER.info('Current Optimum balance is ' + cur_balance)

    if utils.str_to_cents(cur_balance) < 100:
        LOGGER.warning(
            'Optimum account balance is less than minimum $1 payment, will try again later.'
        )
        return Result.skipped
    elif utils.str_to_cents(cur_balance) < amount:
        LOGGER.info('Adjusting spend to ' + utils.str_to_cents(cur_balance) +
                    ' cents since current balance is less than ' + amount +
                    ' cents')
        amount = utils.str_to_cents(cur_balance)

    driver.find_element_by_id('otherAmountInput').send_keys(
        utils.cents_to_str(amount))  # Enter the amount
    driver.find_element_by_xpath(
        "//span[contains(text(),'Other amount')]/preceding-sibling::div"
    ).click()  # Select the radio button
    driver.find_element_by_xpath(
        "//div[contains(text(),'Payment Method')]/following-sibling::div"
    ).click()  # Open the selector dropdown box
    try:
        driver.find_element_by_xpath(
            "//span[contains(text(),'" + merchant.card +
            "')]").click()  # Select the payment method
    except common.exceptions.NoSuchElementException:
        LOGGER.error('Failed to find payment method with name ' +
                     merchant.card)
        return Result.failed

    button_str = driver.find_element_by_id('otpSubmit').get_attribute('value')
    expect_str = "Pay $" + utils.cents_to_str(
        amount) + " now with " + merchant.card

    if button_str == expect_str:
        driver.find_element_by_id('otpSubmit').click()
        LOGGER.info('Submitting purchase: ' + button_str)
    else:
        LOGGER.error('Failed to find valid pay button.')
        LOGGER.info('Detected: ' + button_str)
        LOGGER.info('Expected: ' + expect_str)
        return Result.failed

    # Check if the payment succeeded.
    try:
        WebDriverWait(driver, 90).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH, "//*[contains(text(),'Confirmation Number:')]")))
        LOGGER.info("Successful payment: " + driver.find_element_by_xpath(
            "//*[contains(text(),'Confirmation Number:')]").text)
        return Result.success
    except TimeoutException:
        # Check if there was an error, if so log the error.
        try:
            WebDriverWait(driver, 5).until(
                expected_conditions.presence_of_element_located(
                    (By.XPATH, "//*[contains(text(),'unable')]")))
            LOGGER.error("Failed payment: " + driver.find_element_by_xpath(
                "//*[contains(text(),'unable')]").text)
        except TimeoutException:
            return Result.unverified
        return Result.unverified
Exemple #13
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.amazon.com/asv/reload/order')

    logged_in = utils.is_logged_in(
        driver,
        timeout=30,
        logged_out_element=(
            By.XPATH, "//button[contains(text(),'Sign In to Continue')]"),
        logged_in_element=(By.XPATH, "//button[contains(text(),'Reload $')]"))

    if not logged_in:
        try:
            driver.find_element_by_xpath(
                "//button[contains(text(),'Sign In to Continue')]").click()
        except ElementClickInterceptedException:  # spinner blocking button
            time.sleep(3)
            driver.find_element_by_xpath(
                "//button[contains(text(),'Sign In to Continue')]").click()

        driver.find_element_by_id('ap_email').send_keys(merchant.usr)

        try:  # a/b tested new UI flow
            driver.find_element_by_id(
                'continue').click()  # if not exists, exception is raised
        except common.exceptions.NoSuchElementException:  # a/b tested old UI flow
            pass

        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.ID, 'ap_password')))
        driver.find_element_by_id('ap_password').send_keys(merchant.psw)
        driver.find_element_by_id('signInSubmit').click()

        try:  # OTP email validation
            WebDriverWait(driver, 3).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH, "//*[contains(text(),'One Time Password')]")))
            otp_flow = True
        except TimeoutException:
            otp_flow = False

        try:
            driver.find_element_by_xpath(
                "//*[contains(text(),'one-time pass')]").click()
            otp_flow = True
        except common.exceptions.NoSuchElementException:
            pass

        if otp_flow:
            driver.find_element_by_id('continue').click()

            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH, "//input")))
            sent_to_text = driver.find_element_by_xpath(
                "//*[contains(text(),'@')]").text
            LOGGER.info(sent_to_text)
            LOGGER.info('Enter OTP here:')
            otp = input()

            elem = driver.find_element_by_xpath("//input")
            elem.send_keys(otp)
            elem.send_keys(Keys.TAB)
            elem.send_keys(Keys.ENTER)

    WebDriverWait(driver, 30).until(
        expected_conditions.element_to_be_clickable(
            (By.ID, 'asv-manual-reload-amount')))
    driver.find_element_by_id('asv-manual-reload-amount').send_keys(
        utils.cents_to_str(amount))
    driver.find_element_by_xpath("//span[contains(text(),'ending in " +
                                 merchant.card[-4:] + "')]").click()
    driver.find_element_by_xpath("//button[contains(text(),'Reload $" +
                                 utils.cents_to_str(amount) + "')]").click()

    time.sleep(10)  # give page a chance to load
    if 'thank-you' not in driver.current_url:
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//input[@placeholder='ending in " +
                 merchant.card[-4:] + "']")))
        elem = driver.find_element_by_xpath(
            "//input[@placeholder='ending in " + merchant.card[-4:] + "']")
        elem.send_keys(merchant.card)
        elem.send_keys(Keys.TAB)
        elem.send_keys(Keys.ENTER)
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//button[contains(text(),'Reload $" +
                 utils.cents_to_str(amount) + "')]")))
        time.sleep(1)
        driver.find_element_by_xpath("//button[contains(text(),'Reload $" +
                                     utils.cents_to_str(amount) +
                                     "')]").click()
        time.sleep(10)  # give page a chance to load

    if 'thank-you' not in driver.current_url:
        return Result.unverified

    return Result.success
Exemple #14
0
def web_automation(driver, merchant, amount):
    driver.get(
        'https://jakehilborn.github.io/debbit/example-merchant/login.html')

    logged_in = utils.is_logged_in(driver,
                                   timeout=90,
                                   logged_out_element=(By.ID, 'password'),
                                   logged_in_element=(By.ID, 'submit-payment'))

    if not logged_in:
        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants

        try:  # some websites will have the username auto-filled in due to a previous login
            driver.find_element_by_id('username').send_keys(merchant.usr)
        except ElementNotInteractableException:
            pass

        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants
        driver.find_element_by_id('password').send_keys(merchant.usr)
        time.sleep(
            2
        )  # pause to let user watch what's happening - not necessary for real merchants
        driver.find_element_by_id('login').click()
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.ID, 'submit-payment')))

    cur_balance = driver.find_element_by_xpath(
        "//span[contains(text(), '$')]").text
    if utils.str_to_cents(cur_balance) == 0:
        LOGGER.error('example_merchant balance is zero, will try again later.')
        return Result.skipped
    elif utils.str_to_cents(cur_balance) < amount:
        amount = utils.str_to_cents(cur_balance)

    time.sleep(
        2
    )  # pause to let user watch what's happening - not necessary for real merchants
    driver.find_element_by_xpath("//*[contains(text(), 'card ending in " +
                                 merchant.card + "')]").click()
    time.sleep(
        2
    )  # pause to let user watch what's happening - not necessary for real merchants
    driver.find_element_by_id('amount').send_keys(utils.cents_to_str(amount))
    time.sleep(
        2
    )  # pause to let user watch what's happening - not necessary for real merchants
    driver.find_element_by_id('submit-payment').click()

    try:
        WebDriverWait(driver, 30).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH, "//*[contains(text(),'Thank you!')]")))
    except TimeoutException:
        return Result.unverified  # Purchase command was executed, yet we are unable to verify that it was successfully executed.
        # since debbit may have spent money but isn't sure, we log the error and stop any further payments for this merchant until the user intervenes

    time.sleep(
        5)  # sleep for a bit to show user that payment screen is reached
    return Result.success
def web_automation(driver, merchant, amount):
    driver.get('https://www.amazon.com/asv/reload/order')

    logged_in = utils.is_logged_in(
        driver,
        timeout=30,
        logged_out_element=(
            By.XPATH, "//button[contains(text(),'Sign In to Continue')]"),
        logged_in_element=(By.XPATH, "//button[starts-with(text(),'Reload')]"))

    time.sleep(1 + random.random() *
               2)  # slow down automation randomly to help avoid bot detection
    if not logged_in:
        try:
            driver.find_element_by_xpath(
                "//button[contains(text(),'Sign In to Continue')]").click()
            time.sleep(1 + random.random() * 2)
        except ElementClickInterceptedException:  # spinner blocking button
            time.sleep(3)
            driver.find_element_by_xpath(
                "//button[contains(text(),'Sign In to Continue')]").click()
            time.sleep(1 + random.random() * 2)

        WebDriverWait(driver, 30).until(
            utils.AnyExpectedCondition(
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'ap_email')),  # first time login
                expected_conditions.element_to_be_clickable(
                    (By.XPATH, "//*[contains(text(),'" + merchant.usr +
                     "')]"))  # username found on page
            ))

        if driver.find_elements_by_xpath("//*[contains(text(),'" +
                                         merchant.usr + "')]"):
            driver.find_element_by_xpath(
                "//*[contains(text(),'" + merchant.usr + "')]").click(
                )  # click username in case we're on the Switch Accounts page
            WebDriverWait(driver, 30).until(
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'signInSubmit')))
            time.sleep(1 + random.random() * 2)

        if driver.find_elements_by_id(
                'ap_email'
        ):  # if first run, fill in email. If subsequent run, nothing to fill in
            driver.find_element_by_id('ap_email').send_keys(merchant.usr)
            time.sleep(1 + random.random() * 2)

        if driver.find_elements_by_id('continue'):  # a/b tested new UI flow
            driver.find_element_by_id('continue').click()
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'ap_password')))
            time.sleep(1 + random.random() * 2)

        driver.find_element_by_id('ap_password').send_keys(merchant.psw)
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id('signInSubmit').click()
        time.sleep(1 + random.random() * 2)

        handle_anti_automation_challenge(driver, merchant)

        try:  # OTP text message
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH,
                     "//*[contains(text(),'phone number ending in')]")))
            if driver.find_elements_by_id('auth-mfa-remember-device'):
                driver.find_element_by_id('auth-mfa-remember-device').click()

            sent_to_text = driver.find_element_by_xpath(
                "//*[contains(text(),'phone number ending in')]").text
            LOGGER.info(sent_to_text)
            LOGGER.info('Enter OTP here:')
            otp = input()

            driver.find_element_by_id('auth-mfa-otpcode').send_keys(otp)
            time.sleep(1 + random.random() * 2)
            driver.find_element_by_id('auth-signin-button').click()
            time.sleep(1 + random.random() * 2)
        except TimeoutException:
            pass

        try:  # OTP email validation
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH, "//*[contains(text(),'One Time Pass')]")))
            otp_email = True
        except TimeoutException:
            otp_email = False

        try:
            driver.find_element_by_xpath(
                "//*[contains(text(),'one-time pass')]").click()
            time.sleep(1 + random.random() * 2)
            otp_email = True
        except common.exceptions.NoSuchElementException:
            pass

        if otp_email:
            if driver.find_elements_by_id('continue'):
                driver.find_element_by_id('continue').click()
                time.sleep(1 + random.random() * 2)

            handle_anti_automation_challenge(driver, merchant)

            try:  # User may have manually advanced to gift card screen or stopped at OTP input. Handle OTP input if on OTP screen.
                WebDriverWait(driver, 5).until(
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//*[contains(text(),'Enter OTP')]")))
                sent_to_text = driver.find_element_by_xpath(
                    "//*[contains(text(),'@')]").text
                LOGGER.info(sent_to_text)
                LOGGER.info('Enter OTP here:')
                otp = input()

                elem = driver.find_element_by_xpath("//input")
                elem.send_keys(otp)
                time.sleep(1 + random.random() * 2)
                elem.send_keys(Keys.TAB)
                time.sleep(1 + random.random() * 2)
                elem.send_keys(Keys.ENTER)
                time.sleep(1 + random.random() * 2)
            except TimeoutException:
                pass

        try:
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH, "//*[contains(text(),'Not now')]")))
            driver.find_element_by_xpath(
                "//*[contains(text(),'Not now')]").click()
            time.sleep(1 + random.random() * 2)
        except TimeoutException:  # add mobile number page
            pass

    WebDriverWait(driver, 30).until(
        expected_conditions.element_to_be_clickable(
            (By.ID, 'asv-manual-reload-amount')))
    driver.find_element_by_id('asv-manual-reload-amount').send_keys(
        utils.cents_to_str(amount))
    time.sleep(1 + random.random() * 2)

    for element in driver.find_elements_by_xpath(
            "//span[contains(text(),'ending in " + merchant.card[-4:] + "')]"):
        try:  # Amazon has redundant non-clickable elements. This will try each one until one works.
            element.click()
            time.sleep(1 + random.random() * 2)
            break
        except WebDriverException:
            pass

    driver.find_element_by_xpath(
        "//button[starts-with(text(),'Reload') and contains(text(),'" +
        utils.cents_to_str(amount) + "')]").click()
    time.sleep(1 + random.random() * 2)

    time.sleep(10)  # give page a chance to load
    if 'thank-you' not in driver.current_url:
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//input[@placeholder='ending in " +
                 merchant.card[-4:] + "']")))
        elem = driver.find_element_by_xpath(
            "//input[@placeholder='ending in " + merchant.card[-4:] + "']")
        time.sleep(1 + random.random() * 2)
        elem.send_keys(merchant.card)
        time.sleep(1 + random.random() * 2)
        elem.send_keys(Keys.TAB)
        time.sleep(1 + random.random() * 2)
        elem.send_keys(Keys.ENTER)
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//button[contains(text(),'Reload $" +
                 utils.cents_to_str(amount) + "')]")))
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_xpath(
            "//button[starts-with(text(),'Reload') and contains(text(),'" +
            utils.cents_to_str(amount) + "')]").click()
        time.sleep(10)  # give page a chance to load

    if 'thank-you' not in driver.current_url:
        return Result.unverified

    return Result.success