diff --git a/client-react/package-lock.json b/client-react/package-lock.json index 6c687ed..0bc9a56 100644 --- a/client-react/package-lock.json +++ b/client-react/package-lock.json @@ -80,7 +80,7 @@ }, "../server": { "name": "@krmx/server", - "version": "0.6.10", + "version": "0.6.11", "dev": true, "license": "ISC", "dependencies": { diff --git a/client/package-lock.json b/client/package-lock.json index 3b63cdd..15c1a11 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -47,7 +47,7 @@ }, "../server": { "name": "@krmx/server", - "version": "0.6.10", + "version": "0.6.11", "dev": true, "license": "ISC", "dependencies": { diff --git a/server/package-lock.json b/server/package-lock.json index f2cf0ad..3ac0ed3 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "@krmx/server", - "version": "0.6.10", + "version": "0.6.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@krmx/server", - "version": "0.6.10", + "version": "0.6.11", "license": "ISC", "dependencies": { "@krmx/base": "file:../base", diff --git a/server/package.json b/server/package.json index 97efa5b..608967f 100644 --- a/server/package.json +++ b/server/package.json @@ -2,7 +2,7 @@ "name": "@krmx/server", "description": "krmx server", "author": "Simon Karman", - "version": "0.6.10", + "version": "0.6.11", "main": "dist/src/index.js", "scripts": { "start": "nodemon --exec \"ts-node src/index.ts\" src/index.ts", diff --git a/server/src/server.ts b/server/src/server.ts index 2b1c22b..0c2ad20 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -420,9 +420,11 @@ class ServerImpl extends EventGenerator implements Server { } private async onUnlinkedConnectionMessage(connectionId: string, message: FromClientMessage | Message): Promise { let rejected = false; + let timeoutId: ReturnType | undefined; let timeoutResolver = () => { /*none*/ }; const reject = (reason: string) => { if (rejected) { return; } + if (timeoutId !== undefined) { clearTimeout(timeoutId); } timeoutResolver(); this.logger('debug', `connection ${connectionId} rejected, due to: ${reason}`); const userRejectedMessage: RejectedMessage = { type: 'krmx/rejected', payload: { reason } }; @@ -483,18 +485,19 @@ class ServerImpl extends EventGenerator implements Server { await Promise.race([ new Promise((resolve) => { timeoutResolver = resolve; // allows to resolve the promise immediately on rejection - setTimeout(() => { + timeoutId = setTimeout(() => { reject('authentication timeout'); resolve(); }, this.authTimeoutMilliseconds); }), - await Promise.all(promises), + Promise.all(promises).then(() => { /* resolve race when all handlers complete */ }), ]); } } catch (err: unknown) { rejectFromError(err); } } + if (timeoutId !== undefined) { clearTimeout(timeoutId); } if (rejected) { return; } diff --git a/server/src/version.ts b/server/src/version.ts index 64692cc..ae54a0e 100644 --- a/server/src/version.ts +++ b/server/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.6.10'; +export const VERSION = '0.6.11'; diff --git a/server/test/server.test.ts b/server/test/server.test.ts index 0cbeff7..2452aca 100644 --- a/server/test/server.test.ts +++ b/server/test/server.test.ts @@ -674,4 +674,19 @@ describe('Krmx Server', () => { expect(Date.now() - time).toBeLessThan(100); // should be rejected immediately await expect(addUser('rens')).rejects.toBe('immediately rejected by throw'); })); + + it('should not send a spurious rejection to a successfully authenticated async user after the timeout expires', + withCustomServer({ authTimeoutMilliseconds: 200 }, async ({ server, addUser }) => { + server.on('authenticate', (_username, _info, _reject, markAsync) => markAsync(async () => { + await sleep(100); // completes well before the 200ms timeout + })); + const simon = await addUser('simon'); + // Wait longer than the authTimeoutMilliseconds to ensure no spurious rejection fires + await sleep(400); + // The user should NOT have received a krmx/rejected message after being accepted + const messages = simon.emit.message.mock.calls.map((call) => (call[0] as { type: string }).type); + expect(messages).not.toContain('krmx/rejected'); + expect(messages).toContain('krmx/accepted'); + }), + ); });