Merge branch 'invalid-auth-fix' into 'develop'

Auth: clear `me` when ME_FETCH_SKIP is dispatched

See merge request soapbox-pub/soapbox-fe!588
actually-fix-tabs-bar
Alex Gleason 2021-07-09 21:45:15 +00:00
commit b6b95f06be
2 zmienionych plików z 60 dodań i 9 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import {
VERIFY_CREDENTIALS_FAIL, VERIFY_CREDENTIALS_FAIL,
SWITCH_ACCOUNT, SWITCH_ACCOUNT,
} from 'soapbox/actions/auth'; } from 'soapbox/actions/auth';
import { ME_FETCH_SKIP } from 'soapbox/actions/me';
describe('auth reducer', () => { describe('auth reducer', () => {
it('should return the initial state', () => { it('should return the initial state', () => {
@ -250,4 +251,13 @@ describe('auth reducer', () => {
expect(result.get('me')).toEqual('5678'); expect(result.get('me')).toEqual('5678');
}); });
}); });
describe('ME_FETCH_SKIP', () => {
it('sets `me` to null', () => {
const state = fromJS({ me: '1234' });
const action = { type: ME_FETCH_SKIP };
const result = reducer(state, action);
expect(result.get('me')).toEqual(null);
});
});
}); });

Wyświetl plik

@ -7,7 +7,8 @@ import {
VERIFY_CREDENTIALS_SUCCESS, VERIFY_CREDENTIALS_SUCCESS,
VERIFY_CREDENTIALS_FAIL, VERIFY_CREDENTIALS_FAIL,
} from '../actions/auth'; } from '../actions/auth';
import { Map as ImmutableMap, fromJS } from 'immutable'; import { ME_FETCH_SKIP } from '../actions/me';
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
const defaultState = ImmutableMap({ const defaultState = ImmutableMap({
app: ImmutableMap(), app: ImmutableMap(),
@ -16,31 +17,50 @@ const defaultState = ImmutableMap({
me: null, me: null,
}); });
const validId = id => typeof id === 'string' && id !== 'null' && id !== 'undefined';
const getSessionUser = () => { const getSessionUser = () => {
const id = sessionStorage.getItem('soapbox:auth:me'); const id = sessionStorage.getItem('soapbox:auth:me');
if (id && typeof id === 'string' && id !== 'null' && id !== 'undefined') { return validId(id) ? id : undefined;
return id;
} else {
return undefined;
}
}; };
const sessionUser = getSessionUser(); const sessionUser = getSessionUser();
const localState = fromJS(JSON.parse(localStorage.getItem('soapbox:auth'))); const localState = fromJS(JSON.parse(localStorage.getItem('soapbox:auth')));
// Checks if the user has an ID and access token
const validUser = user => {
try {
return validId(user.get('id')) && validId(user.get('access_token'));
} catch(e) {
return false;
}
};
// Finds the first valid user in the state
const firstValidUser = state => state.get('users', ImmutableMap()).find(validUser);
// If `me` doesn't match an existing user, attempt to shift it. // If `me` doesn't match an existing user, attempt to shift it.
const maybeShiftMe = state => { const maybeShiftMe = state => {
const users = state.get('users', ImmutableMap()); const users = state.get('users', ImmutableMap());
const me = state.get('me'); const me = state.get('me');
if (!users.get(me)) { if (!validUser(users.get(me))) {
return state.set('me', users.first(ImmutableMap()).get('id', null)); const nextUser = firstValidUser(state);
return state.set('me', nextUser ? nextUser.get('id') : null);
} else { } else {
return state; return state;
} }
}; };
const setSessionUser = state => state.update('me', null, me => sessionUser || me); // Set the user from the session or localStorage, whichever is valid first
const setSessionUser = state => state.update('me', null, me => {
const user = ImmutableList([
state.getIn(['users', sessionUser]),
state.getIn(['users', me]),
]).find(validUser);
return user ? user.get('id') : null;
});
// Upgrade the initial state // Upgrade the initial state
const migrateLegacy = state => { const migrateLegacy = state => {
@ -63,6 +83,24 @@ const migrateLegacy = state => {
}); });
}; };
// Checks the state and makes it valid
const sanitizeState = state => {
return state.withMutations(state => {
// Remove invalid users, ensure ID match
state.update('users', ImmutableMap(), users => (
users.filter((user, id) => (
validUser(user) && user.get('id') === id
))
));
// Remove mismatched tokens
state.update('tokens', ImmutableMap(), tokens => (
tokens.filter((token, id) => (
validId(id) && token.get('access_token') === id
))
));
});
};
const persistAuth = state => localStorage.setItem('soapbox:auth', JSON.stringify(state.toJS())); const persistAuth = state => localStorage.setItem('soapbox:auth', JSON.stringify(state.toJS()));
const persistSession = state => { const persistSession = state => {
@ -82,6 +120,7 @@ const initialize = state => {
maybeShiftMe(state); maybeShiftMe(state);
setSessionUser(state); setSessionUser(state);
migrateLegacy(state); migrateLegacy(state);
sanitizeState(state);
persistState(state); persistState(state);
}); });
}; };
@ -158,6 +197,8 @@ const reducer = (state, action) => {
return action.error.response.status === 403 ? deleteToken(state, action.token) : state; return action.error.response.status === 403 ? deleteToken(state, action.token) : state;
case SWITCH_ACCOUNT: case SWITCH_ACCOUNT:
return state.set('me', action.accountId); return state.set('me', action.accountId);
case ME_FETCH_SKIP:
return state.set('me', null);
default: default:
return state; return state;
} }