#389: automatically revoke account, when user clicks back during re-login

This commit is contained in:
SleepWalker
2018-02-28 23:58:02 +02:00
parent f1d33bf7ec
commit 9f926e42bc
9 changed files with 103 additions and 23 deletions

View File

@@ -29,7 +29,7 @@ type State = {
},
};
export { updateToken };
export { updateToken, activate };
/**
* @param {Account|object} account

View File

@@ -34,6 +34,10 @@ export function getActiveAccount(state: { accounts: State }): ?Account {
return state.accounts.available.find((account) => account.id === accountId);
}
export function getAvailableAccounts(state: { accounts: State }): Array<Account> {
return state.accounts.available;
}
export default function accounts(
state: State = {
active: null,

View File

@@ -15,7 +15,12 @@ import { create as createPopup } from 'components/ui/popup/actions';
import ContactForm from 'components/contact/ContactForm';
export { updateUser } from 'components/user/actions';
export { authenticate, logoutAll as logout } from 'components/accounts/actions';
export {
authenticate,
logoutAll as logout,
revoke as removeAccount,
activate as activateAccount
} from 'components/accounts/actions';
import { getCredentials } from './reducer';
/**

View File

@@ -25,6 +25,8 @@ type Request = {
type ActionId =
| 'updateUser'
| 'authenticate'
| 'activateAccount'
| 'removeAccount'
| 'logout'
| 'goBack'
| 'redirect'

View File

@@ -1,6 +1,7 @@
// @flow
import logger from 'services/logger';
import { getCredentials } from 'components/auth/reducer';
import { getActiveAccount, getAvailableAccounts } from 'components/accounts/reducer';
import AbstractState from './AbstractState';
import ChooseAccountState from './ChooseAccountState';
@@ -63,10 +64,24 @@ export default class PasswordState extends AbstractState {
}
goBack(context: AuthContext) {
const { isRelogin } = getCredentials(context.getState());
const state = context.getState();
const { isRelogin } = getCredentials(state);
if (isRelogin) {
context.setState(new ChooseAccountState());
const availableAccounts = getAvailableAccounts(state);
const accountToRemove = getActiveAccount(state);
if (availableAccounts.length === 1 || !accountToRemove) {
context.run('logout');
context.run('setLogin', null);
context.setState(new LoginState());
} else {
const accountToReplace = availableAccounts.find(({id}) => id !== accountToRemove.id);
context.run('activateAccount', accountToReplace);
context.run('removeAccount', accountToRemove);
context.setState(new ChooseAccountState());
}
} else {
context.run('setLogin', null);
context.setState(new LoginState());

View File

@@ -173,6 +173,13 @@ describe('PasswordState', () => {
it('should transition to ChooseAccountState if this is relogin', () => {
context.getState.returns({
accounts: {
active: 1,
available: [
{id: 1},
{id: 2}
]
},
auth: {
credentials: {
login: 'foo',
@@ -181,9 +188,34 @@ describe('PasswordState', () => {
}
});
expectRun(mock, 'activateAccount', { id: 2 });
expectRun(mock, 'removeAccount', { id: 1 });
expectState(mock, ChooseAccountState);
state.goBack(context);
});
it('should transition to LoginState if this is relogin and only one account available', () => {
context.getState.returns({
accounts: {
active: 1,
available: [
{id: 1},
]
},
auth: {
credentials: {
login: 'foo',
isRelogin: true,
}
}
});
expectRun(mock, 'logout');
expectRun(mock, 'setLogin', null);
expectState(mock, LoginState);
state.goBack(context);
});
});
});

View File

@@ -7,6 +7,8 @@ import * as actions from 'components/auth/actions';
const availableActions = {
updateUser: actions.updateUser,
authenticate: actions.authenticate,
activateAccount: actions.activateAccount,
removeAccount: actions.removeAccount,
logout: actions.logout,
goBack: actions.goBack,
redirect: actions.redirect,