diff --git a/package.json b/package.json index ad211e2..286ed47 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Organized and powerful matrix client.", "main": "index.js", "engines": { - "npm": "6.14.11", - "node": "14.6.0" + "npm": ">=6.14.11", + "node": ">=14.6.0" }, "scripts": { "start": "webpack serve --config ./webpack.dev.js --open", diff --git a/src/app/templates/auth/Auth.jsx b/src/app/templates/auth/Auth.jsx index cd287e2..d66617b 100644 --- a/src/app/templates/auth/Auth.jsx +++ b/src/app/templates/auth/Auth.jsx @@ -13,8 +13,12 @@ import Spinner from '../../atoms/spinner/Spinner'; import CinnySvg from '../../../../public/res/svg/cinny.svg'; -const USERNAME_REGEX = /^[a-z0-9_\-.=/]+$/; -const BAD_USERNAME_ERROR = 'Username must contain only lowercase letters, numbers, dashes and underscores.'; +// This regex validates historical usernames, which don't satisy today's username requirements. +// See https://matrix.org/docs/spec/appendices#id13 for more info. +const LOCALPART_LOGIN_REGEX = /^[!-9|;-~]+$/; +const LOCALPART_SIGNUP_REGEX = /^[a-z0-9_\-.=/]+$/; +const BAD_LOCALPART_ERROR = 'Username must contain only a-z, 0-9, ., _, =, -, and /.'; +const USER_ID_TOO_LONG_ERROR = 'Your user ID, including the hostname, can\'t be more than 255 characters long.'; const PASSWORD_REGEX = /.+/; const PASSWORD_STRENGHT_REGEX = /^(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\d\s:])([^\s]){8,16}$/; @@ -52,6 +56,18 @@ function validateOnChange(e, regex, error) { document.getElementById('auth_submit-btn').disabled = false; } +/** + * Normalizes a username into a standard format. + * + * Removes leading and trailing whitespaces and leading "@" symbols. + * @param {string} rawUsername A raw-input username, which may include invalid characters. + * @returns {string} + */ +function normalizeUsername(rawUsername) { + const noLeadingAt = rawUsername.indexOf('@') === 0 ? rawUsername.substr(1) : rawUsername; + return noLeadingAt.trim(); +} + function Auth({ type }) { const [process, changeProcess] = useState(null); const usernameRef = useRef(null); @@ -99,12 +115,17 @@ function Auth({ type }) { document.getElementById('auth_submit-btn').disabled = true; document.getElementById('auth_error').style.display = 'none'; - if (!isValidInput(usernameRef.current.value, USERNAME_REGEX)) { - showBadInputError(usernameRef.current, BAD_USERNAME_ERROR); + /** @type {string} */ + const rawUsername = usernameRef.current.value; + /** @type {string} */ + const normalizedUsername = normalizeUsername(rawUsername); + + if (!isValidInput(normalizedUsername, LOCALPART_LOGIN_REGEX)) { + showBadInputError(usernameRef.current, BAD_LOCALPART_ERROR); return; } - auth.login(usernameRef.current.value, homeserverRef.current.value, passwordRef.current.value) + auth.login(normalizedUsername, homeserverRef.current.value, passwordRef.current.value) .then(() => { document.getElementById('auth_submit-btn').disabled = false; window.location.replace('/'); @@ -122,8 +143,8 @@ function Auth({ type }) { document.getElementById('auth_submit-btn').disabled = true; document.getElementById('auth_error').style.display = 'none'; - if (!isValidInput(usernameRef.current.value, USERNAME_REGEX)) { - showBadInputError(usernameRef.current, BAD_USERNAME_ERROR); + if (!isValidInput(usernameRef.current.value, LOCALPART_SIGNUP_REGEX)) { + showBadInputError(usernameRef.current, BAD_LOCALPART_ERROR); return; } if (!isValidInput(passwordRef.current.value, PASSWORD_STRENGHT_REGEX)) { @@ -138,6 +159,10 @@ function Auth({ type }) { showBadInputError(emailRef.current, BAD_EMAIL_ERROR); return; } + if (`@${usernameRef.current.value}:${homeserverRef.current.value}`.length > 255) { + showBadInputError(usernameRef.current, USER_ID_TOO_LONG_ERROR); + return; + } register(); } @@ -171,7 +196,9 @@ function Auth({ type }) {
validateOnChange(e, USERNAME_REGEX, BAD_USERNAME_ERROR)} + onChange={(e) => (type === 'login' + ? validateOnChange(e, LOCALPART_LOGIN_REGEX, BAD_LOCALPART_ERROR) + : validateOnChange(e, LOCALPART_SIGNUP_REGEX, BAD_LOCALPART_ERROR))} id="auth_username" label="Username" required