def send_user_activation_token(db: DatabaseHandler, email: str, activation_link: str) -> None: """Prepare for activation by emailing the activation token.""" email = decode_object_from_bytes_if_needed(email) activation_link = decode_object_from_bytes_if_needed(activation_link) # Check if user exists try: user = user_info(db=db, email=email) full_name = user.full_name() except Exception as ex: log.warning("Unable to fetch user profile for user '%s': %s" % (email, str(ex),)) full_name = 'Nonexistent user' # If user was not found, send an email to a random address anyway to avoid timing attack full_activation_link = _generate_user_activation_token(db=db, email=email, activation_link=activation_link) if not full_activation_link: log.warning("Unable to generate full activation link for email '%s'" % email) email = '*****@*****.**' full_activation_link = 'activation link' message = AuthActivationNeededMessage( to=email, full_name=full_name, activation_url=full_activation_link, ) if not send_email(message): raise McAuthRegisterException('The user was created, but I was unable to send you an activation email.')
def send_password_reset_token(db: DatabaseHandler, email: str, password_reset_link: str) -> None: """Prepare for password reset by emailing the password reset token.""" email = decode_object_from_bytes_if_needed(email) password_reset_link = decode_object_from_bytes_if_needed(password_reset_link) # Check if user exists try: user = user_info(db=db, email=email) full_name = user.full_name() except Exception as ex: log.warning("Unable to fetch user profile for user '%s': %s" % (email, str(ex),)) full_name = 'Nonexistent user' # If user was not found, send an email to a random address anyway to avoid timing attack full_password_reset_link = _generate_password_reset_token( db=db, email=email, password_reset_link=password_reset_link, ) if not full_password_reset_link: log.warning("Unable to generate full password reset link for email '%s'" % email) email = '*****@*****.**' full_password_reset_link = 'password reset link' message = AuthResetPasswordMessage(to=email, full_name=full_name, password_reset_url=full_password_reset_link) if not send_email(message): raise McAuthResetPasswordException('Unable to send password reset email.')
def test_send_mail(self): message = Message( to='*****@*****.**', cc='*****@*****.**', bcc='*****@*****.**', subject='Hello!', text_body='Text message 𝖜𝖎𝖙𝖍 𝖘𝖔𝖒𝖊 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 𝖈𝖍𝖆𝖗𝖆𝖈𝖙𝖊𝖗𝖘.', html_body='<strong>HTML message 𝖜𝖎𝖙𝖍 𝖘𝖔𝖒𝖊 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 𝖈𝖍𝖆𝖗𝖆𝖈𝖙𝖊𝖗𝖘.</strong>', ) assert send_email(message)
def change_password(db: DatabaseHandler, email: str, new_password: str, new_password_repeat: str, do_not_inform_via_email: bool = False) -> None: """Change user's password.""" email = decode_object_from_bytes_if_needed(email) new_password = decode_object_from_bytes_if_needed(new_password) new_password_repeat = decode_object_from_bytes_if_needed(new_password_repeat) if isinstance(do_not_inform_via_email, bytes): do_not_inform_via_email = decode_object_from_bytes_if_needed(do_not_inform_via_email) do_not_inform_via_email = bool(int(do_not_inform_via_email)) # Check if user exists try: user = user_info(db=db, email=email) except Exception: raise McAuthChangePasswordException('User with email address "%s" does not exist.' % email) password_validation_message = validate_new_password(email=email, password=new_password, password_repeat=new_password_repeat) if password_validation_message: raise McAuthChangePasswordException("Unable to change password: %s" % password_validation_message) # Hash + validate the password try: password_new_hash = generate_secure_hash(password=new_password) except Exception as ex: raise McAuthChangePasswordException("Unable to hash a new password: %s" % str(ex)) if not password_new_hash: raise McAuthChangePasswordException("Generated password hash is empty.") # Set the password hash db.query(""" UPDATE auth_users SET password_hash = %(password_hash)s, active = TRUE WHERE email = %(email)s """, { 'email': email, 'password_hash': password_new_hash, }) if not do_not_inform_via_email: message = AuthPasswordChangedMessage(to=email, full_name=user.full_name()) if not send_email(message): raise McAuthChangePasswordException( 'The password has been changed, but I was unable to send an email notifying you about the change.' )
def regenerate_api_key(db: DatabaseHandler, email: str) -> None: """Regenerate API key -- creates new non-IP limited API key, removes all IP-limited API keys.""" email = decode_object_from_bytes_if_needed(email) if not email: raise McAuthProfileException('Email address is empty.') # Check if user exists try: user = user_info(db=db, email=email) except Exception as _: raise McAuthProfileException( "User with email address '%s' does not exist." % email) db.begin() # Purge all IP-limited API keys db.query( """ DELETE FROM auth_user_api_keys WHERE ip_address IS NOT NULL AND auth_users_id = ( SELECT auth_users_id FROM auth_users WHERE email = %(email)s ) """, {'email': email}) # Regenerate non-IP limited API key db.query( """ UPDATE auth_user_api_keys -- DEFAULT points to a generation function SET api_key = DEFAULT WHERE ip_address IS NULL AND auth_users_id = ( SELECT auth_users_id FROM auth_users WHERE email = %(email)s ) """, {'email': email}) message = AuthAPIKeyResetMessage(to=email, full_name=user.full_name()) if not send_email(message): db.rollback() raise McAuthProfileException( "Unable to send email about reset API key.") db.commit()
def regenerate_api_key(db: DatabaseHandler, email: str) -> None: """Regenerate API key -- creates new non-IP limited API key, removes all IP-limited API keys.""" email = decode_object_from_bytes_if_needed(email) if not email: raise McAuthProfileException('Email address is empty.') # Check if user exists try: user = user_info(db=db, email=email) except Exception: raise McAuthProfileException( "User with email address '%s' does not exist." % email) db.begin() # Purge all API keys db.query( """ DELETE FROM auth_user_api_keys WHERE auth_users_id = %(auth_users_id)s """, {'auth_users_id': user.user_id()}) # Regenerate non-IP limited API key db.query( """ INSERT INTO auth_user_api_keys ( auth_users_id, api_key, ip_address ) VALUES ( %(auth_users_id)s, -- DEFAULT points to a generation function DEFAULT, NULL ) """, {'auth_users_id': user.user_id()}) message = AuthAPIKeyResetMessage(to=email, full_name=user.full_name()) if not send_email(message): db.rollback() raise McAuthProfileException( "Unable to send email about reset API key.") db.commit()
def regenerate_api_key(db: DatabaseHandler, email: str) -> None: """Regenerate API key -- creates new non-IP limited API key, removes all IP-limited API keys.""" email = decode_object_from_bytes_if_needed(email) if not email: raise McAuthProfileException('Email address is empty.') # Check if user exists try: user = user_info(db=db, email=email) except Exception: raise McAuthProfileException("User with email address '%s' does not exist." % email) db.begin() # Purge all IP-limited API keys db.query(""" DELETE FROM auth_user_api_keys WHERE ip_address IS NOT NULL AND auth_users_id = ( SELECT auth_users_id FROM auth_users WHERE email = %(email)s ) """, {'email': email}) # Regenerate non-IP limited API key db.query(""" UPDATE auth_user_api_keys -- DEFAULT points to a generation function SET api_key = DEFAULT WHERE ip_address IS NULL AND auth_users_id = ( SELECT auth_users_id FROM auth_users WHERE email = %(email)s ) """, {'email': email}) message = AuthAPIKeyResetMessage(to=email, full_name=user.full_name()) if not send_email(message): db.rollback() raise McAuthProfileException("Unable to send email about reset API key.") db.commit()
def activate_user_via_token(db: DatabaseHandler, email: str, activation_token: str) -> None: """Change password with a password token sent by email.""" email = decode_object_from_bytes_if_needed(email) activation_token = decode_object_from_bytes_if_needed(activation_token) if not email: raise McAuthRegisterException("Email is empty.") if not activation_token: raise McAuthRegisterException('Password reset token is empty.') # Validate the token once more (was pre-validated in controller) if not password_reset_token_is_valid( db=db, email=email, password_reset_token=activation_token): raise McAuthRegisterException('Activation token is invalid.') db.begin() # Set the password hash db.query( """ UPDATE auth_users SET active = TRUE WHERE email = %(email)s """, {'email': email}) # Unset the password reset token db.query( """ UPDATE auth_users SET password_reset_token_hash = NULL WHERE email = %(email)s """, {'email': email}) user = user_info(db=db, email=email) message = AuthActivatedMessage(to=email, full_name=user.full_name()) if not send_email(message): db.rollback() raise McAuthRegisterException( "Unable to send email about an activated user.") db.commit()
def send_password_reset_token(db: DatabaseHandler, email: str, password_reset_link: str) -> None: """Prepare for password reset by emailing the password reset token.""" email = decode_object_from_bytes_if_needed(email) password_reset_link = decode_object_from_bytes_if_needed( password_reset_link) # Check if user exists try: user = user_info(db=db, email=email) full_name = user.full_name() except Exception as ex: log.warning("Unable to fetch user profile for user '%s': %s" % ( email, str(ex), )) full_name = 'Nonexistent user' # If user was not found, send an email to a random address anyway to avoid timing attack full_password_reset_link = _generate_password_reset_token( db=db, email=email, password_reset_link=password_reset_link, ) if not full_password_reset_link: log.warning( "Unable to generate full password reset link for email '%s'" % email) email = '*****@*****.**' full_password_reset_link = 'password reset link' message = AuthResetPasswordMessage( to=email, full_name=full_name, password_reset_url=full_password_reset_link) if not send_email(message): raise McAuthResetPasswordException( 'Unable to send password reset email.')
def activate_user_via_token(db: DatabaseHandler, email: str, activation_token: str) -> None: """Change password with a password token sent by email.""" email = decode_object_from_bytes_if_needed(email) activation_token = decode_object_from_bytes_if_needed(activation_token) if not email: raise McAuthRegisterException("Email is empty.") if not activation_token: raise McAuthRegisterException('Password reset token is empty.') # Validate the token once more (was pre-validated in controller) if not password_reset_token_is_valid(db=db, email=email, password_reset_token=activation_token): raise McAuthRegisterException('Activation token is invalid.') db.begin() # Set the password hash db.query(""" UPDATE auth_users SET active = TRUE WHERE email = %(email)s """, {'email': email}) # Unset the password reset token db.query(""" UPDATE auth_users SET password_reset_token_hash = NULL WHERE email = %(email)s """, {'email': email}) user = user_info(db=db, email=email) message = AuthActivatedMessage(to=email, full_name=user.full_name()) if not send_email(message): db.rollback() raise McAuthRegisterException("Unable to send email about an activated user.") db.commit()
def send_user_activation_token(db: DatabaseHandler, email: str, activation_link: str, subscribe_to_newsletter: bool = False) -> None: """Prepare for activation by emailing the activation token.""" email = decode_object_from_bytes_if_needed(email) activation_link = decode_object_from_bytes_if_needed(activation_link) if isinstance(subscribe_to_newsletter, bytes): subscribe_to_newsletter = decode_object_from_bytes_if_needed(subscribe_to_newsletter) subscribe_to_newsletter = bool(int(subscribe_to_newsletter)) # Check if user exists try: user = user_info(db=db, email=email) full_name = user.full_name() except Exception as ex: log.warning("Unable to fetch user profile for user '%s': %s" % (email, str(ex),)) full_name = 'Nonexistent user' # If user was not found, send an email to a random address anyway to avoid timing attack full_activation_link = _generate_user_activation_token(db=db, email=email, activation_link=activation_link) if not full_activation_link: log.warning("Unable to generate full activation link for email '%s'" % email) email = '*****@*****.**' full_activation_link = 'activation link' message = AuthActivationNeededMessage( to=email, full_name=full_name, activation_url=full_activation_link, subscribe_to_newsletter=subscribe_to_newsletter ) if not send_email(message): raise McAuthRegisterException('The user was created, but I was unable to send you an activation email.')
def change_password(db: DatabaseHandler, email: str, new_password: str, new_password_repeat: str, do_not_inform_via_email: bool = False) -> None: """Change user's password.""" email = decode_object_from_bytes_if_needed(email) new_password = decode_object_from_bytes_if_needed(new_password) new_password_repeat = decode_object_from_bytes_if_needed( new_password_repeat) if isinstance(do_not_inform_via_email, bytes): do_not_inform_via_email = decode_object_from_bytes_if_needed( do_not_inform_via_email) do_not_inform_via_email = bool(int(do_not_inform_via_email)) # Check if user exists try: user = user_info(db=db, email=email) except Exception: raise McAuthChangePasswordException( 'User with email address "%s" does not exist.' % email) password_validation_message = validate_new_password( email=email, password=new_password, password_repeat=new_password_repeat) if password_validation_message: raise McAuthChangePasswordException("Unable to change password: %s" % password_validation_message) # Hash + validate the password try: password_new_hash = generate_secure_hash(password=new_password) except Exception as ex: raise McAuthChangePasswordException( "Unable to hash a new password: %s" % str(ex)) if not password_new_hash: raise McAuthChangePasswordException( "Generated password hash is empty.") # Set the password hash db.query( """ UPDATE auth_users SET password_hash = %(password_hash)s, active = TRUE WHERE email = %(email)s """, { 'email': email, 'password_hash': password_new_hash, }) if not do_not_inform_via_email: message = AuthPasswordChangedMessage(to=email, full_name=user.full_name()) if not send_email(message): raise McAuthChangePasswordException( 'The password has been changed, but I was unable to send an email notifying you about the change.' )