Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

social login Fix username validation javascript #9297

Merged
merged 3 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/9297.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Further improvements to the user experience of registration via single sign-on.
27 changes: 25 additions & 2 deletions synapse/res/templates/sso_auth_account_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -78,6 +91,15 @@
display: block;
margin-top: 8px;
}

output {
padding: 0 14px;
display: block;
}

output.error {
color: #FE2928;
}
</style>
</head>
<body>
Expand All @@ -87,12 +109,13 @@ <h1>Your account is nearly ready</h1>
</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">
Expand Down
78 changes: 59 additions & 19 deletions synapse/res/templates/sso_auth_account_details.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
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) {
let check_uri = 'check?username=' + encodeURIComponent(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) {
Expand All @@ -34,43 +44,73 @@ 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) {
handleError(err);
}
}, 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);
}
});