From fa235e60ff6cd33cd92aa5f86e6f5955cd9e8024 Mon Sep 17 00:00:00 2001 From: Gaurav Pandey Date: Mon, 5 Apr 2021 13:12:29 +0530 Subject: [PATCH] login: Add show password feature to login page. The show password feature is a functionality to toggle the visibility of the password fields in forms so that one can check if they have entered the correct password or not. We implement this using an eye icon toggling which converts input field type from password to text and vice-versa. Fixes part of #17301. --- docs/development/authentication.md | 10 ++++++++++ frontend_tests/node_tests/common.js | 30 +++++++++++++++++++++++++++++ static/js/common.js | 24 +++++++++++++++++++++++ static/js/portico/signup.js | 5 +++++ static/styles/components.css | 15 +++++++++++++++ templates/zerver/login.html | 5 +++-- 6 files changed, 87 insertions(+), 2 deletions(-) diff --git a/docs/development/authentication.md b/docs/development/authentication.md index 0b09041ed9..3843efce0e 100644 --- a/docs/development/authentication.md +++ b/docs/development/authentication.md @@ -221,4 +221,14 @@ to test 2FA in development, make sure that you login using a password. You can get the passwords for the default test users using `./manage.py print_initial_password`. +## Password form implementation + +By default, Zulip uses `autocomplete=off` for password fields where we +enter the current password, and `autocomplete="new-password"` for +password fields where we create a new account or change the existing +password. This prevents the browser from auto-filling the existing +password. + +Visit for more details. + [0]: https://github.com/Bouke/django-two-factor-auth diff --git a/frontend_tests/node_tests/common.js b/frontend_tests/node_tests/common.js index 409c85849f..64ad858b56 100644 --- a/frontend_tests/node_tests/common.js +++ b/frontend_tests/node_tests/common.js @@ -128,3 +128,33 @@ run_test("adjust_mac_shortcuts mac", (override) => { assert.equal(test_item.stub.text(), test_item.mac_key); } }); + +run_test("show password", () => { + const password_selector = ".password_visibility_toggle"; + + function set_attribute(type) { + $("#id_password").attr("type", type); + } + + function check_assertion(type, present_class, absent_class) { + assert.equal($("#id_password").attr("type"), type); + assert($(password_selector).hasClass(present_class)); + assert(!$(password_selector).hasClass(absent_class)); + } + + const ev = { + preventDefault: () => {}, + stopPropagation: () => {}, + }; + + set_attribute("password"); + common.setup_password_visibility_toggle("#id_password", password_selector); + + const handler = $(password_selector).get_on_handler("click"); + + handler(ev); + check_assertion("text", "fa-eye", "fa-eye-slash"); + + handler(ev); + check_assertion("password", "fa-eye-slash", "fa-eye"); +}); diff --git a/static/js/common.js b/static/js/common.js index f9a5b22a96..be69abb3e2 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -134,3 +134,27 @@ export function adjust_mac_shortcuts(key_elem_class, require_cmd_style) { $(this).text(key_text); }); } + +// See https://zulip.readthedocs.io/en/latest/development/authentication.html#password-form-implementation +// for design details on this feature. +// +// This toggle code would probably be cleaner as 2 functions. +function toggle_password_visibility(password_field_id, password_selector) { + const password_field = $(password_field_id); + + if (password_field.attr("type") === "password") { + password_field.attr("type", "text"); + $(password_selector).removeClass("fa-eye-slash").addClass("fa-eye"); + } else { + password_field.attr("type", "password"); + $(password_selector).removeClass("fa-eye").addClass("fa-eye-slash"); + } +} + +export function setup_password_visibility_toggle(password_field_id, password_selector) { + $(password_selector).on("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + toggle_password_visibility(password_field_id, password_selector); + }); +} diff --git a/static/js/portico/signup.js b/static/js/portico/signup.js index c60ca28785..66c5e10b19 100644 --- a/static/js/portico/signup.js +++ b/static/js/portico/signup.js @@ -24,6 +24,11 @@ $(() => { }); } + common.setup_password_visibility_toggle( + "#id_password", + "#id_password ~ .password_visibility_toggle", + ); + function highlight(class_to_add) { // Set a class on the enclosing control group. return function (element) { diff --git a/static/styles/components.css b/static/styles/components.css index 8ef70851b2..5a781c3887 100644 --- a/static/styles/components.css +++ b/static/styles/components.css @@ -120,3 +120,18 @@ i.zulip-icon.bot { */ font-size: 12px; } + +.password-div { + position: relative; + + .password_visibility_toggle { + position: absolute; + right: 10px; + top: 42px; + opacity: 0.6; + + &:hover { + opacity: 1; + } + } +} diff --git a/templates/zerver/login.html b/templates/zerver/login.html index 7787d5c437..80ca44add6 100644 --- a/templates/zerver/login.html +++ b/templates/zerver/login.html @@ -67,11 +67,12 @@ page can be easily identified in it's respective JavaScript file. --> -
- + +
{% else %} {% include "two_factor/_wizard_forms.html" %}