Files
notifications-admin/app/main/views/user_profile.py
Carlo Costino 9e609efa1c Remove webauthn hooks
This changeset removes webauthn from the Notify.gov admin app.  We are not using webauthn at all in our implementation and will be looking at an entirely different authentication system in the near future.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2023-08-14 16:59:38 -04:00

267 lines
8.0 KiB
Python

import json
from flask import (
abort,
current_app,
flash,
redirect,
render_template,
request,
session,
url_for,
)
from flask_login import current_user
from notifications_utils.url_safe_token import check_token
from app import user_api_client
from app.event_handlers import (
create_email_change_event,
create_mobile_number_change_event,
)
from app.main import main
from app.main.forms import (
ChangeEmailForm,
ChangeMobileNumberForm,
ChangeNameForm,
ChangePasswordForm,
ConfirmPasswordForm,
ServiceOnOffSettingForm,
TwoFactorForm,
)
from app.models.user import User
from app.utils.user import user_is_gov_user, user_is_logged_in
NEW_EMAIL = 'new-email'
NEW_MOBILE = 'new-mob'
NEW_MOBILE_PASSWORD_CONFIRMED = 'new-mob-password-confirmed' # nosec B105 - this is not a password
@main.route("/user-profile")
@user_is_logged_in
def user_profile():
return render_template(
'views/user-profile.html',
can_see_edit=current_user.is_gov_user,
)
@main.route("/user-profile/name", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_name():
form = ChangeNameForm(new_name=current_user.name)
if form.validate_on_submit():
current_user.update(name=form.new_name.data)
return redirect(url_for('.user_profile'))
return render_template(
'views/user-profile/change.html',
thing='name',
form_field=form.new_name
)
@main.route("/user-profile/email", methods=['GET', 'POST'])
@user_is_logged_in
@user_is_gov_user
def user_profile_email():
form = ChangeEmailForm(User.already_registered,
email_address=current_user.email_address)
if form.validate_on_submit():
session[NEW_EMAIL] = form.email_address.data
return redirect(url_for('.user_profile_email_authenticate'))
return render_template(
'views/user-profile/change.html',
thing='email address',
form_field=form.email_address
)
@main.route("/user-profile/email/authenticate", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_email_authenticate():
# Validate password for form
def _check_password(pwd):
return user_api_client.verify_password(current_user.id, pwd)
form = ConfirmPasswordForm(_check_password)
if NEW_EMAIL not in session:
return redirect('main.user_profile_email')
if form.validate_on_submit():
user_api_client.send_change_email_verification(current_user.id, session[NEW_EMAIL])
create_email_change_event(
user_id=current_user.id,
updated_by_id=current_user.id,
original_email_address=current_user.email_address,
new_email_address=session[NEW_EMAIL],
)
return render_template('views/change-email-continue.html',
new_email=session[NEW_EMAIL])
return render_template(
'views/user-profile/authenticate.html',
thing='email address',
form=form,
back_link=url_for('.user_profile_email')
)
@main.route("/user-profile/email/confirm/<token>", methods=['GET'])
@user_is_logged_in
def user_profile_email_confirm(token):
token_data = check_token(token,
current_app.config['SECRET_KEY'],
current_app.config['DANGEROUS_SALT'],
current_app.config['EMAIL_EXPIRY_SECONDS'])
token_data = json.loads(token_data)
user = User.from_id(token_data['user_id'])
user.update(email_address=token_data['email'])
session.pop(NEW_EMAIL, None)
return redirect(url_for('.user_profile'))
@main.route("/user-profile/mobile-number", methods=['GET', 'POST'])
@main.route(
"/user-profile/mobile-number/delete",
methods=['GET'],
endpoint="user_profile_confirm_delete_mobile_number"
)
@user_is_logged_in
def user_profile_mobile_number():
user = User.from_id(current_user.id)
form = ChangeMobileNumberForm(mobile_number=current_user.mobile_number)
if form.validate_on_submit():
session[NEW_MOBILE] = form.mobile_number.data
return redirect(url_for('.user_profile_mobile_number_authenticate'))
if (request.endpoint == "main.user_profile_confirm_delete_mobile_number"):
flash("Are you sure you want to delete your mobile number from Notify?", 'delete')
return render_template(
'views/user-profile/change.html',
thing='mobile number',
form_field=form.mobile_number,
user_auth=user.auth_type
)
@main.route("/user-profile/mobile-number/delete", methods=['POST'])
@user_is_logged_in
def user_profile_mobile_number_delete():
if current_user.auth_type != 'email_auth':
abort(403)
current_user.update(mobile_number=None)
return redirect(url_for('.user_profile'))
@main.route("/user-profile/mobile-number/authenticate", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_mobile_number_authenticate():
# Validate password for form
def _check_password(pwd):
return user_api_client.verify_password(current_user.id, pwd)
form = ConfirmPasswordForm(_check_password)
if NEW_MOBILE not in session:
return redirect(url_for('.user_profile_mobile_number'))
if form.validate_on_submit():
session[NEW_MOBILE_PASSWORD_CONFIRMED] = True
current_user.send_verify_code(to=session[NEW_MOBILE])
create_mobile_number_change_event(
user_id=current_user.id,
updated_by_id=current_user.id,
original_mobile_number=current_user.mobile_number,
new_mobile_number=session[NEW_MOBILE]
)
return redirect(url_for('.user_profile_mobile_number_confirm'))
return render_template(
'views/user-profile/authenticate.html',
thing='mobile number',
form=form,
back_link=url_for('.user_profile_mobile_number_confirm')
)
@main.route("/user-profile/mobile-number/confirm", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_mobile_number_confirm():
# Validate verify code for form
def _check_code(cde):
return user_api_client.check_verify_code(current_user.id, cde, 'sms')
if NEW_MOBILE_PASSWORD_CONFIRMED not in session:
return redirect(url_for('.user_profile_mobile_number'))
form = TwoFactorForm(_check_code)
if form.validate_on_submit():
current_user.refresh_session_id()
mobile_number = session[NEW_MOBILE]
del session[NEW_MOBILE]
del session[NEW_MOBILE_PASSWORD_CONFIRMED]
current_user.update(mobile_number=mobile_number)
return redirect(url_for('.user_profile'))
return render_template(
'views/user-profile/confirm.html',
form_field=form.sms_code,
thing='mobile number'
)
@main.route("/user-profile/password", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_password():
# Validate password for form
def _check_password(pwd):
return user_api_client.verify_password(current_user.id, pwd)
form = ChangePasswordForm(_check_password)
if form.validate_on_submit():
user_api_client.update_password(current_user.id, password=form.new_password.data)
return redirect(url_for('.user_profile'))
return render_template(
'views/user-profile/change-password.html',
form=form
)
@main.route("/user-profile/disable-platform-admin-view", methods=['GET', 'POST'])
@user_is_logged_in
def user_profile_disable_platform_admin_view():
if not current_user.platform_admin and not session.get('disable_platform_admin_view'):
abort(403)
form = ServiceOnOffSettingForm(
name="Use platform admin view",
enabled=not session.get('disable_platform_admin_view'),
truthy='Yes',
falsey='No',
)
form.enabled.param_extensions = {"hint": {"text": "Signing in again clears this setting"}}
if form.validate_on_submit():
session['disable_platform_admin_view'] = not form.enabled.data
return redirect(url_for('.user_profile'))
return render_template(
'views/user-profile/disable-platform-admin-view.html',
form=form
)