mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-12-28 16:00:24 +05:30
Improve oauth state restore logic
This commit is contained in:
parent
fed52bb1c6
commit
fdd56bc886
@ -162,12 +162,18 @@ export function oAuthValidate(oauthData) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} params
|
||||||
|
* @param {bool} params.accept=false
|
||||||
|
*
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
export function oAuthComplete(params = {}) {
|
export function oAuthComplete(params = {}) {
|
||||||
localStorage.removeItem('oauthData');
|
|
||||||
|
|
||||||
return wrapInLoader((dispatch, getState) =>
|
return wrapInLoader((dispatch, getState) =>
|
||||||
oauth.complete(getState().auth.oauth, params)
|
oauth.complete(getState().auth.oauth, params)
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
|
localStorage.removeItem('oauthData');
|
||||||
|
|
||||||
if (resp.redirectUri.startsWith('static_page')) {
|
if (resp.redirectUri.startsWith('static_page')) {
|
||||||
resp.code = resp.redirectUri.match(/code=(.+)&/)[1];
|
resp.code = resp.redirectUri.match(/code=(.+)&/)[1];
|
||||||
resp.redirectUri = resp.redirectUri.match(/^(.+)\?/)[1];
|
resp.redirectUri = resp.redirectUri.match(/^(.+)\?/)[1];
|
||||||
@ -195,6 +201,7 @@ export function oAuthComplete(params = {}) {
|
|||||||
|
|
||||||
function handleOauthParamsValidation(resp = {}) {
|
function handleOauthParamsValidation(resp = {}) {
|
||||||
dispatchBsod();
|
dispatchBsod();
|
||||||
|
localStorage.removeItem('oauthData');
|
||||||
|
|
||||||
// eslint-disable-next-line no-alert
|
// eslint-disable-next-line no-alert
|
||||||
resp.userMessage && setTimeout(() => alert(resp.userMessage), 500); // 500 ms to allow re-render
|
resp.userMessage && setTimeout(() => alert(resp.userMessage), 500); // 500 ms to allow re-render
|
||||||
|
@ -6,6 +6,7 @@ import OAuthState from './OAuthState';
|
|||||||
import ForgotPasswordState from './ForgotPasswordState';
|
import ForgotPasswordState from './ForgotPasswordState';
|
||||||
import RecoverPasswordState from './RecoverPasswordState';
|
import RecoverPasswordState from './RecoverPasswordState';
|
||||||
import ActivationState from './ActivationState';
|
import ActivationState from './ActivationState';
|
||||||
|
import CompleteState from './CompleteState';
|
||||||
import ResendActivationState from './ResendActivationState';
|
import ResendActivationState from './ResendActivationState';
|
||||||
|
|
||||||
export default class AuthFlow {
|
export default class AuthFlow {
|
||||||
@ -39,8 +40,6 @@ export default class AuthFlow {
|
|||||||
|
|
||||||
this.getState = store.getState.bind(store);
|
this.getState = store.getState.bind(store);
|
||||||
this.dispatch = store.dispatch.bind(store);
|
this.dispatch = store.dispatch.bind(store);
|
||||||
|
|
||||||
this.restoreOAuthState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(payload = {}) {
|
resolve(payload = {}) {
|
||||||
@ -131,6 +130,10 @@ export default class AuthFlow {
|
|||||||
|
|
||||||
this.currentRequest = request;
|
this.currentRequest = request;
|
||||||
|
|
||||||
|
if (this.restoreOAuthState()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case '/register':
|
case '/register':
|
||||||
this.setState(new RegisterState());
|
this.setState(new RegisterState());
|
||||||
@ -176,15 +179,25 @@ export default class AuthFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Tries to restore last oauth request, if it was stored in localStorage
|
||||||
|
* in last 2 hours
|
||||||
* @api private
|
* @api private
|
||||||
|
*
|
||||||
|
* @return {bool} - whether oauth state is being restored
|
||||||
*/
|
*/
|
||||||
restoreOAuthState() {
|
restoreOAuthState() {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(localStorage.getItem('oauthData'));
|
const data = JSON.parse(localStorage.getItem('oauthData'));
|
||||||
|
const expirationTime = 2 * 60 * 60 * 1000; // 2h
|
||||||
|
|
||||||
if (Date.now() - data.timestamp < 60 * 60 * 1000) {
|
if (Date.now() - data.timestamp < expirationTime) {
|
||||||
this.run('oAuthValidate', data.payload);
|
this.run('oAuthValidate', data.payload)
|
||||||
|
.then(() => this.setState(new CompleteState()));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} catch (err) {/* bad luck :( */}
|
} catch (err) {/* bad luck :( */}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import ForgotPasswordState from 'services/authFlow/ForgotPasswordState';
|
|||||||
import ActivationState from 'services/authFlow/ActivationState';
|
import ActivationState from 'services/authFlow/ActivationState';
|
||||||
import ResendActivationState from 'services/authFlow/ResendActivationState';
|
import ResendActivationState from 'services/authFlow/ResendActivationState';
|
||||||
import LoginState from 'services/authFlow/LoginState';
|
import LoginState from 'services/authFlow/LoginState';
|
||||||
|
import CompleteState from 'services/authFlow/CompleteState';
|
||||||
|
|
||||||
describe('AuthFlow', () => {
|
describe('AuthFlow', () => {
|
||||||
let flow;
|
let flow;
|
||||||
@ -34,10 +35,6 @@ describe('AuthFlow', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#setStore', () => {
|
describe('#setStore', () => {
|
||||||
afterEach(() => {
|
|
||||||
localStorage.removeItem('oauthData');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create #navigate, #getState, #dispatch', () => {
|
it('should create #navigate, #getState, #dispatch', () => {
|
||||||
flow.setStore({
|
flow.setStore({
|
||||||
getState() {},
|
getState() {},
|
||||||
@ -48,39 +45,64 @@ describe('AuthFlow', () => {
|
|||||||
expect(flow.dispatch, 'to be defined');
|
expect(flow.dispatch, 'to be defined');
|
||||||
expect(flow.navigate, 'to be defined');
|
expect(flow.navigate, 'to be defined');
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should restore oauth state from localStorage', () => {
|
describe('#restoreOAuthState', () => {
|
||||||
const oauthData = {};
|
let oauthData;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
oauthData = {foo: 'bar'};
|
||||||
localStorage.setItem('oauthData', JSON.stringify({
|
localStorage.setItem('oauthData', JSON.stringify({
|
||||||
timestamp: Date.now() - 10,
|
timestamp: Date.now() - 10,
|
||||||
payload: oauthData
|
payload: oauthData
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sinon.stub(flow, 'run').named('flow.run');
|
sinon.stub(flow, 'run').named('flow.run');
|
||||||
|
flow.run.returns({then: (fn) => fn()});
|
||||||
|
sinon.stub(flow, 'setState').named('flow.setState');
|
||||||
|
});
|
||||||
|
|
||||||
flow.setStore({
|
afterEach(() => {
|
||||||
getState() {},
|
localStorage.removeItem('oauthData');
|
||||||
dispatch() {}
|
});
|
||||||
});
|
|
||||||
|
it('should call to restoreOAuthState', () => {
|
||||||
|
sinon.stub(flow, 'restoreOAuthState').named('flow.restoreOAuthState');
|
||||||
|
|
||||||
|
flow.handleRequest({path: '/'});
|
||||||
|
|
||||||
|
expect(flow.restoreOAuthState, 'was called');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should restore oauth state from localStorage', () => {
|
||||||
|
flow.handleRequest({path: '/'});
|
||||||
|
|
||||||
expect(flow.run, 'to have a call satisfying', [
|
expect(flow.run, 'to have a call satisfying', [
|
||||||
'oAuthValidate', oauthData
|
'oAuthValidate', oauthData
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should transition to CompleteState', () => {
|
||||||
|
flow.handleRequest({path: '/'});
|
||||||
|
|
||||||
|
expect(flow.setState, 'to have a call satisfying', [
|
||||||
|
expect.it('to be a', CompleteState)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not handle current request', () => {
|
||||||
|
flow.handleRequest({path: '/'});
|
||||||
|
|
||||||
|
expect(flow.setState, 'was called once');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not restore outdated (>1h) oauth state', () => {
|
it('should not restore outdated (>1h) oauth state', () => {
|
||||||
const oauthData = {};
|
|
||||||
localStorage.setItem('oauthData', JSON.stringify({
|
localStorage.setItem('oauthData', JSON.stringify({
|
||||||
timestamp: Date.now() - 60 * 60 * 1000,
|
timestamp: Date.now() - 2 * 60 * 60 * 1000,
|
||||||
payload: oauthData
|
payload: oauthData
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sinon.stub(flow, 'run').named('flow.run');
|
flow.handleRequest({path: '/'});
|
||||||
|
|
||||||
flow.setStore({
|
|
||||||
getState() {},
|
|
||||||
dispatch() {}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(flow.run, 'was not called');
|
expect(flow.run, 'was not called');
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user