diff options
author | Richard van der Hoff <1389908+richvdh@users.noreply.github.com> | 2021-02-03 17:52:55 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-03 17:52:55 +0000 |
commit | 7a0dcea3e5a9a9f1dae30947b62d0a183e6d0668 (patch) | |
tree | 11b2ecad51a31ffdffd62e8e0d86ffba89b4bdb0 /synapse/res/templates | |
parent | Honour ratelimit flag for application services for invite ratelimiting (#9302) (diff) | |
download | synapse-7a0dcea3e5a9a9f1dae30947b62d0a183e6d0668.tar.xz |
social login Fix username validation javascript (#9297)
* fix validation and don't use built-in validation UI Co-authored-by: Bruno Windels <brunow@element.io>
Diffstat (limited to 'synapse/res/templates')
-rw-r--r-- | synapse/res/templates/sso_auth_account_details.html | 27 | ||||
-rw-r--r-- | synapse/res/templates/sso_auth_account_details.js | 78 |
2 files changed, 84 insertions, 21 deletions
diff --git a/synapse/res/templates/sso_auth_account_details.html b/synapse/res/templates/sso_auth_account_details.html index 105063825a..36850a2d6a 100644 --- a/synapse/res/templates/sso_auth_account_details.html +++ b/synapse/res/templates/sso_auth_account_details.html @@ -18,6 +18,19 @@ font-size: 12px; } + .username_input.invalid { + border-color: #FE2928; + } + + .username_input.invalid input, .username_input.invalid label { + color: #FE2928; + } + + .username_input div, .username_input input { + line-height: 18px; + font-size: 14px; + } + .username_input label { position: absolute; top: -8px; @@ -78,6 +91,15 @@ display: block; margin-top: 8px; } + + output { + padding: 0 14px; + display: block; + } + + output.error { + color: #FE2928; + } </style> </head> <body> @@ -87,12 +109,13 @@ </header> <main> <form method="post" class="form__input" id="form"> - <div class="username_input"> + <div class="username_input" id="username_input"> <label for="field-username">Username</label> <div class="prefix">@</div> - <input type="text" name="username" id="field-username" autofocus required pattern="[a-z0-9\-=_\/\.]+"> + <input type="text" name="username" id="field-username" autofocus> <div class="postfix">:{{ server_name }}</div> </div> + <output for="username_input" id="field-username-output"></output> <input type="submit" value="Continue" class="primary-button"> {% if user_attributes %} <section class="idp-pick-details"> diff --git a/synapse/res/templates/sso_auth_account_details.js b/synapse/res/templates/sso_auth_account_details.js index deef419bb6..3c45df9078 100644 --- a/synapse/res/templates/sso_auth_account_details.js +++ b/synapse/res/templates/sso_auth_account_details.js @@ -1,14 +1,24 @@ const usernameField = document.getElementById("field-username"); +const usernameOutput = document.getElementById("field-username-output"); +const form = document.getElementById("form"); + +// needed to validate on change event when no input was changed +let needsValidation = true; +let isValid = false; function throttle(fn, wait) { let timeout; - return function() { + const throttleFn = function() { const args = Array.from(arguments); if (timeout) { clearTimeout(timeout); } timeout = setTimeout(fn.bind.apply(fn, [null].concat(args)), wait); - } + }; + throttleFn.cancelQueued = function() { + clearTimeout(timeout); + }; + return throttleFn; } function checkUsernameAvailable(username) { @@ -16,14 +26,14 @@ function checkUsernameAvailable(username) { return fetch(check_uri, { // include the cookie "credentials": "same-origin", - }).then((response) => { + }).then(function(response) { if(!response.ok) { // for non-200 responses, raise the body of the response as an exception return response.text().then((text) => { throw new Error(text); }); } else { return response.json(); } - }).then((json) => { + }).then(function(json) { if(json.error) { return {message: json.error}; } else if(json.available) { @@ -34,33 +44,49 @@ function checkUsernameAvailable(username) { }); } +const allowedUsernameCharacters = new RegExp("^[a-z0-9\\.\\_\\-\\/\\=]+$"); +const allowedCharactersString = "lowercase letters, digits, ., _, -, /, ="; + +function reportError(error) { + throttledCheckUsernameAvailable.cancelQueued(); + usernameOutput.innerText = error; + usernameOutput.classList.add("error"); + usernameField.parentElement.classList.add("invalid"); + usernameField.focus(); +} + function validateUsername(username) { - usernameField.setCustomValidity(""); - if (usernameField.validity.valueMissing) { - usernameField.setCustomValidity("Please provide a username"); - return; + isValid = false; + needsValidation = false; + usernameOutput.innerText = ""; + usernameField.parentElement.classList.remove("invalid"); + usernameOutput.classList.remove("error"); + if (!username) { + return reportError("Please provide a username"); } - if (usernameField.validity.patternMismatch) { - usernameField.setCustomValidity("Invalid username, please only use " + allowedCharactersString); - return; + if (username.length > 255) { + return reportError("Too long, please choose something shorter"); } - usernameField.setCustomValidity("Checking if username is available …"); + if (!allowedUsernameCharacters.test(username)) { + return reportError("Invalid username, please only use " + allowedCharactersString); + } + usernameOutput.innerText = "Checking if username is available …"; throttledCheckUsernameAvailable(username); } const throttledCheckUsernameAvailable = throttle(function(username) { - const handleError = function(err) { + const handleError = function(err) { // don't prevent form submission on error - usernameField.setCustomValidity(""); - console.log(err.message); + usernameOutput.innerText = ""; + isValid = true; }; try { checkUsernameAvailable(username).then(function(result) { if (!result.available) { - usernameField.setCustomValidity(result.message); - usernameField.reportValidity(); + reportError(result.message); } else { - usernameField.setCustomValidity(""); + isValid = true; + usernameOutput.innerText = ""; } }, handleError); } catch (err) { @@ -68,9 +94,23 @@ const throttledCheckUsernameAvailable = throttle(function(username) { } }, 500); +form.addEventListener("submit", function(evt) { + if (needsValidation) { + validateUsername(usernameField.value); + evt.preventDefault(); + return; + } + if (!isValid) { + evt.preventDefault(); + usernameField.focus(); + return; + } +}); usernameField.addEventListener("input", function(evt) { validateUsername(usernameField.value); }); usernameField.addEventListener("change", function(evt) { - validateUsername(usernameField.value); + if (needsValidation) { + validateUsername(usernameField.value); + } }); |