Merge branch 'masto-auth-error' into 'develop'

Mastodon: return a friendlier login error than 'invalid_grant', redirect password reset to backend

See merge request soapbox-pub/soapbox-fe!732
This commit is contained in:
Alex Gleason 2021-09-08 16:49:15 +00:00
commit f2384ef178
6 changed files with 49 additions and 9 deletions

View file

@ -163,10 +163,18 @@ export function logIn(intl, username, password) {
return dispatch(createUserToken(username, password));
}).catch(error => {
if (error.response.data.error === 'mfa_required') {
// If MFA is required, throw the error and handle it in the component.
throw error;
} else if(error.response.data.error) {
} else if (error.response.data.error === 'invalid_grant') {
// Mastodon returns this user-unfriendly error as a catch-all
// for everything from "bad request" to "wrong password".
// Assume our code is correct and it's a wrong password.
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
} else if (error.response.data.error) {
// If the backend returns an error, display it.
dispatch(snackbar.error(error.response.data.error));
} else {
// Return "wrong password" message.
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
}
throw error;

View file

@ -23,7 +23,7 @@ export function obtainOAuthToken(params, baseURL) {
dispatch({ type: OAUTH_TOKEN_CREATE_SUCCESS, params, token });
return token;
}).catch(error => {
dispatch({ type: OAUTH_TOKEN_CREATE_FAIL, params, error });
dispatch({ type: OAUTH_TOKEN_CREATE_FAIL, params, error, skipAlert: true });
throw error;
});
};

View file

@ -4,7 +4,7 @@
* @module soapbox/build_config
*/
const { trim } = require('lodash');
const { trim, trimEnd } = require('lodash');
const {
NODE_ENV,
@ -15,7 +15,7 @@ const {
const sanitizeURL = url => {
try {
return new URL(url).toString();
return trimEnd(new URL(url).toString(), '/');
} catch {
return '';
}

View file

@ -3,18 +3,30 @@ import { connect } from 'react-redux';
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
import { Link } from 'react-router-dom';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { getFeatures } from 'soapbox/utils/features';
import { getBaseURL } from 'soapbox/utils/state';
const messages = defineMessages({
username: { id: 'login.fields.username_placeholder', defaultMessage: 'Username' },
password: { id: 'login.fields.password_placeholder', defaultMessage: 'Password' },
});
export default @connect()
const mapStateToProps = state => {
const instance = state.get('instance');
const features = getFeatures(instance);
return {
baseURL: getBaseURL(state),
hasResetPasswordAPI: features.resetPasswordAPI,
};
};
export default @connect(mapStateToProps)
@injectIntl
class LoginForm extends ImmutablePureComponent {
render() {
const { intl, isLoading, handleSubmit } = this.props;
const { intl, isLoading, handleSubmit, baseURL, hasResetPasswordAPI } = this.props;
return (
<form className='simple_form new_user' method='post' onSubmit={handleSubmit}>
@ -43,9 +55,15 @@ class LoginForm extends ImmutablePureComponent {
/>
</div>
<p className='hint subtle-hint'>
<Link to='/auth/reset_password'>
<FormattedMessage id='login.reset_password_hint' defaultMessage='Trouble logging in?' />
</Link>
{hasResetPasswordAPI ? (
<Link to='/auth/reset_password'>
<FormattedMessage id='login.reset_password_hint' defaultMessage='Trouble logging in?' />
</Link>
) : (
<a href={`${baseURL}/auth/password/new`}>
<FormattedMessage id='login.reset_password_hint' defaultMessage='Trouble logging in?' />
</a>
)}
</p>
</div>
</fieldset>

View file

@ -24,6 +24,7 @@ export const getFeatures = createSelector([
securityAPI: v.software === 'Pleroma',
settingsStore: v.software === 'Pleroma',
accountAliasesAPI: v.software === 'Pleroma',
resetPasswordAPI: v.software === 'Pleroma',
};
});

View file

@ -6,6 +6,7 @@
import { getSoapboxConfig } from'soapbox/actions/soapbox';
import { isPrerendered } from 'soapbox/precheck';
import { isURL } from 'soapbox/utils/auth';
import { getBaseURL as getAccountBaseURL } from 'soapbox/utils/accounts';
import { BACKEND_URL } from 'soapbox/build_config';
export const displayFqn = state => {
@ -27,3 +28,15 @@ export const isStandalone = state => {
const instanceFetchFailed = state.getIn(['meta', 'instance_fetch_failed'], false);
return isURL(BACKEND_URL) ? false : (!isPrerendered && instanceFetchFailed);
};
/**
* Get the baseURL of the instance.
* @param {object} state
* @returns {string} url
*/
export const getBaseURL = state => {
const me = state.get('me');
const account = state.getIn(['accounts', me]);
return isURL(BACKEND_URL) ? BACKEND_URL : getAccountBaseURL(account);
};