2017-08-23 00:09:08 +05:30
|
|
|
// @flow
|
2017-12-26 01:33:21 +05:30
|
|
|
import logger from 'services/logger';
|
|
|
|
import request, { InternalServerError } from 'services/request';
|
2016-10-30 17:42:49 +05:30
|
|
|
import accounts from 'services/api/accounts';
|
2016-06-04 19:16:39 +05:30
|
|
|
|
2016-11-05 15:41:41 +05:30
|
|
|
const authentication = {
|
2016-06-04 19:16:39 +05:30
|
|
|
login({
|
2017-08-23 00:09:08 +05:30
|
|
|
login,
|
|
|
|
password,
|
|
|
|
totp,
|
2016-06-04 19:16:39 +05:30
|
|
|
rememberMe = false
|
2017-08-23 00:09:08 +05:30
|
|
|
}: {
|
|
|
|
login: string,
|
|
|
|
password?: string,
|
|
|
|
totp?: string,
|
|
|
|
rememberMe: bool
|
2016-06-04 19:16:39 +05:30
|
|
|
}) {
|
|
|
|
return request.post(
|
|
|
|
'/api/authentication/login',
|
2017-09-09 19:52:19 +05:30
|
|
|
{login, password, totp, rememberMe},
|
2016-12-25 23:39:47 +05:30
|
|
|
{token: null}
|
2017-09-09 19:52:19 +05:30
|
|
|
);
|
2016-06-04 20:28:29 +05:30
|
|
|
},
|
|
|
|
|
2016-11-15 11:25:15 +05:30
|
|
|
/**
|
|
|
|
* @param {object} options
|
2017-08-23 00:09:08 +05:30
|
|
|
* @param {string} [options.token] - an optional token to overwrite headers
|
2016-11-15 11:25:15 +05:30
|
|
|
* in middleware and disable token auto-refresh
|
|
|
|
*
|
|
|
|
* @return {Promise}
|
|
|
|
*/
|
2017-12-31 00:34:31 +05:30
|
|
|
logout(options: ?{
|
|
|
|
token: string
|
|
|
|
}) {
|
2016-11-15 11:25:15 +05:30
|
|
|
return request.post('/api/authentication/logout', {}, {
|
2017-12-31 00:34:31 +05:30
|
|
|
token: options && options.token
|
2016-11-15 11:25:15 +05:30
|
|
|
});
|
2016-06-28 15:43:27 +05:30
|
|
|
},
|
|
|
|
|
2016-07-28 10:33:30 +05:30
|
|
|
forgotPassword({
|
2017-08-23 00:09:08 +05:30
|
|
|
login,
|
|
|
|
captcha
|
|
|
|
}: {
|
|
|
|
login: string,
|
|
|
|
captcha: string
|
2016-07-28 10:33:30 +05:30
|
|
|
}) {
|
|
|
|
return request.post(
|
|
|
|
'/api/authentication/forgot-password',
|
2017-04-18 22:17:46 +05:30
|
|
|
{login, captcha},
|
2017-02-24 02:51:24 +05:30
|
|
|
{token: null}
|
2016-07-28 10:33:30 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
recoverPassword({
|
2017-08-23 00:09:08 +05:30
|
|
|
key,
|
|
|
|
newPassword,
|
|
|
|
newRePassword
|
|
|
|
}: {
|
|
|
|
key: string,
|
|
|
|
newPassword: string,
|
|
|
|
newRePassword: string
|
2016-07-28 10:33:30 +05:30
|
|
|
}) {
|
|
|
|
return request.post(
|
|
|
|
'/api/authentication/recover-password',
|
2017-02-24 02:51:24 +05:30
|
|
|
{key, newPassword, newRePassword},
|
|
|
|
{token: null}
|
2016-07-28 10:33:30 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2016-10-30 17:42:49 +05:30
|
|
|
/**
|
|
|
|
* Resolves if token is valid
|
|
|
|
*
|
|
|
|
* @param {object} options
|
|
|
|
* @param {string} options.token
|
|
|
|
* @param {string} options.refreshToken
|
|
|
|
*
|
|
|
|
* @return {Promise} - resolves with options.token or with a new token
|
2017-01-06 11:34:14 +05:30
|
|
|
* if it was refreshed. As a side effect the response
|
|
|
|
* will have a `user` field with current user data
|
2016-10-30 17:42:49 +05:30
|
|
|
*/
|
2017-08-23 00:09:08 +05:30
|
|
|
validateToken({token, refreshToken}: {
|
|
|
|
token: string,
|
2017-12-31 00:34:31 +05:30
|
|
|
refreshToken: ?string
|
2017-08-23 00:09:08 +05:30
|
|
|
}) {
|
2016-11-05 15:41:41 +05:30
|
|
|
return new Promise((resolve) => {
|
|
|
|
if (typeof token !== 'string') {
|
|
|
|
throw new Error('token must be a string');
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve();
|
|
|
|
})
|
2017-08-23 02:30:10 +05:30
|
|
|
.then(() => accounts.current({token}))
|
|
|
|
.then((user) => ({token, refreshToken, user}))
|
2017-12-31 00:34:31 +05:30
|
|
|
.catch((resp) =>
|
|
|
|
this.handleTokenError(resp, refreshToken)
|
|
|
|
// TODO: use recursion here
|
|
|
|
.then(({token}) =>
|
|
|
|
accounts.current({token})
|
|
|
|
.then((user) => ({token, refreshToken, user}))
|
|
|
|
)
|
|
|
|
);
|
|
|
|
},
|
2017-12-26 01:33:21 +05:30
|
|
|
|
2017-12-31 00:34:31 +05:30
|
|
|
handleTokenError(resp: Error | { message: string }, refreshToken: ?string): Promise<{
|
|
|
|
token: string,
|
|
|
|
}> {
|
|
|
|
if (resp instanceof InternalServerError) {
|
|
|
|
// delegate error recovering to the bsod middleware
|
|
|
|
return new Promise(() => {});
|
|
|
|
}
|
2017-12-26 01:33:21 +05:30
|
|
|
|
2017-12-31 00:34:31 +05:30
|
|
|
if (refreshToken) {
|
|
|
|
if ([
|
|
|
|
'Token expired',
|
|
|
|
'Incorrect token',
|
|
|
|
'You are requesting with an invalid credential.'
|
|
|
|
].includes(resp.message)) {
|
|
|
|
return authentication.requestToken(refreshToken);
|
|
|
|
}
|
2016-11-05 15:41:41 +05:30
|
|
|
|
2017-12-31 00:34:31 +05:30
|
|
|
logger.error('Unexpected error during token validation', {
|
|
|
|
resp
|
2017-08-23 02:30:10 +05:30
|
|
|
});
|
2017-12-31 00:34:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.reject(resp);
|
2016-10-30 17:42:49 +05:30
|
|
|
},
|
|
|
|
|
2016-08-10 00:47:49 +05:30
|
|
|
/**
|
|
|
|
* Request new access token using a refreshToken
|
|
|
|
*
|
|
|
|
* @param {string} refreshToken
|
|
|
|
*
|
|
|
|
* @return {Promise} - resolves to {token}
|
|
|
|
*/
|
2017-08-23 00:09:08 +05:30
|
|
|
requestToken(refreshToken: string): Promise<{token: string}> {
|
2016-06-04 20:28:29 +05:30
|
|
|
return request.post(
|
|
|
|
'/api/authentication/refresh-token',
|
2016-12-13 01:37:49 +05:30
|
|
|
{refresh_token: refreshToken}, // eslint-disable-line
|
|
|
|
{token: null}
|
2017-12-31 00:34:31 +05:30
|
|
|
)
|
|
|
|
.then((resp: {access_token: string}) => ({
|
|
|
|
token: resp.access_token
|
|
|
|
}))
|
|
|
|
.catch((resp) => {
|
|
|
|
const errors = resp.errors || {};
|
|
|
|
|
|
|
|
if (errors.refresh_token !== 'error.refresh_token_not_exist') {
|
|
|
|
logger.error('Failed refreshing token: unknown error', {
|
|
|
|
resp
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.reject(resp);
|
|
|
|
});
|
2016-06-04 19:16:39 +05:30
|
|
|
}
|
|
|
|
};
|
2016-11-05 15:41:41 +05:30
|
|
|
|
|
|
|
export default authentication;
|