Skip to content

Commit

Permalink
Add support for email verification code (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
simao-silva committed May 12, 2024
1 parent bfdfa01 commit 5b53751
Showing 1 changed file with 57 additions and 16 deletions.
73 changes: 57 additions & 16 deletions renew.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ def get_credentials():
return email, password


def validate_otp(code):
valid = True

if len(code) != 6:
exit_with_error(message="Invalid email verification code. The code must have 6 digits. Exiting.")
valid = False
if otp_code.isnumeric() is False:
exit_with_error("Email verification code must be numeric. Exiting.")
valid = False

return valid

def validate_2fa(code):
if len(code) != 16 or code.isalnum() is False:
exit_with_error(message="Invalid 2FA key. Key must have 16 alphanumeric characters. Exiting.")
return False
return True

if __name__ == "__main__":
LOGIN_URL = "https://www.noip.com/login?ref_url=console"
HOST_URL = "https://my.noip.com/dynamic-dns"
Expand Down Expand Up @@ -126,32 +144,55 @@ def get_credentials():
except TimeoutException:
exit_with_error(message="Could not do post login action. Exiting.")

# Check if login has 2FA enabled
# Check if login has 2FA enabled and handle it
if browser.current_url.find("2fa") > -1:
totp_secret = os.getenv("NO_IP_TOTP_KEY", "")
if len(totp_secret) == 0:
totp_secret = str(input("Enter 2FA key: ")).replace("\n", "")

try:
totp_input = WebDriverWait(browser, 10).until(lambda browser: browser.find_element(by=By.ID, value="challenge_code"))
except TimeoutException:
exit_with_error(message="2FA input not found within the specified timeout.")

totp = pyotp.TOTP(totp_secret)

# Wait for submit button to ensure page is loaded
try:
WebDriverWait(driver=browser, timeout=60, poll_frequency=3).until(expected_conditions.element_to_be_clickable((By.NAME, "submit")))
submit_button = browser.find_elements(By.NAME, "submit")
if len(submit_button) > 0:
totp_input.send_keys(totp.now())
submit_button[0].click()
else:
if len(submit_button) < 1:
exit_with_error(message="2FA submit button not found. Exiting.")
except TimeoutException:
exit_with_error(message="2FA submit button not found within the specified timeout.")
exit_with_error(message="2FA page did not load within the specified timeout. Exiting.")
except NoSuchElementException:
exit_with_error(message="2FA submit button not found. Exiting.")

# Find if account has 2FA enabled or if is relying on email verification code
CODE_METHOD = None
try:
code_form = browser.find_element(by=By.ID, value="otp-input")
CODE_METHOD = "email"
except NoSuchElementException:
try:
code_form = browser.find_element(by=By.ID, value="challenge_code")
CODE_METHOD = "app"
except NoSuchElementException:
exit_with_error(message="2FA/Email code input not found. Exiting.")

# Account has email verification code
if CODE_METHOD == "email":
otp_code = str(input("Enter OTP code: ")).replace("\n", "")
if validate_otp(otp_code):
code_inputs = code_form.find_elements(by=By.TAG_NAME, value="input")
if len(code_inputs) == 6:
for i in range(len(code_inputs)):
code_inputs[i].send_keys(otp_code[i])
else:
exit_with_error(message="Email code input not found. Exiting.")

# Account has 2FA code
elif CODE_METHOD == "app":
totp_secret = os.getenv("NO_IP_TOTP_KEY", "")
if len(totp_secret) == 0:
totp_secret = str(input("Enter 2FA key: ")).replace("\n", "")
if validate_2fa(totp_secret):
totp = pyotp.TOTP(totp_secret)
code_form.send_keys(totp.now())

# Click submit button
submit_button[0].click()

# Wait for account dashboard to load
try:
WebDriverWait(driver=browser, timeout=120, poll_frequency=3).until(expected_conditions.visibility_of_element_located((By.ID, "dashboard-nav")))
Expand Down

0 comments on commit 5b53751

Please sign in to comment.