From dce03a6ce0d7f038fea37c87491a98f8389b7636 Mon Sep 17 00:00:00 2001 From: Deepak Bhagat Date: Fri, 30 Jan 2026 06:35:16 +0530 Subject: [PATCH 1/2] fix: remove dangerous busy-wait lock in handleTypingEvent causing DoS --- packages/api/src/EmbeddedChatApi.ts | 64 ++++++++++++----------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts index 72e25a046..df5d1b505 100644 --- a/packages/api/src/EmbeddedChatApi.ts +++ b/packages/api/src/EmbeddedChatApi.ts @@ -7,8 +7,6 @@ import { ApiError, } from "@embeddedchat/auth"; -// mutliple typing status can come at the same time they should be processed in order. -let typingHandlerLock = 0; export default class EmbeddedChatApi { host: string; rid: string; @@ -73,21 +71,21 @@ export default class EmbeddedChatApi { const payload = acsCode ? JSON.stringify({ - serviceName: "google", - accessToken: tokens.access_token, - idToken: tokens.id_token, - expiresIn: 3600, - totp: { - code: acsPayload, - }, - }) + serviceName: "google", + accessToken: tokens.access_token, + idToken: tokens.id_token, + expiresIn: 3600, + totp: { + code: acsPayload, + }, + }) : JSON.stringify({ - serviceName: "google", - accessToken: tokens.access_token, - idToken: tokens.id_token, - expiresIn: 3600, - scope: "profile", - }); + serviceName: "google", + accessToken: tokens.access_token, + idToken: tokens.id_token, + expiresIn: 3600, + scope: "profile", + }); try { const req = await fetch(`${this.host}/api/v1/login`, { @@ -358,13 +356,6 @@ export default class EmbeddedChatApi { typingUser: string; isTyping: boolean; }) { - // don't wait for more than 2 seconds. Though in practical, the waiting time is insignificant. - setTimeout(() => { - typingHandlerLock = 0; - }, 2000); - // eslint-disable-next-line no-empty - while (typingHandlerLock) {} - typingHandlerLock = 1; // move user to front if typing else remove it. const idx = this.typingUsers.indexOf(typingUser); if (idx !== -1) { @@ -373,7 +364,6 @@ export default class EmbeddedChatApi { if (isTyping) { this.typingUsers.unshift(typingUser); } - typingHandlerLock = 0; const newTypingStatus = cloneArray(this.typingUsers); this.onTypingStatusCallbacks.forEach((callback) => callback(newTypingStatus) @@ -561,9 +551,9 @@ export default class EmbeddedChatApi { query?: object | undefined; field?: object | undefined; } = { - query: undefined, - field: undefined, - }, + query: undefined, + field: undefined, + }, isChannelPrivate = false ) { const roomType = isChannelPrivate ? "groups" : "channels"; @@ -600,10 +590,10 @@ export default class EmbeddedChatApi { field?: object | undefined; offset?: number; } = { - query: undefined, - field: undefined, - offset: 50, - }, + query: undefined, + field: undefined, + offset: 50, + }, isChannelPrivate = false ) { const roomType = isChannelPrivate ? "groups" : "channels"; @@ -751,13 +741,13 @@ export default class EmbeddedChatApi { const messageObj = typeof message === "string" ? { - rid: this.rid, - msg: message, - } + rid: this.rid, + msg: message, + } : { - ...message, - rid: this.rid, - }; + ...message, + rid: this.rid, + }; if (threadId) { messageObj.tmid = threadId; } From 2a8dee606f0ad4a391ab18b8363384bf1ab95fe0 Mon Sep 17 00:00:00 2001 From: Deepak Bhagat Date: Fri, 30 Jan 2026 06:45:19 +0530 Subject: [PATCH 2/2] style: fix formatting in EmbeddedChatApi.ts --- packages/api/src/EmbeddedChatApi.ts | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts index df5d1b505..b978e67e2 100644 --- a/packages/api/src/EmbeddedChatApi.ts +++ b/packages/api/src/EmbeddedChatApi.ts @@ -71,21 +71,21 @@ export default class EmbeddedChatApi { const payload = acsCode ? JSON.stringify({ - serviceName: "google", - accessToken: tokens.access_token, - idToken: tokens.id_token, - expiresIn: 3600, - totp: { - code: acsPayload, - }, - }) + serviceName: "google", + accessToken: tokens.access_token, + idToken: tokens.id_token, + expiresIn: 3600, + totp: { + code: acsPayload, + }, + }) : JSON.stringify({ - serviceName: "google", - accessToken: tokens.access_token, - idToken: tokens.id_token, - expiresIn: 3600, - scope: "profile", - }); + serviceName: "google", + accessToken: tokens.access_token, + idToken: tokens.id_token, + expiresIn: 3600, + scope: "profile", + }); try { const req = await fetch(`${this.host}/api/v1/login`, { @@ -551,9 +551,9 @@ export default class EmbeddedChatApi { query?: object | undefined; field?: object | undefined; } = { - query: undefined, - field: undefined, - }, + query: undefined, + field: undefined, + }, isChannelPrivate = false ) { const roomType = isChannelPrivate ? "groups" : "channels"; @@ -590,10 +590,10 @@ export default class EmbeddedChatApi { field?: object | undefined; offset?: number; } = { - query: undefined, - field: undefined, - offset: 50, - }, + query: undefined, + field: undefined, + offset: 50, + }, isChannelPrivate = false ) { const roomType = isChannelPrivate ? "groups" : "channels"; @@ -741,13 +741,13 @@ export default class EmbeddedChatApi { const messageObj = typeof message === "string" ? { - rid: this.rid, - msg: message, - } + rid: this.rid, + msg: message, + } : { - ...message, - rid: this.rid, - }; + ...message, + rid: this.rid, + }; if (threadId) { messageObj.tmid = threadId; }