From 89f4246f08ddb7ec26ca3b2158bc25076d3cc964 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Mon, 9 Aug 2021 09:33:42 +0200 Subject: [PATCH 1/9] enable reauthentication using jwt property --- src/Kuzzle.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Kuzzle.ts b/src/Kuzzle.ts index 5487c6484..f59c8be62 100644 --- a/src/Kuzzle.ts +++ b/src/Kuzzle.ts @@ -429,6 +429,13 @@ export class Kuzzle extends KuzzleEventEmitter { set jwt (encodedJwt) { this.auth.authenticationToken = encodedJwt; + + if (! encodedJwt) { + this._loggedIn = false; + return; + } + + this._loggedIn = true; } get offlineQueue () { @@ -599,7 +606,6 @@ export class Kuzzle extends KuzzleEventEmitter { // If an authenticator was set, check if a user was logged in and if the token is still valid and try // to re-authenticate if needed. Otherwise the SDK is in disconnected state. if ( this._loggedIn - && this.authenticator && ! await this.tryReAuthenticate() ) { this._loggedIn = false; @@ -634,6 +640,14 @@ export class Kuzzle extends KuzzleEventEmitter { return true; } + /** + * Check if there is an authenticator after verifying if the token is still valid, + * like so API Keys can be used even if there is no authenticator since they will be still valid. + */ + if (! this.authenticator) { + return false; + } + await this.authenticate(); return true; @@ -839,10 +853,13 @@ Discarded request: ${JSON.stringify(request)}`)); return; } - if (this._loggedIn && this.authenticator && await this.tryReAuthenticate()) { - this.emit('reAuthenticated'); + if (this._loggedIn) { + if (await this.tryReAuthenticate()) { + this.emit('reAuthenticated'); - return; + return; + } + this._loggedIn = false; } const now = Date.now(); From 0c0a0da35011aa84857d794cd6b0fa76e827df58 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Mon, 9 Aug 2021 09:50:56 +0200 Subject: [PATCH 2/9] set jwt property to null on TokenExpired --- src/Kuzzle.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Kuzzle.ts b/src/Kuzzle.ts index f59c8be62..d455ae180 100644 --- a/src/Kuzzle.ts +++ b/src/Kuzzle.ts @@ -853,13 +853,10 @@ Discarded request: ${JSON.stringify(request)}`)); return; } - if (this._loggedIn) { - if (await this.tryReAuthenticate()) { - this.emit('reAuthenticated'); + if (this._loggedIn && await this.tryReAuthenticate()) { + this.emit('reAuthenticated'); - return; - } - this._loggedIn = false; + return; } const now = Date.now(); @@ -871,6 +868,8 @@ Discarded request: ${JSON.stringify(request)}`)); this._lastTokenExpired = now; + this._loggedIn = false; + this.auth.authenticationToken = null; this.emit('tokenExpired'); } From 49b2bcf163c33ed81dc786a768a4a6b385bc7e67 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Mon, 9 Aug 2021 09:52:33 +0200 Subject: [PATCH 3/9] use ternary --- src/Kuzzle.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Kuzzle.ts b/src/Kuzzle.ts index d455ae180..f7172081f 100644 --- a/src/Kuzzle.ts +++ b/src/Kuzzle.ts @@ -430,12 +430,7 @@ export class Kuzzle extends KuzzleEventEmitter { set jwt (encodedJwt) { this.auth.authenticationToken = encodedJwt; - if (! encodedJwt) { - this._loggedIn = false; - return; - } - - this._loggedIn = true; + this._loggedIn = encodedJwt ? true : false; } get offlineQueue () { From ae6682063148f48f7db5dec0f5155ef50e38aae5 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Mon, 9 Aug 2021 10:22:21 +0200 Subject: [PATCH 4/9] simplify check --- src/Kuzzle.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Kuzzle.ts b/src/Kuzzle.ts index f7172081f..f9cde2c20 100644 --- a/src/Kuzzle.ts +++ b/src/Kuzzle.ts @@ -863,8 +863,7 @@ Discarded request: ${JSON.stringify(request)}`)); this._lastTokenExpired = now; - this._loggedIn = false; - this.auth.authenticationToken = null; + this.jwt = null; this.emit('tokenExpired'); } From df9c5b407ffe28b44f909e79bdc2c781c814a507 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Mon, 9 Aug 2021 10:22:33 +0200 Subject: [PATCH 5/9] add tests --- test/kuzzle/authenticator.test.js | 26 ++++++++++++++++++++++++++ test/kuzzle/protocol.test.js | 10 +++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/test/kuzzle/authenticator.test.js b/test/kuzzle/authenticator.test.js index 645d07e6b..3542a1063 100644 --- a/test/kuzzle/authenticator.test.js +++ b/test/kuzzle/authenticator.test.js @@ -2,6 +2,7 @@ const should = require('should'); const sinon = require('sinon'); const ProtocolMock = require('../mocks/protocol.mock'); const { Kuzzle } = require('../../src/Kuzzle'); +const generateJwt = require('../mocks/generateJwt.mock'); describe('Kuzzle authenticator function mecanisms', () => { let kuzzle; @@ -16,6 +17,20 @@ describe('Kuzzle authenticator function mecanisms', () => { sinon.restore(); }); + describe('jwt property', () => { + it('should set the SDK property _loggedIn when setting the JWT property', () => { + kuzzle.jwt = generateJwt(); + + should(kuzzle._loggedIn).be.true(); + }); + + it('should set the SDK property _loggedIn when setting the JWT property to null or undefined', () => { + kuzzle.jwt = null; + + should(kuzzle._loggedIn).be.false(); + }); + }); + describe('connected listener', () => { let resolve; let promise; @@ -230,6 +245,17 @@ describe('Kuzzle authenticator function mecanisms', () => { should(reconnectionErrorSpy).not.be.called(); }); + it('should returns false if the token is not valid and there is no authenticator', async () => { + kuzzle.auth.checkToken.resolves({ valid: false }); + kuzzle.authenticator = null; + + const ret = await kuzzle.tryReAuthenticate(); + + should(ret).be.false(); + should(kuzzle.authenticate).not.be.called(); + should(reconnectionErrorSpy).not.be.called(); + }); + it('should call "authenticate" if the token is not valid', async () => { const ret = await kuzzle.tryReAuthenticate(); diff --git a/test/kuzzle/protocol.test.js b/test/kuzzle/protocol.test.js index 950d8b8a1..547c1f7a2 100644 --- a/test/kuzzle/protocol.test.js +++ b/test/kuzzle/protocol.test.js @@ -52,11 +52,19 @@ describe('Kuzzle protocol methods', () => { it('should empty the jwt when a "tokenExpired" events is triggered', () => { kuzzle.jwt = generateJwt(); + + should(kuzzle._loggedIn).be.true(); + kuzzle.connect(); + kuzzle.tryReAuthenticate = sinon.stub().resolves(false); kuzzle.protocol.emit('tokenExpired'); - should(kuzzle.jwt).be.null(); + setTimeout(() => { + should(kuzzle.tryReAuthenticate).be.calledOnce(); + should(kuzzle._loggedIn).be.false(); + should(kuzzle.jwt).be.null(); + }, 1); }); }); }); From c6bd6c14224ede57cc3dc751a76d1563cbedea69 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Tue, 10 Aug 2021 11:22:24 +0200 Subject: [PATCH 6/9] Fix subscription not working in the browser because of a bad transpilation --- src/controllers/Realtime.ts | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/controllers/Realtime.ts b/src/controllers/Realtime.ts index 4d587e361..946960ec4 100644 --- a/src/controllers/Realtime.ts +++ b/src/controllers/Realtime.ts @@ -226,8 +226,13 @@ export class RealtimeController extends BaseController { * Called when kuzzle is disconnected */ private saveSubscriptions () { - for (const roomId of this._subscriptions.keys()) { - for (const room of this._subscriptions.get(roomId)) { + /** + * Use forEach instead of iterating over Map.keys() because the Webpack + * transpilation is producing bad code leading to a loop not iterating. + */ + this._subscriptions.forEach((rooms, roomId) => { + + for (const room of rooms) { room.removeListeners(); if (room.autoResubscribe) { @@ -239,15 +244,20 @@ export class RealtimeController extends BaseController { } this._subscriptions.delete(roomId); - } + + }); } /** * Called on kuzzle reconnection */ private resubscribe () { - for (const roomId of this._subscriptionsOff.keys()) { - for (const room of this._subscriptionsOff.get(roomId)) { + /** + * Use forEach instead of iterating over Map.keys() because the Webpack + * transpilation is producing bad code leading to a loop not iterating. + */ + this._subscriptionsOff.forEach((rooms, roomId) => { + for (const room of rooms) { if (!this._subscriptions.has(roomId)) { this._subscriptions.set(roomId, []); } @@ -258,18 +268,22 @@ export class RealtimeController extends BaseController { } this._subscriptionsOff.delete(roomId); - } + }); } /** * Called when a token expire */ private removeSubscriptions() { - for (const roomId of this._subscriptions.keys()) { - for (const room of this._subscriptions.get(roomId)) { + /** + * Use forEach instead of iterating over Map.keys() because the Webpack + * transpilation is producing bad code leading to a loop not iterating. + */ + this._subscriptionsOff.forEach((rooms, roomId) => { + for (const room of rooms) { room.removeListeners(); } - } + }); this._subscriptions = new Map(); this._subscriptionsOff = new Map(); From 05bfc285898578863835f1ae242f206cafe18517 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Tue, 10 Aug 2021 12:21:18 +0200 Subject: [PATCH 7/9] unused variable --- src/controllers/Realtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/Realtime.ts b/src/controllers/Realtime.ts index 946960ec4..9b43b06ff 100644 --- a/src/controllers/Realtime.ts +++ b/src/controllers/Realtime.ts @@ -279,7 +279,7 @@ export class RealtimeController extends BaseController { * Use forEach instead of iterating over Map.keys() because the Webpack * transpilation is producing bad code leading to a loop not iterating. */ - this._subscriptionsOff.forEach((rooms, roomId) => { + this._subscriptionsOff.forEach((rooms) => { for (const room of rooms) { room.removeListeners(); } From aa81470c675b3522b26e1d770525200ffe9a4b63 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Tue, 10 Aug 2021 12:24:01 +0200 Subject: [PATCH 8/9] use the correct map when removing subscriptions --- src/controllers/Realtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/Realtime.ts b/src/controllers/Realtime.ts index 9b43b06ff..f0cfb3b74 100644 --- a/src/controllers/Realtime.ts +++ b/src/controllers/Realtime.ts @@ -279,7 +279,7 @@ export class RealtimeController extends BaseController { * Use forEach instead of iterating over Map.keys() because the Webpack * transpilation is producing bad code leading to a loop not iterating. */ - this._subscriptionsOff.forEach((rooms) => { + this._subscriptions.forEach((rooms) => { for (const room of rooms) { room.removeListeners(); } From 7e4f88321d46e95710c46eb612740b78d0aae996 Mon Sep 17 00:00:00 2001 From: Shiranuit Date: Tue, 10 Aug 2021 14:57:34 +0200 Subject: [PATCH 9/9] Release 7.7.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6139a037c..7384015d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "kuzzle-sdk", - "version": "7.7.3", + "version": "7.7.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e703893d6..5ec09d2c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kuzzle-sdk", - "version": "7.7.3", + "version": "7.7.4", "description": "Official Javascript SDK for Kuzzle", "author": "The Kuzzle Team ", "repository": {