MFA: setupMfa/confirmMfa, throw errors to component, don't be optimistic

This commit is contained in:
Alex Gleason 2022-01-12 11:22:46 -06:00
parent c1cfd2ca2a
commit e94acbc44f
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
3 changed files with 49 additions and 21 deletions

View file

@ -60,10 +60,12 @@ export function confirmMfa(method, code, password) {
return (dispatch, getState) => {
const params = { code, password };
dispatch({ type: MFA_CONFIRM_REQUEST, method, code });
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(() => {
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(({ data }) => {
dispatch({ type: MFA_CONFIRM_SUCCESS, method, code });
return data;
}).catch(error => {
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error });
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error, skipAlert: true });
throw error;
});
};
}
@ -71,10 +73,12 @@ export function confirmMfa(method, code, password) {
export function disableMfa(method, password) {
return (dispatch, getState) => {
dispatch({ type: MFA_DISABLE_REQUEST, method });
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(response => {
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(({ data }) => {
dispatch({ type: MFA_DISABLE_SUCCESS, method });
return data;
}).catch(error => {
dispatch({ type: MFA_DISABLE_FAIL, method });
dispatch({ type: MFA_DISABLE_FAIL, method, skipAlert: true });
throw error;
});
};
}

View file

@ -118,31 +118,36 @@ class DisableOtpForm extends ImmutablePureComponent {
state = {
password: '',
isLoading: false,
}
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
}
handleOtpDisableClick = e => {
handleSubmit = e => {
const { password } = this.state;
const { dispatch, intl } = this.props;
this.setState({ isLoading: true });
dispatch(disableMfa('totp', password)).then(() => {
dispatch(snackbar.success(intl.formatMessage(messages.mfaDisableSuccess)));
this.context.router.history.push('../auth/edit');
}).catch(error => {
dispatch(snackbar.error(intl.formatMessage(messages.disableFail)));
this.setState({ isLoading: false });
});
this.context.router.history.push('../auth/edit');
e.preventDefault();
}
render() {
const { intl } = this.props;
const { isLoading, password } = this.state;
return (
<SimpleForm>
<SimpleForm onSubmit={this.handleSubmit} disabled={isLoading}>
<div className='security-settings-panel'>
<h1 className='security-settings-panel__setup-otp'>
<FormattedMessage id='mfa.otp_enabled_title' defaultMessage='OTP Enabled' />
@ -150,10 +155,16 @@ class DisableOtpForm extends ImmutablePureComponent {
<div><FormattedMessage id='mfa.otp_enabled_description' defaultMessage='You have enabled two-factor authentication via OTP.' /></div>
<div><FormattedMessage id='mfa.mfa_disable_enter_password' defaultMessage='Enter your current password to disable two-factor auth:' /></div>
<ShowablePassword
disabled={isLoading}
name='password'
onChange={this.handleInputChange}
value={password}
/>
<Button
disabled={isLoading}
className='button button-primary disable'
text={intl.formatMessage(messages.mfa_setup_disable_button)}
/>
<Button className='button button-primary disable' text={intl.formatMessage(messages.mfa_setup_disable_button)} onClick={this.handleOtpDisableClick} />
</div>
</SimpleForm>
);
@ -255,7 +266,7 @@ class OtpConfirmForm extends ImmutablePureComponent {
state = {
password: '',
done: false,
isLoading: false,
code: '',
qrCodeURI: '',
confirm_key: '',
@ -275,26 +286,29 @@ class OtpConfirmForm extends ImmutablePureComponent {
this.setState({ [e.target.name]: e.target.value });
}
handleOtpConfirmClick = e => {
const { code, password } = this.state;
handleSubmit = e => {
const { dispatch, intl } = this.props;
const { code, password } = this.state;
this.setState({ isLoading: true });
dispatch(confirmMfa('totp', code, password)).then(() => {
dispatch(snackbar.success(intl.formatMessage(messages.mfaConfirmSuccess)));
this.context.router.history.push('../auth/edit');
}).catch(error => {
dispatch(snackbar.error(intl.formatMessage(messages.confirmFail)));
this.setState({ isLoading: false });
});
this.context.router.history.push('../auth/edit');
e.preventDefault();
}
render() {
const { intl } = this.props;
const { qrCodeURI, confirm_key } = this.state;
const { isLoading, qrCodeURI, confirm_key, password, code } = this.state;
return (
<SimpleForm>
<SimpleForm onSubmit={this.handleSubmit} disabled={isLoading}>
<div className='security-settings-panel'>
<fieldset disabled={false}>
@ -319,19 +333,34 @@ class OtpConfirmForm extends ImmutablePureComponent {
name='code'
onChange={this.handleInputChange}
autoComplete='off'
value={code}
disabled={isLoading}
/>
<div><FormattedMessage id='mfa.mfa_setup_enter_password' defaultMessage='Enter your current password to confirm your identity:' /></div>
<ShowablePassword
name='password'
onChange={this.handleInputChange}
value={password}
disabled={isLoading}
/>
</div>
</FieldsGroup>
</fieldset>
<div className='security-settings-panel__setup-otp__buttons'>
<Button className='button button-secondary cancel' text={intl.formatMessage(messages.mfa_cancel_button)} onClick={this.handleCancelClick} />
<Button className='button button-primary setup' text={intl.formatMessage(messages.mfa_setup_confirm_button)} onClick={this.handleOtpConfirmClick} />
<Button
type='button'
className='button button-secondary cancel'
text={intl.formatMessage(messages.mfa_cancel_button)}
onClick={this.handleCancelClick}
disabled={isLoading}
/>
<Button
type='submit'
className='button button-primary setup'
text={intl.formatMessage(messages.mfa_setup_confirm_button)}
disabled={isLoading}
/>
</div>
</div>
</SimpleForm>

View file

@ -3,9 +3,7 @@ import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
import {
MFA_FETCH_SUCCESS,
MFA_CONFIRM_SUCCESS,
MFA_DISABLE_REQUEST,
MFA_DISABLE_SUCCESS,
MFA_DISABLE_FAIL,
} from '../actions/mfa';
import {
FETCH_TOKENS_SUCCESS,
@ -49,11 +47,8 @@ export default function security(state = initialState, action) {
return importMfa(state, fromJS(action.data));
case MFA_CONFIRM_SUCCESS:
return enableMfa(state, action.method);
case MFA_DISABLE_REQUEST:
case MFA_DISABLE_SUCCESS:
return disableMfa(state, action.method);
case MFA_DISABLE_FAIL:
return enableMfa(state, action.method);
default:
return state;
}