def delete_verification_token(token): """ Gives call to party service to delete a verification token for the respondent :param token: the verification token """ email = decode_email_token(token) logger.info("Attempting to delete respondent verification token", email=obfuscate_email(email)) party_id = get_respondent_by_email(email)["id"] url = f"{app.config['PARTY_URL']}/party-api/v1/respondents/{party_id}/password-verification-token/{token}" response = requests.delete(url, auth=app.config["BASIC_AUTH"]) try: response.raise_for_status() except requests.exceptions.HTTPError: if response.status_code == 404: logger.error("Verification token not found") raise NotFound("Token not found") logger.error("Failed to delete respondent verification token", email=obfuscate_email(email)) raise ApiError(logger, response) logger.info("Successfully deleted respondent verification token", email=obfuscate_email(email)) return response.json()
def post_reset_password(token): form = ResetPasswordForm(request.form) if not form.validate(): return get_reset_password(token, form_errors=form.errors) password = request.form.get('password') try: duration = app.config['EMAIL_TOKEN_EXPIRY'] email = verification.decode_email_token(token, duration) party_controller.change_password(email, password) except ApiError as exc: if exc.status_code == 409: logger.warning('Token expired', api_url=exc.url, api_status_code=exc.status_code, token=token) return render_template('passwords/password-expired.html', token=token) elif exc.status_code == 404: logger.warning('Invalid token sent to party service', api_url=exc.url, api_status_code=exc.status_code, token=token) abort(404) else: raise exc logger.info('Successfully changed user password', token=token) return redirect(url_for('passwords_bp.reset_password_confirmation'))
def get_reset_password(token, form_errors=None): form = ResetPasswordForm(request.form) try: duration = app.config['EMAIL_TOKEN_EXPIRY'] _ = verification.decode_email_token(token, duration) except SignatureExpired: logger.warning('Token expired for frontstage reset', token=token, exc_info=True) return render_template('passwords/password-expired.html', token=token) except (BadSignature, BadData): logger.warning('Invalid token sent to frontstage password reset', token=token, exc_info=True) return render_template('passwords/password-expired.html', token=token) template_data = { "error": { "type": form_errors }, 'token': token } return render_template('passwords/reset-password.html', form=form, data=template_data)
def get_reset_password(token, form_errors=None): form = ResetPasswordForm(request.form) try: duration = app.config["EMAIL_TOKEN_EXPIRY"] email = verification.decode_email_token(token, duration) respondent = party_controller.get_respondent_by_email(email) db_token = respondent["password_verification_token"] if not token == db_token: logger.warning("Token not found for respondent", token=token, respondent_id=respondent["id"]) return render_template("passwords/password-token-not-found.html", token=token) except KeyError: logger.warning("Token not found for respondent", token=token, exc_info=True) return render_template("passwords/password-token-not-found.html", token=token) except SignatureExpired: try: party_controller.delete_verification_token(token) except NotFound: return render_template("passwords/password-token-not-found.html", token=token) logger.warning("Token expired for frontstage reset", token=token, exc_info=True) return render_template("passwords/password-expired.html", token=token) except (BadSignature, BadData): logger.warning("Invalid token sent to frontstage password reset", token=token, exc_info=True) return render_template("passwords/password-expired.html", token=token) template_data = {"error": {"type": form_errors}, "token": token} return render_template("passwords/reset-password.html", form=form, data=template_data)
def resend_password_email_expired_token(token): email = verification.decode_email_token(token) return request_password_change(email)
def request_password_change(email): respondent = party_controller.get_respondent_by_email(email) if not respondent: logger.info("Respondent does not exist") return redirect(url_for("passwords_bp.reset_password_trouble")) party_id = str(respondent["id"]) password_reset_counter = party_controller.get_password_reset_counter( party_id)["counter"] if password_reset_counter != 0: try: email = verification.decode_email_token( respondent["password_verification_token"], app.config["PASSWORD_RESET_ATTEMPTS_TIMEOUT"]) except SignatureExpired: try: party_controller.reset_password_reset_counter(party_id) password_reset_counter = 0 except ApiError: logger.error("Error resetting password reset counter") return redirect(url_for("passwords_bp.reset_password_trouble")) if password_reset_counter >= 5: logger.error("Password reset attempts exceeded") return redirect( url_for("passwords_bp.exceeded_number_of_reset_attempts")) logger.info("Requesting password change", party_id=party_id) token = verification.generate_email_token(email) url_root = request.url_root # url_for comes with a leading slash, so strip off the trailing slash in url_root if there is one if url_root.endswith("/"): url_root = url_root[:-1] verification_url = url_root + url_for("passwords_bp.post_reset_password", token=token) personalisation = { "RESET_PASSWORD_URL": verification_url, "FIRST_NAME": respondent["firstName"] } logger.info("Reset password url", url=verification_url, party_id=party_id) party_controller.post_verification_token(email, token) try: NotifyGateway(app.config).request_to_notify( email=email, personalisation=personalisation, reference=party_id) logger.info("Password reset email successfully sent", party_id=party_id) except RasNotifyError: # Note: intentionally suppresses exception logger.error("Error sending request to Notify Gateway", respondent_id=party_id, exc_info=True) # Get real time counter to check how many attempts are left password_reset_counter = party_controller.get_password_reset_counter( party_id)["counter"] if password_reset_counter == 4: flash(message="You have 1 try left to reset your password", category="warn") return redirect( url_for("passwords_bp.reset_password_check_email", token=token))
def resend_password_email_expired_token(token): email = verification.decode_email_token(token) party_controller.post_verification_token(email, token) return request_password_change(email)
def reset_password_check_email(token): email = verification.decode_email_token(token) return render_template("passwords/reset-password.check-email.html", email=email)