diff --git a/app/soapbox/actions/auth.ts b/app/soapbox/actions/auth.ts index e219741164..d3252e7fb0 100644 --- a/app/soapbox/actions/auth.ts +++ b/app/soapbox/actions/auth.ts @@ -207,9 +207,19 @@ export const loadCredentials = (token: string, accountUrl: string) => }) .catch(() => dispatch(verifyCredentials(token, accountUrl))); +/** Trim the username and strip the leading @. */ +const normalizeUsername = (username: string): string => { + const trimmed = username.trim(); + if (trimmed[0] === '@') { + return trimmed.slice(1); + } else { + return trimmed; + } +}; + export const logIn = (username: string, password: string) => (dispatch: AppDispatch) => dispatch(getAuthApp()).then(() => { - return dispatch(createUserToken(username, password)); + return dispatch(createUserToken(normalizeUsername(username), password)); }).catch((error: AxiosError) => { if ((error.response?.data as any).error === 'mfa_required') { // If MFA is required, throw the error and handle it in the component. diff --git a/app/soapbox/features/auth_login/components/login_form.tsx b/app/soapbox/features/auth_login/components/login_form.tsx index 64145453c7..948a6bc31a 100644 --- a/app/soapbox/features/auth_login/components/login_form.tsx +++ b/app/soapbox/features/auth_login/components/login_form.tsx @@ -40,6 +40,7 @@ const LoginForm: React.FC = ({ isLoading, handleSubmit }) => { autoComplete='off' autoCorrect='off' autoCapitalize='off' + pattern='^[@a-zA-Z\d_-]+$' required /> diff --git a/app/soapbox/features/public_layout/components/header.tsx b/app/soapbox/features/public_layout/components/header.tsx index 1813c7d8ab..6ba216ee69 100644 --- a/app/soapbox/features/public_layout/components/header.tsx +++ b/app/soapbox/features/public_layout/components/header.tsx @@ -128,10 +128,14 @@ const Header = () => { setUsername(event.target.value)} + onChange={(event) => setUsername(event.target.value.trim())} type='text' placeholder={intl.formatMessage(messages.username)} className='max-w-[200px]' + autoComplete='off' + autoCorrect='off' + autoCapitalize='off' + pattern='^[@a-zA-Z\d_-]+$' /> { type='password' placeholder={intl.formatMessage(messages.password)} className='max-w-[200px]' + autoComplete='off' + autoCorrect='off' + autoCapitalize='off' />