From 98f237b4bd9ae2b0c213d9804969c8ccb1c6d57b Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 3 Nov 2023 16:10:46 +0100 Subject: [PATCH 01/19] new middleware for auth:before --- loopback/server/middleware.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/loopback/server/middleware.json b/loopback/server/middleware.json index 31a2f113b..45e8ada23 100644 --- a/loopback/server/middleware.json +++ b/loopback/server/middleware.json @@ -34,12 +34,15 @@ } } }, + "auth:before": { + "./middleware/renew-token": {} + }, "auth:after": { "./middleware/current-user": {}, "./middleware/salix-version": {} }, "parse": { - "body-parser#json":{} + "body-parser#json":{} }, "routes": { "loopback#rest": { From 38d1e2b14fb2babad9453313b7cc54ed55fdf5c9 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 3 Nov 2023 16:11:35 +0100 Subject: [PATCH 02/19] renew-token middleware definition --- loopback/server/middleware/renew-token.js | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 loopback/server/middleware/renew-token.js diff --git a/loopback/server/middleware/renew-token.js b/loopback/server/middleware/renew-token.js new file mode 100644 index 000000000..ab5825942 --- /dev/null +++ b/loopback/server/middleware/renew-token.js @@ -0,0 +1,24 @@ +const {models} = require('vn-loopback/server/server'); + +module.exports = function(options) { + return async function(req, res, next) { + const token = req.headers.authorization; + if (!token) return next(); + + const accessToken = await models.AccessToken.findById(token); + if (!accessToken) return next(); + const maxDate = accessToken.created.setSeconds(accessToken.ttl); + if (new Date().getTime() > new Date(maxDate)) return next(); + + const vnUser = await models.VnUser.findById(accessToken.userId); + if (!vnUser) return next(); + const newToken = await vnUser.createAccessToken(accessToken.ttl); + + // console.log(accessToken, newToken); + // req.accessToken = newToken; + // res.headers.authorization = newToken; + res.setHeader('Authorization', newToken.id); + // const removed = await accessToken.delete({id: token}); + next(); + }; +}; From 82ee4f6e5b344e11111c5684182ca7ab7d5a649f Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 14:38:21 +0100 Subject: [PATCH 03/19] remove auth:before middleware --- loopback/server/middleware.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/loopback/server/middleware.json b/loopback/server/middleware.json index 45e8ada23..cfc693217 100644 --- a/loopback/server/middleware.json +++ b/loopback/server/middleware.json @@ -34,9 +34,6 @@ } } }, - "auth:before": { - "./middleware/renew-token": {} - }, "auth:after": { "./middleware/current-user": {}, "./middleware/salix-version": {} From 8c6eab23e5ab76d5bf2516c9291a32fe8a1b1dc9 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 14:39:26 +0100 Subject: [PATCH 04/19] handle expired token and return new token --- back/methods/vn-user/is-token-valid.js | 7 +++++++ back/methods/vn-user/renew-token.js | 26 ++++++++++++++++---------- back/methods/vn-user/validate-token.js | 9 +++++++-- 3 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 back/methods/vn-user/is-token-valid.js diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js new file mode 100644 index 000000000..1104b55e2 --- /dev/null +++ b/back/methods/vn-user/is-token-valid.js @@ -0,0 +1,7 @@ + +module.exports = async(token, accessTokenConfig) => { + const now = new Date(); + const differenceMilliseconds = now - token.created; + const differenceSeconds = Math.floor(differenceMilliseconds / 1000); + return differenceSeconds > accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; +}; diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js index 9850267d6..1206e537f 100644 --- a/back/methods/vn-user/renew-token.js +++ b/back/methods/vn-user/renew-token.js @@ -1,5 +1,12 @@ const UserError = require('vn-loopback/util/user-error'); - +const handlePromiseLogout = (Self, {id}, courtesyTime = 60) => { + new Promise(res => { + setTimeout(() => { + res(Self.logout(id)); + } + , courtesyTime * 1000); + }); +}; module.exports = Self => { Self.remoteMethodCtx('renewToken', { description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it', @@ -19,17 +26,16 @@ module.exports = Self => { const models = Self.app.models; const token = ctx.req.accessToken; - const now = new Date(); - const differenceMilliseconds = now - token.created; - const differenceSeconds = Math.floor(differenceMilliseconds / 1000); + // Check if current token is valid + const isValid = await Self.validateToken(token); + if (!isValid) throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); + const fields = ['courtesyTime']; + const {courtesyTime} = await models.AccessTokenConfig.findOne({fields}); - const fields = ['renewPeriod', 'courtesyTime']; - const accessTokenConfig = await models.AccessTokenConfig.findOne({fields}); + // Schedule to remove current token + handlePromiseLogout(Self, token, courtesyTime); - if (differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime) - throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); - - await Self.logout(token.id); + // Create new accessToken const user = await Self.findById(token.userId); const accessToken = await user.createAccessToken(); diff --git a/back/methods/vn-user/validate-token.js b/back/methods/vn-user/validate-token.js index 7bccfe0b1..5cbbbf0e8 100644 --- a/back/methods/vn-user/validate-token.js +++ b/back/methods/vn-user/validate-token.js @@ -1,3 +1,5 @@ +const isTokenValid = require('./is-token-valid'); + module.exports = Self => { Self.remoteMethod('validateToken', { description: 'Validates the current logged user token', @@ -11,7 +13,10 @@ module.exports = Self => { } }); - Self.validateToken = async function() { - return true; + Self.validateToken = async function(token) { + const fields = ['renewPeriod', 'courtesyTime']; + const accessTokenConfig = await Self.app.models.AccessTokenConfig.findOne({fields}); + const isValid = await isTokenValid(token, accessTokenConfig); + return isValid; }; }; From b02e1f000ef61d4ba0c2156c66fccdb2d5582c31 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 14:39:59 +0100 Subject: [PATCH 05/19] handle expired token while exists in BD --- loopback/server/middleware/current-user.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/loopback/server/middleware/current-user.js b/loopback/server/middleware/current-user.js index a6624351e..8ff4bb618 100644 --- a/loopback/server/middleware/current-user.js +++ b/loopback/server/middleware/current-user.js @@ -1,7 +1,16 @@ +const {models} = require('vn-loopback/server/server'); + module.exports = function(options) { - return function(req, res, next) { - if (!req.accessToken) + return async function(req, res, next) { + if (!req.accessToken) { + const token = req.headers.authorization; + if (!token) return next(); + + const accessToken = await models.AccessToken.findById(token); + if (!accessToken) return next(); + return next(); + } let LoopBackContext = require('loopback-context'); let loopbackContext = LoopBackContext.getCurrentContext(); From 67faf076d267af7a88a7b93ae48bee7f7f9b5c8c Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 16:51:25 +0100 Subject: [PATCH 06/19] refs '#6264' feat: memoization accessTokenConfig --- back/methods/vn-user/is-token-valid.js | 5 ++++- back/methods/vn-user/renew-token.js | 11 ++++++----- back/methods/vn-user/token-config.js | 9 +++++++++ back/methods/vn-user/validate-token.js | 4 +--- 4 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 back/methods/vn-user/token-config.js diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js index 1104b55e2..e40c2765a 100644 --- a/back/methods/vn-user/is-token-valid.js +++ b/back/methods/vn-user/is-token-valid.js @@ -1,5 +1,8 @@ +const tokenConfig = require('./token-config'); + +module.exports = async token => { + const accessTokenConfig = await tokenConfig(); -module.exports = async(token, accessTokenConfig) => { const now = new Date(); const differenceMilliseconds = now - token.created; const differenceSeconds = Math.floor(differenceMilliseconds / 1000); diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js index 1206e537f..4226886fc 100644 --- a/back/methods/vn-user/renew-token.js +++ b/back/methods/vn-user/renew-token.js @@ -1,5 +1,7 @@ const UserError = require('vn-loopback/util/user-error'); -const handlePromiseLogout = (Self, {id}, courtesyTime = 60) => { +const tokenConfig = require('./token-config'); +const DEFAULT_COURTESY_TIME = 60; +const handlePromiseLogout = (Self, {id}, courtesyTime = DEFAULT_COURTESY_TIME) => { new Promise(res => { setTimeout(() => { res(Self.logout(id)); @@ -23,14 +25,13 @@ module.exports = Self => { }); Self.renewToken = async function(ctx) { - const models = Self.app.models; - const token = ctx.req.accessToken; + const {accessToken: token} = ctx.req; // Check if current token is valid const isValid = await Self.validateToken(token); if (!isValid) throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); - const fields = ['courtesyTime']; - const {courtesyTime} = await models.AccessTokenConfig.findOne({fields}); + + const {courtesyTime} = await tokenConfig(); // Schedule to remove current token handlePromiseLogout(Self, token, courtesyTime); diff --git a/back/methods/vn-user/token-config.js b/back/methods/vn-user/token-config.js new file mode 100644 index 000000000..0936e0b89 --- /dev/null +++ b/back/methods/vn-user/token-config.js @@ -0,0 +1,9 @@ +const DEFAULT_FIELDS = ['renewPeriod', 'courtesyTime']; +const {models} = require('vn-loopback/server/server'); +let currentAccessTokenConfig = null; +module.exports = async(fields = DEFAULT_FIELDS) => { + if (currentAccessTokenConfig) return currentAccessTokenConfig; + const accessTokenConfig = await models.AccessTokenConfig.findOne({fields}); + if (!accessTokenConfig) currentAccessTokenConfig = accessTokenConfig; + return accessTokenConfig; +}; diff --git a/back/methods/vn-user/validate-token.js b/back/methods/vn-user/validate-token.js index 5cbbbf0e8..fadaed43b 100644 --- a/back/methods/vn-user/validate-token.js +++ b/back/methods/vn-user/validate-token.js @@ -14,9 +14,7 @@ module.exports = Self => { }); Self.validateToken = async function(token) { - const fields = ['renewPeriod', 'courtesyTime']; - const accessTokenConfig = await Self.app.models.AccessTokenConfig.findOne({fields}); - const isValid = await isTokenValid(token, accessTokenConfig); + const isValid = await isTokenValid(token); return isValid; }; }; From 21028e3b79be1e5d8afccd9c8df9bd4dca52979a Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 17:23:44 +0100 Subject: [PATCH 07/19] refs #6264 feat: db changes --- db/changes/234601/00-updateCourtesyTime.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 db/changes/234601/00-updateCourtesyTime.sql diff --git a/db/changes/234601/00-updateCourtesyTime.sql b/db/changes/234601/00-updateCourtesyTime.sql new file mode 100644 index 000000000..4751b2e03 --- /dev/null +++ b/db/changes/234601/00-updateCourtesyTime.sql @@ -0,0 +1,4 @@ +-- Auto-generated SQL script #202311061003 +UPDATE salix.accessTokenConfig + SET courtesyTime=60 + WHERE id=1; From 43366d1ba825dfcd32f13278aceb805b048a0ca5 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 17:24:04 +0100 Subject: [PATCH 08/19] refs #6264 feat: update fixture.sql --- db/dump/fixtures.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index d70279e7d..9bc3e102a 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2758,7 +2758,7 @@ INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk VALUES (1, 1); -INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`, `teleworkingStart`, `teleworkingStartBreakTime`, `maxTimeToBreak`, `maxWorkShortCycle`, `maxWorkLongCycle`) +INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`, `teleworkingStart`, `teleworkingStartBreakTime`, `maxTimeToBreak`, `maxWorkShortCycle`, `maxWorkLongCycle`) VALUES (1, 43200, 32400, 129600, 259200, 1080000, '', 'imap.verdnatura.es', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.00, 0.33, 40, '22:00:00', '06:00:00', 72000, 1200, 18000, 72000, 6, 13, 28800, 32400, 3600, 561600, 950400); @@ -2945,9 +2945,9 @@ INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`) (2, 1, 50, 2), (3, 1, 0, 3); -INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `renewInterval`) +INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `courtesyTime`, `renewInterval`) VALUES - (1, 21600, 300); + (1, 21600, 60, 300); INSERT INTO `vn`.`travelConfig` (`id`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `companyFk`) VALUES @@ -2986,4 +2986,4 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`) VALUES (1, 'Error in VAT calculation'), (2, 'Error in sales details'), - (3, 'Error in customer data'); \ No newline at end of file + (3, 'Error in customer data'); From 5601ce5dac7ddd8f155961f4ea0d333a391bed04 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 17:25:30 +0100 Subject: [PATCH 09/19] refs #6264 fix: rename variable --- front/core/services/token.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/core/services/token.js b/front/core/services/token.js index 426fe2b73..f1408f7e3 100644 --- a/front/core/services/token.js +++ b/front/core/services/token.js @@ -82,7 +82,7 @@ export default class Token { if (!data) return; this.renewPeriod = data.renewPeriod; this.stopRenewer(); - this.inservalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000); + this.intervalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000); }); } @@ -113,7 +113,7 @@ export default class Token { } stopRenewer() { - clearInterval(this.inservalId); + clearInterval(this.intervalId); } } Token.$inject = ['vnInterceptor', '$http', '$rootScope']; From 0c2b2b25b741d62e54d4cae526199a338a734836 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Sat, 4 Nov 2023 18:07:37 +0100 Subject: [PATCH 10/19] refs #6264 fix: remove unnecessary file --- loopback/server/middleware/renew-token.js | 24 ----------------------- 1 file changed, 24 deletions(-) delete mode 100644 loopback/server/middleware/renew-token.js diff --git a/loopback/server/middleware/renew-token.js b/loopback/server/middleware/renew-token.js deleted file mode 100644 index ab5825942..000000000 --- a/loopback/server/middleware/renew-token.js +++ /dev/null @@ -1,24 +0,0 @@ -const {models} = require('vn-loopback/server/server'); - -module.exports = function(options) { - return async function(req, res, next) { - const token = req.headers.authorization; - if (!token) return next(); - - const accessToken = await models.AccessToken.findById(token); - if (!accessToken) return next(); - const maxDate = accessToken.created.setSeconds(accessToken.ttl); - if (new Date().getTime() > new Date(maxDate)) return next(); - - const vnUser = await models.VnUser.findById(accessToken.userId); - if (!vnUser) return next(); - const newToken = await vnUser.createAccessToken(accessToken.ttl); - - // console.log(accessToken, newToken); - // req.accessToken = newToken; - // res.headers.authorization = newToken; - res.setHeader('Authorization', newToken.id); - // const removed = await accessToken.delete({id: token}); - next(); - }; -}; From 784f5bb7f92f5b7df876b722fcc645972938faac Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Tue, 7 Nov 2023 23:23:02 +0100 Subject: [PATCH 11/19] refs #6264 perf: replace now with vnNew --- back/methods/vn-user/is-token-valid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js index e40c2765a..f4c2a9ea8 100644 --- a/back/methods/vn-user/is-token-valid.js +++ b/back/methods/vn-user/is-token-valid.js @@ -3,7 +3,7 @@ const tokenConfig = require('./token-config'); module.exports = async token => { const accessTokenConfig = await tokenConfig(); - const now = new Date(); + const now = Date.vnNew(); const differenceMilliseconds = now - token.created; const differenceSeconds = Math.floor(differenceMilliseconds / 1000); return differenceSeconds > accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; From bcccd1894c555706f115c1fe670ce1c40dfe2b4b Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 10 Nov 2023 13:13:17 +0100 Subject: [PATCH 12/19] refs #6264 test: init test --- .../methods/vn-user/specs/renew-token.spec.js | 22 +++++++++++++++++++ .../vn-user/specs/validate-token.spec.js | 9 ++++++++ 2 files changed, 31 insertions(+) create mode 100644 back/methods/vn-user/specs/renew-token.spec.js create mode 100644 back/methods/vn-user/specs/validate-token.spec.js diff --git a/back/methods/vn-user/specs/renew-token.spec.js b/back/methods/vn-user/specs/renew-token.spec.js new file mode 100644 index 000000000..cae91f310 --- /dev/null +++ b/back/methods/vn-user/specs/renew-token.spec.js @@ -0,0 +1,22 @@ +describe('Renew Token', () => { + it('Token is valid', async() => { + let login = await VnUser.signIn(unauthCtx, 'salesAssistant', 'nightmare'); + let accessToken = await AccessToken.findById(login.token); + let ctx = {req: {accessToken: accessToken}}; + + expect(login.token).toBeDefined(); + }); + + it('Token is is invalid', async() => { + let error; + try { + await models.VnUser.validateCode('developer', '123456'); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.statusCode).toBe(400); + expect(error.message).toEqual('Invalid or expired verification code'); + }); +}); diff --git a/back/methods/vn-user/specs/validate-token.spec.js b/back/methods/vn-user/specs/validate-token.spec.js new file mode 100644 index 000000000..0d0af689f --- /dev/null +++ b/back/methods/vn-user/specs/validate-token.spec.js @@ -0,0 +1,9 @@ +describe('Validate Token', () => { + it('Token is not expired', async() => { + + }); + + it('Token is expired', async() => { + + }); +}); From 72a0932e35539bd53857a0e3cb9c02916c8e5965 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 27 Nov 2023 09:46:27 +0100 Subject: [PATCH 13/19] refs #6264 other: rename camel-case variable --- back/methods/vn-user/specs/sign-in.spec.js | 12 ++++++------ .../methods/account/specs/change-password.spec.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/back/methods/vn-user/specs/sign-in.spec.js b/back/methods/vn-user/specs/sign-in.spec.js index f4cad88b9..e02c72ad3 100644 --- a/back/methods/vn-user/specs/sign-in.spec.js +++ b/back/methods/vn-user/specs/sign-in.spec.js @@ -2,7 +2,7 @@ const {models} = require('vn-loopback/server/server'); describe('VnUser Sign-in()', () => { const employeeId = 1; - const unauthCtx = { + const unAuthCtx = { req: { headers: {}, connection: { @@ -15,7 +15,7 @@ describe('VnUser Sign-in()', () => { const {VnUser, AccessToken} = models; describe('when credentials are correct', () => { it('should return the token', async() => { - let login = await VnUser.signIn(unauthCtx, 'salesAssistant', 'nightmare'); + let login = await VnUser.signIn(unAuthCtx, 'salesAssistant', 'nightmare'); let accessToken = await AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; @@ -25,7 +25,7 @@ describe('VnUser Sign-in()', () => { }); it('should return the token if the user doesnt exist but the client does', async() => { - let login = await VnUser.signIn(unauthCtx, 'PetterParker', 'nightmare'); + let login = await VnUser.signIn(unAuthCtx, 'PetterParker', 'nightmare'); let accessToken = await AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; @@ -40,7 +40,7 @@ describe('VnUser Sign-in()', () => { let error; try { - await VnUser.signIn(unauthCtx, 'IDontExist', 'TotallyWrongPassword'); + await VnUser.signIn(unAuthCtx, 'IDontExist', 'TotallyWrongPassword'); } catch (e) { error = e; } @@ -61,7 +61,7 @@ describe('VnUser Sign-in()', () => { const options = {transaction: tx}; await employee.updateAttribute('twoFactor', 'email', options); - await VnUser.signIn(unauthCtx, 'employee', 'nightmare', options); + await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -86,7 +86,7 @@ describe('VnUser Sign-in()', () => { const options = {transaction: tx}; await employee.updateAttribute('passExpired', yesterday, options); - await VnUser.signIn(unauthCtx, 'employee', 'nightmare', options); + await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options); await tx.rollback(); } catch (e) { await tx.rollback(); diff --git a/modules/account/back/methods/account/specs/change-password.spec.js b/modules/account/back/methods/account/specs/change-password.spec.js index 2fa3010af..c79960212 100644 --- a/modules/account/back/methods/account/specs/change-password.spec.js +++ b/modules/account/back/methods/account/specs/change-password.spec.js @@ -2,7 +2,7 @@ const {models} = require('vn-loopback/server/server'); describe('account changePassword()', () => { const userId = 70; - const unauthCtx = { + const unAuthCtx = { req: { headers: {}, connection: { @@ -79,7 +79,7 @@ describe('account changePassword()', () => { passExpired: yesterday } , options); - await models.VnUser.signIn(unauthCtx, 'trainee', 'nightmare', options); + await models.VnUser.signIn(unAuthCtx, 'trainee', 'nightmare', options); } catch (e) { if (e.message != 'Pass expired') throw e; From 81be3b18f77be9062aed7d29811a8977d7a1b54d Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 27 Nov 2023 09:48:15 +0100 Subject: [PATCH 14/19] refs #6264 test: validate-token and renew-token --- back/methods/vn-user/is-token-valid.js | 5 ++- .../methods/vn-user/specs/renew-token.spec.js | 45 +++++++++++++++---- .../vn-user/specs/validate-token.spec.js | 38 +++++++++++++++- loopback/server/boot/date.js | 3 +- 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js index f4c2a9ea8..c5c05a178 100644 --- a/back/methods/vn-user/is-token-valid.js +++ b/back/methods/vn-user/is-token-valid.js @@ -2,8 +2,9 @@ const tokenConfig = require('./token-config'); module.exports = async token => { const accessTokenConfig = await tokenConfig(); - - const now = Date.vnNew(); + let now = Date.now(); + if (Date?.vnNow !== undefined) + now = Date.vnNow(); const differenceMilliseconds = now - token.created; const differenceSeconds = Math.floor(differenceMilliseconds / 1000); return differenceSeconds > accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; diff --git a/back/methods/vn-user/specs/renew-token.spec.js b/back/methods/vn-user/specs/renew-token.spec.js index cae91f310..21d3de1a9 100644 --- a/back/methods/vn-user/specs/renew-token.spec.js +++ b/back/methods/vn-user/specs/renew-token.spec.js @@ -1,22 +1,49 @@ +const {models} = require('vn-loopback/server/server'); describe('Renew Token', () => { - it('Token is valid', async() => { - let login = await VnUser.signIn(unauthCtx, 'salesAssistant', 'nightmare'); - let accessToken = await AccessToken.findById(login.token); - let ctx = {req: {accessToken: accessToken}}; - - expect(login.token).toBeDefined(); + const startingTime = Date.now(); + let ctx = null; + beforeAll(async() => { + const unAuthCtx = { + req: { + headers: {}, + connection: { + remoteAddress: '127.0.0.1' + }, + getLocale: () => 'en' + }, + args: {} + }; + let login = await models.VnUser.signIn(unAuthCtx, 'salesAssistant', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); + ctx = {req: {accessToken: accessToken}}; }); - it('Token is is invalid', async() => { + beforeEach(() => { + jasmine.clock().install(); + jasmine.clock().mockDate(new Date(startingTime)); + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + + it('should renew process', async() => { + jasmine.clock().mockDate(new Date(startingTime + 21600000)); + const {id} = await models.VnUser.renewToken(ctx); + + expect(id).not.toEqual(ctx.req.accessToken.id); + }); + + it('NOT should renew', async() => { let error; try { - await models.VnUser.validateCode('developer', '123456'); + await models.VnUser.renewToken(ctx); } catch (e) { error = e; } expect(error).toBeDefined(); expect(error.statusCode).toBe(400); - expect(error.message).toEqual('Invalid or expired verification code'); + expect(error.message).toEqual('The renew period has not been exceeded'); }); }); diff --git a/back/methods/vn-user/specs/validate-token.spec.js b/back/methods/vn-user/specs/validate-token.spec.js index 0d0af689f..25207336d 100644 --- a/back/methods/vn-user/specs/validate-token.spec.js +++ b/back/methods/vn-user/specs/validate-token.spec.js @@ -1,9 +1,43 @@ -describe('Validate Token', () => { - it('Token is not expired', async() => { +const {models} = require('vn-loopback/server/server'); +describe('Validate Token', () => { + const startingTime = Date.now(); + let ctx = null; + beforeAll(async() => { + const unAuthCtx = { + req: { + headers: {}, + connection: { + remoteAddress: '127.0.0.1' + }, + getLocale: () => 'en' + }, + args: {} + }; + let login = await models.VnUser.signIn(unAuthCtx, 'salesAssistant', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); + ctx = {req: {accessToken: accessToken}}; + }); + + beforeEach(() => { + jasmine.clock().install(); + jasmine.clock().mockDate(new Date(startingTime)); + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + + it('Token is not expired', async() => { + jasmine.clock().mockDate(new Date(startingTime + 21600000)); + const isValid = await models.VnUser.validateToken(ctx.req.accessToken); + + expect(isValid).toBeTrue(); }); it('Token is expired', async() => { + const isValid = await models.VnUser.validateToken(ctx.req.accessToken); + expect(isValid).toBeFalse(); }); }); diff --git a/loopback/server/boot/date.js b/loopback/server/boot/date.js index 810745562..d592dc416 100644 --- a/loopback/server/boot/date.js +++ b/loopback/server/boot/date.js @@ -1,6 +1,5 @@ module.exports = () => { - Date.vnUTC = () => { - const env = process.env.NODE_ENV; + Date.vnUTC = (env = process.env.NODE_ENV) => { if (!env || env === 'development') return new Date(Date.UTC(2001, 0, 1, 11)); From 9da5fb9a14e739458f823290b1f1996ad7c1762a Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 27 Nov 2023 10:24:25 +0100 Subject: [PATCH 15/19] refs #6264 other: rename camel-case variable --- back/methods/vn-user/specs/sign-in.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/methods/vn-user/specs/sign-in.spec.js b/back/methods/vn-user/specs/sign-in.spec.js index 99d7b90f9..f800454aa 100644 --- a/back/methods/vn-user/specs/sign-in.spec.js +++ b/back/methods/vn-user/specs/sign-in.spec.js @@ -15,7 +15,7 @@ describe('VnUser Sign-in()', () => { const {VnUser, AccessToken, SignInLog} = models; describe('when credentials are correct', () => { it('should return the token if user uses email', async() => { - let login = await VnUser.signIn(unauthCtx, 'salesAssistant@mydomain.com', 'nightmare'); + let login = await VnUser.signIn(unAuthCtx, 'salesAssistant@mydomain.com', 'nightmare'); let accessToken = await AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; let signInLog = await SignInLog.find({where: {token: accessToken.id}}); From d4cd23853ffbd474ee7c55401437c47763a204ef Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Thu, 30 Nov 2023 07:32:16 +0100 Subject: [PATCH 16/19] refs #6264 perf: try to remove jasmine.clock() --- back/methods/vn-user/is-token-valid.js | 6 ++---- back/methods/vn-user/renew-token.js | 2 +- back/methods/vn-user/specs/validate-token.spec.js | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js index c5c05a178..23b68797e 100644 --- a/back/methods/vn-user/is-token-valid.js +++ b/back/methods/vn-user/is-token-valid.js @@ -2,10 +2,8 @@ const tokenConfig = require('./token-config'); module.exports = async token => { const accessTokenConfig = await tokenConfig(); - let now = Date.now(); - if (Date?.vnNow !== undefined) - now = Date.vnNow(); + const now = Date.now(); const differenceMilliseconds = now - token.created; const differenceSeconds = Math.floor(differenceMilliseconds / 1000); - return differenceSeconds > accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; + return differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; }; diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js index 4226886fc..cb88e665d 100644 --- a/back/methods/vn-user/renew-token.js +++ b/back/methods/vn-user/renew-token.js @@ -29,7 +29,7 @@ module.exports = Self => { // Check if current token is valid const isValid = await Self.validateToken(token); - if (!isValid) throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); + if (isValid) throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); const {courtesyTime} = await tokenConfig(); diff --git a/back/methods/vn-user/specs/validate-token.spec.js b/back/methods/vn-user/specs/validate-token.spec.js index 25207336d..ec254d0e5 100644 --- a/back/methods/vn-user/specs/validate-token.spec.js +++ b/back/methods/vn-user/specs/validate-token.spec.js @@ -29,13 +29,13 @@ describe('Validate Token', () => { }); it('Token is not expired', async() => { - jasmine.clock().mockDate(new Date(startingTime + 21600000)); const isValid = await models.VnUser.validateToken(ctx.req.accessToken); expect(isValid).toBeTrue(); }); it('Token is expired', async() => { + jasmine.clock().mockDate(new Date(startingTime + 21600000)); const isValid = await models.VnUser.validateToken(ctx.req.accessToken); expect(isValid).toBeFalse(); From b9671c0b67b6b4222b61598ac6a5ee2460a684f2 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 4 Dec 2023 14:44:50 +0100 Subject: [PATCH 17/19] refs #6264 perf: remove files related to token --- back/methods/vn-user/is-token-valid.js | 9 --------- back/methods/vn-user/token-config.js | 9 --------- 2 files changed, 18 deletions(-) delete mode 100644 back/methods/vn-user/is-token-valid.js delete mode 100644 back/methods/vn-user/token-config.js diff --git a/back/methods/vn-user/is-token-valid.js b/back/methods/vn-user/is-token-valid.js deleted file mode 100644 index 23b68797e..000000000 --- a/back/methods/vn-user/is-token-valid.js +++ /dev/null @@ -1,9 +0,0 @@ -const tokenConfig = require('./token-config'); - -module.exports = async token => { - const accessTokenConfig = await tokenConfig(); - const now = Date.now(); - const differenceMilliseconds = now - token.created; - const differenceSeconds = Math.floor(differenceMilliseconds / 1000); - return differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; -}; diff --git a/back/methods/vn-user/token-config.js b/back/methods/vn-user/token-config.js deleted file mode 100644 index 0936e0b89..000000000 --- a/back/methods/vn-user/token-config.js +++ /dev/null @@ -1,9 +0,0 @@ -const DEFAULT_FIELDS = ['renewPeriod', 'courtesyTime']; -const {models} = require('vn-loopback/server/server'); -let currentAccessTokenConfig = null; -module.exports = async(fields = DEFAULT_FIELDS) => { - if (currentAccessTokenConfig) return currentAccessTokenConfig; - const accessTokenConfig = await models.AccessTokenConfig.findOne({fields}); - if (!accessTokenConfig) currentAccessTokenConfig = accessTokenConfig; - return accessTokenConfig; -}; From 5656ed7a2b29860b571125b46796abdd2d7609bd Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 4 Dec 2023 14:46:05 +0100 Subject: [PATCH 18/19] refs #6264 perf: use functions extracted previously --- back/methods/vn-user/renew-token.js | 5 +++-- back/methods/vn-user/validate-token.js | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js index cb88e665d..d5d22fd0d 100644 --- a/back/methods/vn-user/renew-token.js +++ b/back/methods/vn-user/renew-token.js @@ -1,5 +1,6 @@ const UserError = require('vn-loopback/util/user-error'); -const tokenConfig = require('./token-config'); +const {models} = require('vn-loopback/server/server'); + const DEFAULT_COURTESY_TIME = 60; const handlePromiseLogout = (Self, {id}, courtesyTime = DEFAULT_COURTESY_TIME) => { new Promise(res => { @@ -31,7 +32,7 @@ module.exports = Self => { const isValid = await Self.validateToken(token); if (isValid) throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); - const {courtesyTime} = await tokenConfig(); + const {courtesyTime} = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']}); // Schedule to remove current token handlePromiseLogout(Self, token, courtesyTime); diff --git a/back/methods/vn-user/validate-token.js b/back/methods/vn-user/validate-token.js index fadaed43b..ef3c5b212 100644 --- a/back/methods/vn-user/validate-token.js +++ b/back/methods/vn-user/validate-token.js @@ -1,5 +1,4 @@ -const isTokenValid = require('./is-token-valid'); - +const {models} = require('vn-loopback/server/server'); module.exports = Self => { Self.remoteMethod('validateToken', { description: 'Validates the current logged user token', @@ -14,7 +13,12 @@ module.exports = Self => { }); Self.validateToken = async function(token) { - const isValid = await isTokenValid(token); + const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']}); + const now = Date.now(); + const differenceMilliseconds = now - token.created; + const differenceSeconds = Math.floor(differenceMilliseconds / 1000); + const isValid = differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; + return isValid; }; }; From a5fb07bf127a81e2e9e80935e89ae8840b28babe Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Tue, 5 Dec 2023 13:05:26 +0100 Subject: [PATCH 19/19] refs #6264 perf remove unnecessary code --- loopback/server/middleware/current-user.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/loopback/server/middleware/current-user.js b/loopback/server/middleware/current-user.js index 8ff4bb618..b450f6bb1 100644 --- a/loopback/server/middleware/current-user.js +++ b/loopback/server/middleware/current-user.js @@ -1,16 +1,7 @@ -const {models} = require('vn-loopback/server/server'); - module.exports = function(options) { return async function(req, res, next) { - if (!req.accessToken) { - const token = req.headers.authorization; - if (!token) return next(); - - const accessToken = await models.AccessToken.findById(token); - if (!accessToken) return next(); - + if (!req.accessToken) return next(); - } let LoopBackContext = require('loopback-context'); let loopbackContext = LoopBackContext.getCurrentContext();