From ccc90a8fdba69da7c035f95139711d24193bc024 Mon Sep 17 00:00:00 2001 From: Julian Rother <julian@cccv.de> Date: Mon, 26 Feb 2024 20:13:01 +0100 Subject: [PATCH] Fix autocomplete behaviour in Firefox Firefox autofills all type="password" inputs with passwords from its built-in password store. This breaks usability of admin pages. This change fixes that by adding autocomplete="new-password" to these inputs. It also adds appropriate autocomplete attributes to other forms/inputs to improve autocomplete behaviour across browsers: - autocomplete="off" on all non-login/signup/selfservice forms - autocomplete="new-password" or autocomplete="current-password" on all type="password" inputs to workaround Firefox's misdetection - autocomplete="username"/"email"/"nickname" on login/signup/selfservice inputs wherever appropriate - Avoid type="password" where possible (e.g. on readonly fields) --- uffd/templates/group/show.html | 2 +- uffd/templates/invite/new.html | 2 +- uffd/templates/mail/show.html | 2 +- uffd/templates/mfa/auth.html | 4 ++-- uffd/templates/mfa/setup.html | 4 ++-- uffd/templates/mfa/setup_totp.html | 2 +- uffd/templates/role/show.html | 2 +- uffd/templates/selfservice/forgot_password.html | 6 +++--- uffd/templates/selfservice/self.html | 6 +++--- uffd/templates/selfservice/set_password.html | 6 +++--- uffd/templates/service/api.html | 6 +++--- uffd/templates/service/oauth2.html | 6 +++--- uffd/templates/service/show.html | 2 +- uffd/templates/session/deviceauth.html | 6 +++--- uffd/templates/session/devicelogin.html | 2 +- uffd/templates/session/login.html | 6 +++--- uffd/templates/signup/confirm.html | 2 +- uffd/templates/signup/start.html | 10 +++++----- uffd/templates/user/show.html | 8 ++++---- 19 files changed, 42 insertions(+), 42 deletions(-) diff --git a/uffd/templates/group/show.html b/uffd/templates/group/show.html index 698d4836..5f7c1658 100644 --- a/uffd/templates/group/show.html +++ b/uffd/templates/group/show.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block body %} -<form action="{{ url_for("group.update", id=group.id) }}" method="POST"> +<form action="{{ url_for("group.update", id=group.id) }}" method="POST" autocomplete="off"> <div class="align-self-center"> <div class="clearfix pb-2 col"> <div class="float-sm-right"> diff --git a/uffd/templates/invite/new.html b/uffd/templates/invite/new.html index 0e734a75..547a5cf7 100644 --- a/uffd/templates/invite/new.html +++ b/uffd/templates/invite/new.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block body %} -<form action="{{ url_for("invite.new_submit") }}" method="POST" class="form"> +<form action="{{ url_for("invite.new_submit") }}" method="POST" autocomplete="off" class="form"> <div class="form-group"> <label for="single-use">{{_('Link Type')}}</label> <select class="form-control" id="single-use" name="single-use"> diff --git a/uffd/templates/mail/show.html b/uffd/templates/mail/show.html index 0f11fa9c..7cb7a2cc 100644 --- a/uffd/templates/mail/show.html +++ b/uffd/templates/mail/show.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block body %} -<form action="{{ url_for("mail.update", mail_id=mail.id) }}" method="POST"> +<form action="{{ url_for("mail.update", mail_id=mail.id) }}" method="POST" autocomplete="off"> <div class="align-self-center"> <div class="form-group col"> <label for="mail-name">{{_('Name')}}</label> diff --git a/uffd/templates/mfa/auth.html b/uffd/templates/mfa/auth.html index 8b64a597..28bea1d5 100644 --- a/uffd/templates/mfa/auth.html +++ b/uffd/templates/mfa/auth.html @@ -1,7 +1,7 @@ {% extends 'base_narrow.html' %} {% block body %} -<form action="{{ url_for("mfa.auth_finish", ref=ref) }}" method="POST"> +<form action="{{ url_for("mfa.auth_finish", ref=ref) }}" method="POST" autocomplete="off"> <div class="col-12 mb-3"> <h2 class="text-center">{{_("Two-Factor Authentication")}}</h2> </div> @@ -24,7 +24,7 @@ <div class="text-center text-muted d-none webauthn-group mb-3">- {{_("or")}} -</div> {% endif %} <div class="form-group col-12 mb-2"> - <input type="text" class="form-control" id="mfa-code" name="code" required="required" placeholder="{{_("Code from your authenticator app or recovery code")}}" autocomplete="off" autofocus> + <input type="text" class="form-control" id="mfa-code" name="code" required="required" placeholder="{{_("Code from your authenticator app or recovery code")}}" autofocus> </div> <div class="form-group col-12"> <button type="submit" class="btn btn-primary btn-block">{{_("Verify")}}</button> diff --git a/uffd/templates/mfa/setup.html b/uffd/templates/mfa/setup.html index 2922aac2..134f651b 100644 --- a/uffd/templates/mfa/setup.html +++ b/uffd/templates/mfa/setup.html @@ -93,7 +93,7 @@ mfa_enabled: The user has setup at least one two-factor method. Two-factor authe </div> <div class="col-12 col-md-7"> - <form class="form mb-2" action="{{ url_for('mfa.setup_totp') }}"> + <form class="form mb-2" action="{{ url_for('mfa.setup_totp') }}" autocomplete="off"> <div class="row m-0"> <label class="sr-only" for="totp-name">{{_("Name")}}</label> <input type="text" name="name" class="form-control mb-2 col-12 col-lg-auto mr-2" style="width: 15em;" id="totp-name" placeholder="{{_("Name")}}" required {{ 'disabled' if mfa_init }}> @@ -152,7 +152,7 @@ mfa_enabled: The user has setup at least one two-factor method. Two-factor authe </div> </noscript> <div id="webauthn-alert" class="alert alert-warning d-none" role="alert"></div> - <form id="webauthn-form" class="form mb-2"> + <form id="webauthn-form" autocomplete="off" class="form mb-2"> <div class="row m-0"> <label class="sr-only" for="webauthn-name">{{_("Name")}}</label> <input type="text" class="form-control mb-2 col-12 col-lg-auto mr-2" style="width: 15em;" id="webauthn-name" placeholder="{{_("Name")}}" required disabled> diff --git a/uffd/templates/mfa/setup_totp.html b/uffd/templates/mfa/setup_totp.html index da2e3317..b450793d 100644 --- a/uffd/templates/mfa/setup_totp.html +++ b/uffd/templates/mfa/setup_totp.html @@ -32,7 +32,7 @@ </div> </div> -<form action="{{ url_for('mfa.setup_totp_finish', name=name) }}" method="POST" class="form"> +<form action="{{ url_for('mfa.setup_totp_finish', name=name) }}" method="POST" autocomplete="off" class="form"> <div class="row m-0"> <input type="text" name="code" class="form-control mb-2 mr-2 col-auto col-md" id="code" placeholder="{{_('Code')}}" required autofocus> <button type="submit" class="btn btn-primary mb-2 col col-md-auto">{{_("Verify and complete setup")}}</button> diff --git a/uffd/templates/role/show.html b/uffd/templates/role/show.html index 282bbb7c..f9b548c7 100644 --- a/uffd/templates/role/show.html +++ b/uffd/templates/role/show.html @@ -7,7 +7,7 @@ </div> {% endif %} -<form action="{{ url_for("role.update", roleid=role.id) }}" method="POST"> +<form action="{{ url_for("role.update", roleid=role.id) }}" method="POST" autocomplete="off"> <div class="align-self-center"> <div class="clearfix pb-2"><div class="float-sm-right"> <button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> {{_("Save")}}</button> diff --git a/uffd/templates/selfservice/forgot_password.html b/uffd/templates/selfservice/forgot_password.html index 9792f15b..96f8cd60 100644 --- a/uffd/templates/selfservice/forgot_password.html +++ b/uffd/templates/selfservice/forgot_password.html @@ -7,14 +7,14 @@ </div> <div class="form-group col-12"> <label for="user-loginname">{{_("Login Name")}}</label> - <input type="text" class="form-control" id="user-loginname" name="loginname" required="required" tabindex = "1"> + <input type="text" autocomplete="username" class="form-control" id="user-loginname" name="loginname" required="required" tabindex="1"> </div> <div class="form-group col-12"> <label for="user-mail">{{_("Mail Address")}}</label> - <input type="text" class="form-control" id="user-mail" name="mail" required="required" tabindex = "2"> + <input type="email" autocomplete="email" class="form-control" id="user-mail" name="mail" required="required" tabindex="2"> </div> <div class="form-group col-12"> - <button type="submit" class="btn btn-primary btn-block" tabindex = "3">{{_("Send password reset mail")}}</button> + <button type="submit" class="btn btn-primary btn-block" tabindex="3">{{_("Send password reset mail")}}</button> </div> </form> {% endblock %} diff --git a/uffd/templates/selfservice/self.html b/uffd/templates/selfservice/self.html index 6e032d5b..548791df 100644 --- a/uffd/templates/selfservice/self.html +++ b/uffd/templates/selfservice/self.html @@ -41,7 +41,7 @@ <form method="POST" action="{{ url_for('selfservice.add_email') }}" class="form mb-2"> <div class="row m-0"> <label class="sr-only" for="new-email-address">{{_("Email")}}</label> - <input type="text" class="form-control mb-2 col-12 col-lg-auto mr-2" style="width: 20em;" id="new-email-address" name="address" placeholder="{{_("New E-Mail Address")}}" required> + <input type="email" autocomplete="email" class="form-control mb-2 col-12 col-lg-auto mr-2" style="width: 20em;" id="new-email-address" name="address" placeholder="{{_("New E-Mail Address")}}" required> <button type="submit" class="btn btn-primary mb-2 col">{{_("Add address")}}</button> </div> </form> @@ -139,13 +139,13 @@ <div class="col-12 col-md-7"> <form class="form" action="{{ url_for("selfservice.change_password") }}" method="POST"> <div class="form-group"> - <input type="password" class="form-control" id="user-password1" name="password1" placeholder="{{_("New Password")}}" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password1" name="password1" placeholder="{{_("New Password")}}" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> <small class="form-text text-muted"> {{ User.PASSWORD_DESCRIPTION|safe }} </small> </div> <div class="form-group"> - <input type="password" class="form-control" id="user-password2" name="password2" placeholder="{{_("Repeat Password")}}" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password2" name="password2" placeholder="{{_("Repeat Password")}}" required> </div> <button type="submit" class="btn btn-primary btn-block">{{_("Change Password")}}</button> </form> diff --git a/uffd/templates/selfservice/set_password.html b/uffd/templates/selfservice/set_password.html index 39e51107..bab7ce91 100644 --- a/uffd/templates/selfservice/set_password.html +++ b/uffd/templates/selfservice/set_password.html @@ -7,17 +7,17 @@ </div> <div class="form-group col-12"> <label for="user-password1">{{_("New Password")}}</label> - <input type="password" class="form-control" id="user-password1" name="password1" tabindex="2" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password1" name="password1" tabindex="2" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> <small class="form-text text-muted"> {{ User.PASSWORD_DESCRIPTION|safe }} </small> </div> <div class="form-group col-12"> <label for="user-password2">{{_("Repeat Password")}}</label> - <input type="password" class="form-control" id="user-password2" name="password2" tabindex="3" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password2" name="password2" tabindex="3" required> </div> <div class="form-group col-12"> - <button type="submit" class="btn btn-primary btn-block" tabindex = "3">{{_("Set password")}}</button> + <button type="submit" class="btn btn-primary btn-block" tabindex="3">{{_("Set password")}}</button> </div> </form> {% endblock %} diff --git a/uffd/templates/service/api.html b/uffd/templates/service/api.html index abe7ad68..23b47de2 100644 --- a/uffd/templates/service/api.html +++ b/uffd/templates/service/api.html @@ -2,7 +2,7 @@ {% block body %} <div class="row"> - <form action="{{ url_for('service.api_submit', service_id=service.id, id=client.id) }}" method="POST" class="form col-12 px-0"> + <form action="{{ url_for('service.api_submit', service_id=service.id, id=client.id) }}" method="POST" autocomplete="off" class="form col-12 px-0"> <div class="form-group col"> <p class="text-right"> @@ -24,9 +24,9 @@ <div class="form-group col"> <label for="client-auth-password">{{ _('Authentication Password') }}</label> {% if client.id %} - <input type="password" class="form-control" id="client-auth-password" name="auth_password" placeholder="●●●●●●●●"> + <input type="password" autocomplete="new-password" class="form-control" id="client-auth-password" name="auth_password" placeholder="●●●●●●●●"> {% else %} - <input type="password" class="form-control" id="client-auth-password" name="auth_password" required> + <input type="password" autocomplete="new-password" class="form-control" id="client-auth-password" name="auth_password" required> {% endif %} </div> diff --git a/uffd/templates/service/oauth2.html b/uffd/templates/service/oauth2.html index 3337f3a8..3ad87f5d 100644 --- a/uffd/templates/service/oauth2.html +++ b/uffd/templates/service/oauth2.html @@ -2,7 +2,7 @@ {% block body %} <div class="row"> - <form action="{{ url_for('service.oauth2_submit', service_id=service.id, db_id=client.db_id) }}" method="POST" class="form col-12 px-0"> + <form action="{{ url_for('service.oauth2_submit', service_id=service.id, db_id=client.db_id) }}" method="POST" autocomplete="off" class="form col-12 px-0"> <div class="form-group col"> <p class="text-right"> @@ -24,9 +24,9 @@ <div class="form-group col"> <label for="client-client-secret">{{ _('Client Secret') }}</label> {% if client.db_id %} - <input type="password" class="form-control" id="client-client-secret" name="client_secret" placeholder="●●●●●●●●"> + <input type="password" autocomplete="new-password" class="form-control" id="client-client-secret" name="client_secret" placeholder="●●●●●●●●"> {% else %} - <input type="password" class="form-control" id="client-client-secret" name="client_secret" required> + <input type="password" autocomplete="new-password" class="form-control" id="client-client-secret" name="client_secret" required> {% endif %} </div> diff --git a/uffd/templates/service/show.html b/uffd/templates/service/show.html index 08e0629f..b258f8ca 100644 --- a/uffd/templates/service/show.html +++ b/uffd/templates/service/show.html @@ -4,7 +4,7 @@ <div class="row"> - <form action="{{ url_for('service.edit_submit', id=service.id) }}" method="POST" class="form col-12 px-0"> + <form action="{{ url_for('service.edit_submit', id=service.id) }}" method="POST" autocomplete="off" class="form col-12 px-0"> <div class="form-group col"> <p class="text-right"> <a href="{{ url_for('service.index') }}" class="btn btn-secondary">{{ _('Cancel') }}</a> diff --git a/uffd/templates/session/deviceauth.html b/uffd/templates/session/deviceauth.html index c0827501..b05b508d 100644 --- a/uffd/templates/session/deviceauth.html +++ b/uffd/templates/session/deviceauth.html @@ -2,11 +2,11 @@ {% block body %} {% if not initiation %} -<form action="{{ url_for("session.deviceauth") }}"> +<form action="{{ url_for("session.deviceauth") }}" autocomplete="off"> {% elif not confirmation %} -<form action="{{ url_for("session.deviceauth_submit") }}" method="POST"> +<form action="{{ url_for("session.deviceauth_submit") }}" method="POST" autocomplete="off"> {% else %} -<form action="{{ url_for("session.deviceauth_finish") }}" method="POST"> +<form action="{{ url_for("session.deviceauth_finish") }}" method="POST" autocomplete="off"> {% endif %} <div class="col-12"> <h2 class="text-center">{{_('Authorize Device Login')}}</h2> diff --git a/uffd/templates/session/devicelogin.html b/uffd/templates/session/devicelogin.html index b9874ecd..369580fe 100644 --- a/uffd/templates/session/devicelogin.html +++ b/uffd/templates/session/devicelogin.html @@ -1,7 +1,7 @@ {% extends 'base_narrow.html' %} {% block body %} -<form action="{{ url_for("session.devicelogin_submit", ref=ref) }}" method="POST"> +<form action="{{ url_for("session.devicelogin_submit", ref=ref) }}" method="POST" autocomplete="off"> <div class="col-12"> <h2 class="text-center">{{_('Device Login')}}</h2> </div> diff --git a/uffd/templates/session/login.html b/uffd/templates/session/login.html index 8b963c29..dccedd82 100644 --- a/uffd/templates/session/login.html +++ b/uffd/templates/session/login.html @@ -10,14 +10,14 @@ {% endif %} <div class="form-group col-12"> <label for="user-loginname">{{_("Login Name")}}</label> - <input type="text" class="form-control" id="user-loginname" name="loginname" required="required" tabindex = "1" autofocus> + <input type="text" autocomplete="username" class="form-control" id="user-loginname" name="loginname" required="required" tabindex="1" autofocus> </div> <div class="form-group col-12"> <label for="user-password1">{{_("Password")}}</label> - <input type="password" class="form-control" id="user-password1" name="password" required="required" tabindex = "2"> + <input type="password" autocomplete="current-password" class="form-control" id="user-password1" name="password" required="required" tabindex="2"> </div> <div class="form-group col-12"> - <button type="submit" class="btn btn-primary btn-block" tabindex = "3">{{_("Login")}}</button> + <button type="submit" class="btn btn-primary btn-block" tabindex="3">{{_("Login")}}</button> </div> {% if request.values.get('devicelogin') %} <div class="text-center text-muted mb-3">{{_("- or -")}}</div> diff --git a/uffd/templates/signup/confirm.html b/uffd/templates/signup/confirm.html index 087ef8b0..3fcfb47f 100644 --- a/uffd/templates/signup/confirm.html +++ b/uffd/templates/signup/confirm.html @@ -7,7 +7,7 @@ </div> <div class="form-group col-12"> <label for="user-password1">{{_('Please enter your password to complete the account registration')}}</label> - <input type="password" class="form-control" id="user-password1" name="password" required="required"> + <input type="password" autocomplete="current-password" class="form-control" id="user-password1" name="password" required="required"> </div> <div class="form-group col-12"> <button type="submit" class="btn btn-primary btn-block">{{_('Complete Account Registration')}}</button> diff --git a/uffd/templates/signup/start.html b/uffd/templates/signup/start.html index 1c72f469..09e0ad36 100644 --- a/uffd/templates/signup/start.html +++ b/uffd/templates/signup/start.html @@ -8,7 +8,7 @@ <div class="form-group col-12"> <label for="user-loginname">{{_('Login Name')}}</label> <div class="js-only-input-group"> - <input type="text" class="form-control" id="user-loginname" name="loginname" aria-describedby="loginname-feedback" value="{{ request.form.loginname }}" minlength=1 maxlength=32 pattern="[a-z0-9_-]*" required> + <input type="text" autocomplete="username" class="form-control" id="user-loginname" name="loginname" aria-describedby="loginname-feedback" value="{{ request.form.loginname }}" minlength=1 maxlength=32 pattern="[a-z0-9_-]*" required> <div class="js-only-input-group-append d-none"> <button class="btn btn-outline-secondary rounded-right" type="button" id="check-loginname">{{_('Check')}}</button> </div> @@ -20,28 +20,28 @@ </div> <div class="form-group col-12"> <label for="user-displayname">{{_('Display Name')}}</label> - <input type="text" class="form-control" id="user-displayname" name="displayname" value="{{ request.form.displayname }}" minlength=1 maxlength=128 required> + <input type="text" autocomplete="nickname" class="form-control" id="user-displayname" name="displayname" value="{{ request.form.displayname }}" minlength=1 maxlength=128 required> <small class="form-text text-muted"> {{_('At least one and at most 128 characters, no other special requirements.')}} </small> </div> <div class="form-group col-12"> <label for="user-mail">{{_('E-Mail Address')}}</label> - <input type="email" class="form-control" id="user-mail" name="mail" value="{{ request.form.mail }}" required> + <input type="email" autocomplete="email" class="form-control" id="user-mail" name="mail" value="{{ request.form.mail }}" required> <small class="form-text text-muted"> {{_('We will send a confirmation mail to this address that you need to complete the registration.')}} </small> </div> <div class="form-group col-12"> <label for="user-password1">{{_('Password')}}</label> - <input type="password" class="form-control" id="user-password1" name="password1" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password1" name="password1" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}" required> <small class="form-text text-muted"> {{ User.PASSWORD_DESCRIPTION|safe }} </small> </div> <div class="form-group col-12"> <label for="user-password2">{{_('Repeat Password')}}</label> - <input type="password" class="form-control" id="user-password2" name="password2" required> + <input type="password" autocomplete="new-password" class="form-control" id="user-password2" name="password2" required> </div> <div class="form-group col-12"> <button type="submit" class="btn btn-primary btn-block">{{_('Create Account')}}</button> diff --git a/uffd/templates/user/show.html b/uffd/templates/user/show.html index 04b2cf35..ed4b2bd9 100644 --- a/uffd/templates/user/show.html +++ b/uffd/templates/user/show.html @@ -17,9 +17,9 @@ {% block body %} {% if user.id %} -<form action="{{ url_for("user.update", id=user.id) }}" method="POST"> +<form action="{{ url_for("user.update", id=user.id) }}" method="POST" autocomplete="off"> {% else %} -<form action="{{ url_for("user.create") }}" method="POST"> +<form action="{{ url_for("user.create") }}" method="POST" autocomplete="off"> {% endif %} <div class="align-self-center"> {% if user.id and user.is_deactivated %} @@ -174,9 +174,9 @@ <div class="form-group col"> <label for="user-loginname">{{_("Password")}}</label> {% if user.id %} - <input type="password" class="form-control" id="user-password" name="password" placeholder="●●●●●●●●" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}"> + <input type="password" autocomplete="new-password" class="form-control" id="user-password" name="password" placeholder="●●●●●●●●" minlength={{ User.PASSWORD_MINLEN }} maxlength={{ User.PASSWORD_MAXLEN }} pattern="{{ User.PASSWORD_REGEX }}"> {% else %} - <input type="password" class="form-control" id="user-password" name="password" placeholder="{{_("E-Mail to set it will be sent")}}" readonly> + <input type="text" class="form-control" id="user-password" name="password" placeholder="{{_("E-Mail to set it will be sent")}}" readonly> {% endif %} <small class="form-text text-muted"> {{ User.PASSWORD_DESCRIPTION|safe }} -- GitLab