Skip to content

fix: API Modernization, Security, and Stability Improvements for EmbeddedChat#1155

Open
vivekyadav-3 wants to merge 20 commits intoRocketChat:developfrom
vivekyadav-3:fix/api-stability-and-modernization
Open

fix: API Modernization, Security, and Stability Improvements for EmbeddedChat#1155
vivekyadav-3 wants to merge 20 commits intoRocketChat:developfrom
vivekyadav-3:fix/api-stability-and-modernization

Conversation

@vivekyadav-3
Copy link

I’ve been working on a few improvements to help make the chat experience more reliable and secure. These changes focus on fixing some underlying performance bottlenecks and modernizing how the app communicates with the Rocket.Chat server.

Key Changes
Resolved App Freezing: I identified a blocking loop in the typing status handler that was causing the browser to freeze when multiple people were active at once. I’ve refactored this logic to be non-blocking, ensuring the UI stays smooth and responsive.
Modernized Server Communication: Some of the older methods used to fetch user roles and room details are becoming unreliable on modern server versions. I’ve updated these to use the latest REST API endpoints. This fixes issues where "Admin" badges or archived room information didn't always display correctly.
Enhanced Security & Reliability: I’ve implemented proper encoding for search and message filters to prevent "parameter pollution" and ensure requests don't fail unexpectedly. I also added a safety check to handle excessively long messages gracefully before they are sent.
General Housekeeping: I did some minor cleanup across several components, removing unused variables and imports to keep the codebase tidy and maintainable.

… authentication, commands, and message tools
- Added encodeURIComponent() to properly encode user input before appending to URL query string
- Prevents special characters (&, ?, #, %) from breaking query parameters
- Fixes issue RocketChat#1149
- Changed typing status timeout from 15000ms to 10000ms
- Makes typing indicator more responsive and updates faster
- Improves real-time chat experience
- Added defensive check to ensure selectedItem exists before accessing properties
- Prevents TypeError when user types commands not in the filtered list
- Fixes issue RocketChat#1144
…icated

- Added default empty string values in destructuring pattern
- Fixes all 37 API methods that were sending literal 'undefined' as header values
- Headers now send empty strings instead of 'undefined' when user is not logged in
- Fixes issue RocketChat#1133
Summary of changes:
- Replaced legacy DDP method calls (getUserRoles, rooms:get) with modern REST API endpoints for better server compatibility.
- Fixed critical busy-wait loop in handleTypingEvent that caused application freezes.
- URL-encoded search and filter parameters in API calls to prevent HTTP Parameter Pollution.
- Added a 50,000-character safety guard in sendMessage to prevent crashes from excessively large messages.
- Cleaned up unused variables and imports across several components.
Copilot AI review requested due to automatic review settings February 13, 2026 07:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes parts of EmbeddedChat’s React UI and the EmbeddedChatApi client to improve stability, responsiveness, and request safety (URL encoding + safer request bodies), while also cleaning up unused imports/variables.

Changes:

  • Refactors typing indicator listener handling and reduces typing timeout (intended) while adding memoization/cleanup in several UI components.
  • Updates API calls to newer REST endpoints, adds URL encoding for query/field/search params, and replaces manual JSON string construction with JSON.stringify.
  • Adds UX-facing error toasts for auth flows and general cleanup across multiple components/stores.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/react/src/views/ChatInput/ChatInput.js Adjusts typing timeout + quote-link assembly logic
packages/react/src/views/EmbeddedChat.js Adds auto-login failure toast + memoizes auth config
packages/react/src/views/ChatHeader/ChatHeader.js Refactors logout to always delete stored token and reset state
packages/api/src/EmbeddedChatApi.ts Removes blocking typing lock, encodes query params, modernizes room/role APIs, uses JSON.stringify, adds max-length guard
packages/react/src/lib/emoji.js Updates emoji parsing to replace all shortnames
packages/react/lint_report.txt Adds a lint output artifact file (should not be committed)
GSOC_2026_PROPOSAL_EmbeddedChat.md Adds proposal document (process/docs addition)
packages/react/src/views/* (multiple) Memoization, unused import cleanup, minor safety checks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 137 to 139
const { deleteToken } = getTokenStorage(
ECOptions?.secure
);
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logout token deletion is wired to getTokenStorage(ECOptions?.secure), but ECOptions created in EmbeddedChat does not include secure. In secure mode this can delete from the wrong storage (or not delete at all), leaving auth tokens behind after logout. Pass secure through ECOptions or obtain the correct deleteToken from the same place the RCInstance was initialized.

Suggested change
const { deleteToken } = getTokenStorage(
ECOptions?.secure
);
const secure = useSettingsStore((state) => state.secure);
const { deleteToken } = getTokenStorage(secure);

Copilot uses AI. Check for mistakes.
Comment on lines +743 to +745
if (messageObj.msg && messageObj.msg.length > 50000) {
return { success: false, error: "Message is too long" };
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hard-coded 50000 message length limit is a magic number and can diverge from the server’s configured Message_MaxAllowedSize (which the UI already fetches). Consider using the server-provided limit (or at least centralizing this constant) and returning an error shape consistent with other API failures so the UI can surface the reason to the user.

Copilot uses AI. Check for mistakes.
Comment on lines 4 to 7
return text.replace(/:([^:\s]+):/g, (match) => {
const unicode = emojione.shortnameToUnicode(match);
return unicode !== undefined && unicode !== match ? unicode : match;
});
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation violates ESLint arrow-body-style (it uses a block body with an explicit return). If the repo enforces this rule (as shown in the included lint output), adjust the callback to use an implicit return or disable the rule for this line/file.

Suggested change
return text.replace(/:([^:\s]+):/g, (match) => {
const unicode = emojione.shortnameToUnicode(match);
return unicode !== undefined && unicode !== match ? unicode : match;
});
return text.replace(
/:([^:\s]+):/g,
(match) =>
emojione.shortnameToUnicode(match) !== undefined &&
emojione.shortnameToUnicode(match) !== match
? emojione.shortnameToUnicode(match)
: match
);

Copilot uses AI. Check for mistakes.
timerRef.current = setTimeout(() => {
typingRef.current = false;
}, [15000]);
}, [10000]);
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setTimeout is being called with an array ([10000]) as the delay argument. This will coerce to NaN and effectively make the typing flag reset immediately, breaking typing status behavior. Pass a number (e.g., 10000) instead of an array.

Suggested change
}, [10000]);
}, 10000);

Copilot uses AI. Check for mistakes.
Comment on lines 91 to 145
@@ -125,13 +132,17 @@ const EmbeddedChat = (props) => {
try {
await RCInstance.autoLogin(auth);
} catch (error) {
console.error(error);
console.error('Auto-login failed:', error);
dispatchToastMessage({
type: 'error',
message: 'Auto-login failed. Please sign in manually.',
});
} finally {
setIsLoginIn(false);
}
};
autoLogin();
}, [RCInstance, auth, setIsLoginIn]);
}, [RCInstance, auth, setIsLoginIn, dispatchToastMessage]);
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useToastBarDispatch() is called in EmbeddedChat before the <ToastBarProvider> is rendered (the provider is created inside this component’s return). If there is no higher-level provider, this hook will throw at runtime. Consider moving ToastBarProvider above this component, or moving the auto-login/toast logic into a child component that is rendered inside the provider.

Copilot uses AI. Check for mistakes.
Comment on lines 482 to 503
async getRoomInfo() {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const { userId = "", authToken = "" } =
(await this.auth.getCurrentUser()) || {};
const response = await fetch(
`${this.host}/api/v1/method.call/rooms%3Aget`,
`${this.host}/api/v1/rooms.get`,
{
body: JSON.stringify({
message: JSON.stringify({
msg: "method",
id: null,
method: "rooms/get",
params: [],
}),
}),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
"X-User-Id": userId,
},
method: "POST",
method: "GET",
}
);

const result = await response.json();

if (result.success && result.message) {
const parsedMessage = JSON.parse(result.message);
return parsedMessage;
if (result.success && result.update) {
return { success: true, result: result.update };
}
return null;
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getRoomInfo() now calls GET /api/v1/rooms.get without filtering by roomId, and returns the entire update array. Current usage expects data for the current room, so this can lead to incorrect room details (and unnecessary payload). Consider calling an endpoint that returns a single room (or filter result.update to the current this.rid before returning).

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +10
# GSoC 2026 Proposal: EmbeddedChat Stability & Input Hardening - Vivek Yadav

---

## 1. Abstract

I am proposing a targeted set of improvements for the **Rocket.Chat EmbeddedChat** component to ensure production-grade reliability. While EmbeddedChat serves as a powerful drop-in solution, specific user experience gaps—specifically in message composition and authentication stability—hinder its adoption. My project will leverage the **React SDK** internals to harden the input handling system, optimize the authentication hooks, and implement a robust "quoting" mechanism.

## 2. The Problem

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains a personal/organizational proposal document rather than project documentation tied to shipped behavior. Keeping it in the main repo may add noise and make maintenance harder; consider moving it to an external document or linking it from an issue/PR discussion instead of committing it here.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +67
const auth = useMemo(
() => authProp,
[JSON.stringify(authProp)] // Deep comparison via stringify to handle inline objects
);
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using useMemo(() => authProp, [JSON.stringify(authProp)]) forces a stringify on every render and can still be unstable (key order) while also defeating exhaustive-deps linting. Prefer passing a stable auth object from the caller, or use a dedicated deep-compare memo/effect helper so dependency tracking remains predictable.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant