Пример #1
0
def handle_mfa_code_flow(driver):
    if driver.find_elements_by_id('submitDest'):  # MFA flow
        LOGGER.info(
            'One time multi-factor auth required. This will not happen after the first debbit run.'
        )
        try:
            multi_mfa_options = False
            try:
                WebDriverWait(driver, 0).until(
                    expected_conditions.element_to_be_clickable(
                        (By.ID, "submitDest")))
            except TimeoutException:  # The Send code button is not clickable. This means there are multiple MFA options. Ask user which one to use.
                multi_mfa_options = True

            if multi_mfa_options:
                mfa_options = {}
                for i in range(1, 10):
                    if driver.find_elements_by_id('m' + str(i) + 'label'):
                        mfa_options[i] = driver.find_element_by_id(
                            'm' + str(i) + 'label').text
                LOGGER.info('')
                LOGGER.info('Choose a multi-factor authentication option.')
                for k, v in mfa_options.items():
                    LOGGER.info('    ' + str(k) + ' - ' + v)
                LOGGER.info('Type a number 1-9 and then hit enter: ')
                user_mfa_choice_input = input()  # TODO put timeout around this
                user_mfa_choice_index = ''.join([
                    c for c in user_mfa_choice_input if c.isdigit()
                ])  # sanitize input to remove all non digit characters
                driver.find_element_by_id('m' + user_mfa_choice_index +
                                          'label').click()
                time.sleep(1 + random.random() * 2)

            time.sleep(1 + random.random() * 2)
            driver.find_element_by_id("submitDest").click()
            WebDriverWait(driver, 20).until(
                expected_conditions.element_to_be_clickable(
                    (By.ID, "codeValue")))
            LOGGER.info('Enter OTP here: ')
            otp = input()  # TODO put timeout around this

            elem = driver.find_element_by_id("codeValue")
            elem.send_keys(otp)
            time.sleep(1 + random.random() * 2)
            driver.find_element_by_xpath("//*[contains(@id,'ubmit')]").click(
            )  # submit or Submit button

            WebDriverWait(driver, 120).until(
                utils.AnyExpectedCondition(
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH,
                         "//button[contains(text(),'Make a payment')]"))))
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            pass  # User may have intervened by clicking around in the UI, allow failures to be ignored
Пример #2
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.amazon.com/gp/product/B086KKT3RX')

    WebDriverWait(driver, 90).until(
        expected_conditions.element_to_be_clickable(
            (By.ID, "gcui-asv-reload-buynow-button")))
    for i in range(300):
        if driver.find_element_by_id(
                "gcui-asv-reload-buynow-button"
        ).text == 'Buy Now':  # wait for 'Loading...' text to turn into 'Buy Now'
            break
        time.sleep(0.1)

    time.sleep(1 + random.random() *
               2)  # slow down automation randomly to help avoid bot detection
    driver.find_element_by_id('gcui-asv-reload-form-custom-amount').send_keys(
        utils.cents_to_str(amount))
    time.sleep(1 + random.random() *
               2)  # slow down automation randomly to help avoid bot detection
    driver.find_element_by_id("gcui-asv-reload-buynow-button").click()

    WebDriverWait(driver, 90).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 login page
            # Already logged in
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//*[contains(text(),'Order Summary')]")),  # Checkout page
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//*[contains(text(),'a payment method')]"
                 ))  # Another version of the checkout page
        ))

    if not driver.find_elements_by_xpath(
            "//*[contains(text(),'Order Summary')]"
    ) and not driver.find_elements_by_xpath(
            "//*[contains(text(),'a payment method')]"
    ):  # Not in checkout, so we did not auto login. Finish login flow.
        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
            try:
                driver.find_element_by_id('ap_email').send_keys(merchant.usr)
                time.sleep(1 + random.random() * 2)
            except ElementNotInteractableException:  # Sometimes this field is prefilled with Firstname Lastname and does not accept input
                pass

        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)

        if driver.find_elements_by_name('rememberMe'):
            time.sleep(1 + random.random() * 2)
            driver.find_element_by_name('rememberMe').click()

        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:  # Push Notification / Email MFA
            WebDriverWait(driver, 5).until(
                expected_conditions.element_to_be_clickable(
                    (By.XPATH,
                     "//*[contains(text(),'approve the notification')]")))
            if driver.find_elements_by_xpath(
                    "//*[contains(text(),'approve the notification')]"):
                LOGGER.info('\n')
                LOGGER.info(
                    'Please approve the Amazon login notification sent to your email or phone. Debbit will wait up to 3 minutes.'
                )
                for i in range(
                        180
                ):  # Wait for up to 3 minutes for user to approve login notification
                    if not driver.find_elements_by_xpath(
                            "//*[contains(text(),'approve the notification')]"
                    ):
                        break
                    time.sleep(1)
        except TimeoutException:
            pass

        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

    # Now expecting to be on checkout page with debit card selection present
    WebDriverWait(driver, 30).until(
        utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//*[contains(text(),'Order Summary')]")),  # Checkout page
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//*[contains(text(),'a payment method')]"
                 ))  # Another version of the checkout page
        ))

    if driver.find_elements_by_id('payChangeButtonId'):  # expand list of cards
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id('payChangeButtonId').click()
        WebDriverWait(driver, 10).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//span[contains(text(),'ending in " +
                 merchant.card[-4:] + "')]")))

    if driver.find_elements_by_id(
            'payment-change-link'
    ):  # expand list of cards if prior element did not exist
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id('payment-change-link').click()
        WebDriverWait(driver, 10).until(
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//span[contains(text(),'ending in " +
                 merchant.card[-4:] + "')]")))

    card_selected = False
    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.
            time.sleep(1 + random.random() * 2)
            element.click()
            card_selected = True
            break
        except WebDriverException:
            pass

    if not card_selected:
        raise Exception(
            'Unable to find or unable to click on card that has last 4 digits matching config file card.'
        )

    if driver.find_elements_by_id('orderSummaryPrimaryActionBtn'):
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id('orderSummaryPrimaryActionBtn').click(
        )  # Click "Use this payment method" button
    else:  # Find Continue button. There are also non clickable spans with 'Continue' in them so try all of them until one works.
        for element in driver.find_elements_by_xpath(
                "//span[contains(text(),'Continue')]"):
            try:
                time.sleep(1 + random.random() * 2)
                element.find_element_by_xpath('../..').click(
                )  # the grandparent element of the text is the clickable Continue button
                break
            except Exception:
                pass

    WebDriverWait(driver, 10).until(
        utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable(
                (By.ID, 'submitOrderButtonId')
            ),  # "Place your order" button showing, card ready to be used
            expected_conditions.element_to_be_clickable(
                (By.ID, 'placeYourOrder')
            ),  # Other checkout page "Place your order" button showing, card ready to be used
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//input[@placeholder='ending in " +
                 merchant.card[-4:] + "']"))  # Verify card flow
        ))

    if driver.find_elements_by_xpath("//input[@placeholder='ending in " +
                                     merchant.card[-4:] +
                                     "']"):  # Verify card flow
        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)

        time.sleep(10 + random.random() * 2)
        if driver.find_elements_by_id('orderSummaryPrimaryActionBtn'):
            driver.find_element_by_id('orderSummaryPrimaryActionBtn').click(
            )  # Click "Use this payment method" button
        else:  # Find Continue text, the grandparent element of the text is the clickable Continue button
            driver.find_element_by_xpath(
                "//span[contains(text(),'Continue')]").find_element_by_xpath(
                    '../..').click()

        WebDriverWait(driver, 10).until(
            utils.AnyExpectedCondition(
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'submitOrderButtonId')
                ),  # "Place your order" button showing, card ready to be used
                expected_conditions.element_to_be_clickable(
                    (By.ID, 'placeYourOrder')
                ),  # Other checkout page "Place your order" button showing, card ready to be used
            ))

    time.sleep(1 + random.random() * 2)

    if not is_order_total_correct(driver, amount):
        return Result.unverified

    if driver.find_elements_by_id('submitOrderButtonId'):
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id(
            'submitOrderButtonId').click()  # Click "Place your order" button
    else:
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_id('placeYourOrder').click(
        )  # Other checkout page click "Place your order" button

    try:
        WebDriverWait(driver, 30).until(
            expected_conditions.element_to_be_clickable((
                By.XPATH,
                "//*[contains(text(), 'your order has been placed') or contains(text(),'Order placed')]"
            )))
    except TimeoutException:
        LOGGER.error(
            'Clicked "Place your order" button, but unable to confirm if order was successful.'
        )
        return Result.unverified

    if driver.find_elements_by_xpath(
            "//*[contains(text(), 'your order has been placed') or contains(text(),'Order placed')]"
    ):
        return Result.success
    else:
        LOGGER.error(
            'Clicked "Place your order" button, but unable to confirm if order was successful.'
        )
        return Result.unverified
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
Пример #4
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.att.com/my/#/passthrough/overview')

    # Wait until login screen, promotion pop-up, or account dashboard shows.
    WebDriverWait(driver, 120).until(
        utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable(
                (By.NAME, "password")),  # logged out
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//*[contains(@id,'ancel')]"
                 )),  # mfa flow identified by cancel button
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//img[contains(@src,'btnNoThanks')]")),  # logged in
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//button[contains(text(),'Make a payment')]"))  # logged in
        ))

    handle_mfa_code_flow(driver)

    time.sleep(
        1 + random.random() * 2
    )  # AT&T is using bot detection software, slow down the automation a bit to help avoid detection
    if driver.find_elements_by_name(
            'password'):  # password field found, need to log in
        try:
            driver.find_element_by_id('userID').send_keys(merchant.usr)
            time.sleep(1 + random.random() * 2)
        except common.exceptions.NoSuchElementException:
            pass

        driver.find_element_by_name('password').send_keys(merchant.psw)
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_xpath(
            "//button[contains(text(),'Sign in')]").click()

        try:
            # Wait for potential promotions screen, regular account overview, or OTP flow
            WebDriverWait(driver, 120).until(
                utils.AnyExpectedCondition(
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH,
                         "//button[contains(text(),'Make a payment')]")),
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//*[contains(@id,'ancel')]"
                         ))  # mfa flow identified by cancel button
                ))
        except TimeoutException:
            pass  # Try continuing to the makePayment page just in case log in worked, but timeout failed

        time.sleep(1 + random.random() * 2)
        handle_mfa_code_flow(driver)

    driver.get("https://www.att.com/my/#/makePayment")

    WebDriverWait(driver, 20).until(
        expected_conditions.element_to_be_clickable(
            (By.ID, "MAP_Amount_TextField")))
    time.sleep(1 + random.random() * 2)

    cur_balance_html_text = driver.find_element_by_xpath(
        "//span[contains(text(), 'Balance due')]").text
    cur_balance = cur_balance_html_text.split('$')[1]
    if utils.str_to_cents(cur_balance) == 0:
        LOGGER.warning('AT&T 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)

    elem = driver.find_element_by_id('MAP_Amount_TextField')
    elem.clear()
    time.sleep(1 + random.random() * 2)
    elem.send_keys(utils.cents_to_str(amount))
    time.sleep(1 + random.random() * 2)
    if driver.find_elements_by_xpath(
            "//*[contains(text(),'Debit or credit card')]"):
        driver.find_element_by_xpath(
            "//*[contains(text(),'Debit or credit card')]").click()
        time.sleep(1 + random.random() * 2)
    driver.find_element_by_xpath("//input[@value='" + merchant.card +
                                 "']").click()
    time.sleep(1 + random.random() * 2)
    driver.find_element_by_xpath("//*[contains(text(),'Pay $" +
                                 utils.cents_to_str(amount) + "')]").click()
    time.sleep(1 + random.random() * 2)

    try:
        WebDriverWait(driver, 120).until(
            utils.AnyExpectedCondition(
                expected_conditions.presence_of_element_located(
                    (By.XPATH, "//*[contains(text(),'We got your $" +
                     utils.cents_to_str(amount) + " payment')]")),
                expected_conditions.presence_of_element_located((
                    By.XPATH,
                    "//*[contains(text(),'multiple payments for the same amount')]"
                ))))

        if driver.find_elements_by_xpath(
                "//*[contains(text(),'multiple payments for the same amount')]"
        ):
            LOGGER.info(
                "Duplicate payment amount not accepted within 24 hours. Trying again later. Please use a larger range between amount_min and amount_max in config.txt for att_bill_pay to avoid duplicate payment amount scenarios."
            )
            return Result.skipped
        elif driver.find_elements_by_xpath("//*[text()='We got your $ + " +
                                           utils.cents_to_str(amount) +
                                           " payment']"):
            return Result.success
        else:
            return Result.unverified

    except (KeyboardInterrupt, SystemExit):
        raise
    except Exception:
        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

    return Result.success
Пример #5
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.att.com/my/#/passthrough/overview')

    # Wait until login screen, promotion pop-up, or account dashboard shows.
    WebDriverWait(driver, 120).until(utils.AnyExpectedCondition(
        expected_conditions.element_to_be_clickable((By.ID, "password")),
        expected_conditions.element_to_be_clickable((By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
        expected_conditions.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Make a payment')]")),
    ))

    if not driver.find_elements_by_id('password'):  # password field found, need to log in
        try:
            driver.find_element_by_id('userName').send_keys(merchant.usr)
        except common.exceptions.ElementNotInteractableException:
            pass
        try:
            driver.find_element_by_xpath("//a[@value='" + merchant.usr + "']").click()
        except common.exceptions.NoSuchElementException:
            pass

        driver.find_element_by_id('password').send_keys(merchant.psw)
        driver.find_element_by_xpath("//button[contains(@id,'loginButton')]").click()

        # Wait for potential promotions screen, regular account overview, or OTP flow
        WebDriverWait(driver, 30).until(utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable((By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
            expected_conditions.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Make a payment')]")),
            expected_conditions.element_to_be_clickable((By.NAME, "Send code"))
        ))

        try:  # OTP text validation
            driver.find_element_by_name("Send code").click()
            WebDriverWait(driver, 20).until(expected_conditions.element_to_be_clickable((By.ID, "verificationCodeInput")))
            sent_to_text = driver.find_element_by_xpath("//*[contains(text(),'We sent it to')]").text.strip()
            LOGGER.info(sent_to_text)
            LOGGER.info('Enter OTP here: ')
            otp = input()

            elem = driver.find_element_by_id("verificationCodeInput")
            elem.send_keys(otp)
            elem.send_keys(Keys.ENTER)
        except common.exceptions.NoSuchElementException:
            pass

        # Wait for potential promotions screen or regular account overview
        WebDriverWait(driver, 30).until(utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable((By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
            expected_conditions.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Make a payment')]"))
        ))

        try:  # Dismiss promotions screen if it appeared
            driver.find_element_by_xpath("//*[contains(@src,'btnNoThanks')]").click()
            WebDriverWait(driver, 20).until(expected_conditions.element_to_be_clickable((By.XPATH, "//*[contains(text(),'Make a payment')]")))
        except common.exceptions.NoSuchElementException:
            pass

    driver.get("https://www.att.com/my/#/makePayment")

    # Enter amount and select payment card
    WebDriverWait(driver, 20).until(expected_conditions.element_to_be_clickable((By.ID, "pmtAmount0")))
    elem = driver.find_element_by_id('pmtAmount0')
    elem.clear()
    elem.send_keys(utils.cents_to_str(amount))
    elem = driver.find_element_by_id("paymentMethod0")
    before_first_payment_card = "Select Payment Method"
    after_last_payment_card = "New checking / savings account"
    while elem.get_attribute("value").lower() != before_first_payment_card.lower():
        elem.send_keys(Keys.UP)
    while elem.get_attribute("value").lower() != merchant.card.lower() and elem.get_attribute("value").lower() != after_last_payment_card.lower():
        elem.send_keys(Keys.DOWN)
    if elem.get_attribute("value").lower() == after_last_payment_card.lower():
        raise Exception("Payment method " + merchant.card + " not found in list of saved payment methods")

    # Continue
    elem.send_keys(Keys.ENTER)
    try:
        WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, "//html/body/div[contains(@class,'modalwrapper active')]//p[contains(text(),'paying more than the amount due')]")))
        driver.find_element_by_xpath("//html/body/div[contains(@class,'modalwrapper active')]//button[text()='OK']").click()
    except TimeoutException:
        pass

    # Submit
    WebDriverWait(driver, 20).until(expected_conditions.element_to_be_clickable((By.XPATH, "//button[text()='Submit']")))
    WebDriverWait(driver, 20).until(expected_conditions.invisibility_of_element_located((By.ID, "loaderOverlay")))
    time.sleep(2)
    driver.find_element_by_xpath("//button[text()='Submit']").click()

    try:
        WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, "//*[contains(text(),'Thank you for your payment')]")))
        WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, "//*[text()='$" + utils.cents_to_str(amount) + "']")))
    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

    return Result.success
Пример #6
0
def web_automation(driver, merchant, amount):
    driver.get('https://www.att.com/my/#/passthrough/overview')

    # Wait until login screen, promotion pop-up, or account dashboard shows.
    WebDriverWait(driver, 120).until(
        utils.AnyExpectedCondition(
            expected_conditions.element_to_be_clickable(
                (By.NAME, "password")),  # logged out
            expected_conditions.element_to_be_clickable(
                (By.XPATH, "//*[contains(@id,'ancel')]"
                 )),  # mfa flow identified by cancel button
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//img[contains(@src,'btnNoThanks')]")),  # logged in
            expected_conditions.element_to_be_clickable(
                (By.XPATH,
                 "//button[contains(text(),'Make a payment')]"))  # logged in
        ))

    handle_mfa_code_flow(driver)

    time.sleep(
        1 + random.random() * 2
    )  # AT&T is using bot detection software, slow down the automation a bit to help avoid detection
    if driver.find_elements_by_name(
            'password'):  # password field found, need to log in
        try:
            driver.find_element_by_id('userID').send_keys(merchant.usr)
            time.sleep(1 + random.random() * 2)
        except common.exceptions.NoSuchElementException:
            pass

        driver.find_element_by_name('password').send_keys(merchant.psw)
        time.sleep(1 + random.random() * 2)
        driver.find_element_by_xpath(
            "//button[contains(text(),'Sign in')]").click()

        try:
            # Wait for potential promotions screen, regular account overview, or OTP flow
            WebDriverWait(driver, 120).until(
                utils.AnyExpectedCondition(
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//img[contains(@src,'btnNoThanks')]")),
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH,
                         "//button[contains(text(),'Make a payment')]")),
                    expected_conditions.element_to_be_clickable(
                        (By.XPATH, "//*[contains(@id,'ancel')]"
                         ))  # mfa flow identified by cancel button
                ))
        except TimeoutException:
            pass  # Try continuing to the makePayment page just in case log in worked, but timeout failed

        time.sleep(1 + random.random() * 2)
        handle_mfa_code_flow(driver)

    driver.get("https://www.att.com/my/#/makePayment")

    # Enter amount and select payment card
    WebDriverWait(driver, 20).until(
        expected_conditions.element_to_be_clickable((By.ID, "pmtAmount0")))
    time.sleep(1 + random.random() * 2)
    elem = driver.find_element_by_id('pmtAmount0')
    elem.clear()
    time.sleep(1 + random.random() * 2)
    elem.send_keys(utils.cents_to_str(amount))
    time.sleep(1 + random.random() * 2)
    elem = driver.find_element_by_id("paymentMethod0")
    before_first_payment_card = "Select Payment Method"
    after_last_payment_card = "New checking / savings account"
    while elem.get_attribute(
            "value").lower() != before_first_payment_card.lower():
        elem.send_keys(Keys.UP)
        time.sleep(1 + random.random())
    while elem.get_attribute(
            "value").lower() != merchant.card.lower() and elem.get_attribute(
                "value").lower() != after_last_payment_card.lower():
        elem.send_keys(Keys.DOWN)
        time.sleep(1 + random.random())
    if elem.get_attribute("value").lower() == after_last_payment_card.lower():
        raise Exception("Payment method " + merchant.card +
                        " not found in list of saved payment methods")

    # Continue
    elem.send_keys(Keys.ENTER)
    time.sleep(1 + random.random() * 2)
    try:
        WebDriverWait(driver, 20).until(
            expected_conditions.presence_of_element_located((
                By.XPATH,
                "//html/body/div[contains(@class,'modalwrapper active')]//p[contains(text(),'paying more than the amount due')]"
            )))
        driver.find_element_by_xpath(
            "//html/body/div[contains(@class,'modalwrapper active')]//button[text()='OK']"
        ).click()
        time.sleep(1 + random.random() * 2)
    except TimeoutException:
        pass

    # Submit
    WebDriverWait(driver, 20).until(
        expected_conditions.element_to_be_clickable(
            (By.XPATH, "//button[text()='Submit']")))
    WebDriverWait(driver, 20).until(
        expected_conditions.invisibility_of_element_located(
            (By.ID, "loaderOverlay")))
    time.sleep(2 + random.random())
    driver.find_element_by_xpath("//button[text()='Submit']").click()

    try:
        WebDriverWait(driver, 120).until(
            utils.AnyExpectedCondition(
                expected_conditions.presence_of_element_located(
                    (By.XPATH,
                     "//*[contains(text(),'Thank you for your payment')]")),
                expected_conditions.presence_of_element_located(
                    (By.XPATH,
                     "//*[contains(text(),'payment was unsuccessful')]"))))

        if driver.find_elements_by_xpath(
                "//*[contains(text(),'multiple payments')]"):
            return Result.skipped  # att does not allow payments of the same dollar amount within 24 hours, skip this purchase and try again 24 hours later
        elif driver.find_elements_by_xpath("//*[text()='$" +
                                           utils.cents_to_str(amount) + "']"):
            return Result.success
        else:
            return Result.unverified

    except (KeyboardInterrupt, SystemExit):
        raise
    except Exception:
        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

    return Result.success