-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix: chat.update not updating e2ee messages correctly #6723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughThis change replaces the previous encrypted message content type with a new union type across message and attachment definitions, updates the chat.update REST params to accept encrypted content and e2e mentions, adjusts decryption to populate message text, and updates editMessage to handle encryption and branch requests accordingly. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Client UI
participant Service as editMessage()
participant Crypto as E2E Encryptor
participant API as REST chat.update
UI->>Service: editMessage({ id, rid, msg?, content?, e2eMentions? })
Note over Service: Prepare payload for encryption
Service->>Crypto: encrypt({ msg/content, rid, mentions })
alt Encryption fails
Crypto-->>Service: error/null
Service-->>UI: throw Error("encryption failed")
else Encryption succeeds
Crypto-->>Service: { content? , text? , e2eMentions? }
alt Has encrypted content
Service->>API: POST /chat.update { roomId, msgId, content, e2eMentions }
else Fallback to plaintext
Service->>API: POST /chat.update { roomId, msgId, text }
end
API-->>Service: 200 OK
Service-->>UI: resolve()
end
sequenceDiagram
autonumber
participant Server as Server
participant Decrypt as room.decrypt()
participant Msg as IMessage
Server-->>Decrypt: content (rc.v1.aes-sha2)
Decrypt-->>Decrypt: decrypt content
alt content.text present
Decrypt->>Msg: msg = content.text
else No text
Note over Decrypt,Msg: msg unchanged
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–70 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/lib/encryption/room.ts (1)
648-651
: Normalize from bothcontent.text
andcontent.msg
.Be explicit and resilient to either field being present.
- if (content.text) { - message.msg = content.text; - } + const normalizedText = (content as any)?.text ?? (content as any)?.msg; + if (normalizedText) { + message.msg = normalizedText; + }app/definitions/IMessage.ts (1)
83-107
: Consider a single discriminated union without the base interface.Defining
TEncryptedContent
directly tightens thealgorithm
literal type and reduces indirection. Current approach works; this is just simplification.export type TEncryptedContent = | { algorithm: 'rc.v1.aes-sha2'; ciphertext: string } | { algorithm: 'rc.v2.aes-sha2'; ciphertext: string; iv: string; kid: string };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
app/definitions/IAttachment.ts
(2 hunks)app/definitions/IMessage.ts
(3 hunks)app/definitions/rest/v1/chat.ts
(2 hunks)app/lib/encryption/room.ts
(1 hunks)app/lib/services/restApi.ts
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/lib/services/restApi.ts (2)
app/definitions/IMessage.ts (1)
IMessage
(146-177)android/app/src/main/java/chat/rocket/reactnative/notification/Encryption.java (1)
Encryption
(67-267)
app/definitions/rest/v1/chat.ts (2)
app/definitions/IRoom.ts (1)
IServerRoom
(152-236)app/definitions/IMessage.ts (2)
TEncryptedContent
(107-107)IMessage
(146-177)
app/definitions/IAttachment.ts (1)
app/definitions/IMessage.ts (1)
TEncryptedContent
(107-107)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ESLint and Test / run-eslint-and-test
🔇 Additional comments (4)
app/definitions/IMessage.ts (1)
171-171
: Publice2eMentions
shape looks good.No concerns. Aligns with usage downstream.
app/definitions/rest/v1/chat.ts (1)
78-84
: API shape update LGTM; confirm backward compatibility.Extending
chat.update
to acceptcontent
/e2eMentions
makes sense. Please verify behavior against older servers wheretext
might still be required.app/definitions/IAttachment.ts (2)
2-2
: Type import update LGTM.Consistent with
TEncryptedContent
adoption.
75-76
: Attachmentcontent
now usesTEncryptedContent
— good.Matches decryption logic that checks
algorithm
andciphertext
.
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid' | 'content' | 'e2eMentions'>) => { | ||
const result = await Encryption.encryptMessage(message as IMessage); | ||
if (!result) { | ||
throw new Error('Failed to encrypt message'); | ||
} | ||
|
||
if (result.content) { | ||
// RC 0.49.0 | ||
return sdk.post('chat.update', { | ||
roomId: message.rid, | ||
msgId: message.id, | ||
content: result.content, | ||
e2eMentions: result.e2eMentions | ||
}); | ||
} | ||
|
||
// RC 0.49.0 | ||
return sdk.post('chat.update', { roomId: rid, msgId: message.id, text: msg }); | ||
return sdk.post('chat.update', { | ||
roomId: message.rid, | ||
msgId: message.id, | ||
text: message.msg || '' | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add fallback for servers that don’t support content
in chat.update
.
Currently, edits in E2EE rooms may fail on older servers (where text
is required). Try content
first, then fallback to text
with the ciphertext.
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid' | 'content' | 'e2eMentions'>) => {
const result = await Encryption.encryptMessage(message as IMessage);
if (!result) {
throw new Error('Failed to encrypt message');
}
if (result.content) {
- // RC 0.49.0
- return sdk.post('chat.update', {
- roomId: message.rid,
- msgId: message.id,
- content: result.content,
- e2eMentions: result.e2eMentions
- });
+ try {
+ // Prefer new API with encrypted content
+ return await sdk.post('chat.update', {
+ roomId: message.rid,
+ msgId: message.id,
+ content: result.content,
+ e2eMentions: result.e2eMentions
+ });
+ } catch (e) {
+ // Fallback for older servers: send ciphertext as text
+ const ciphertext = (result as any).msg ?? result.content.ciphertext ?? message.msg ?? '';
+ return sdk.post('chat.update', {
+ roomId: message.rid,
+ msgId: message.id,
+ text: ciphertext
+ });
+ }
}
// RC 0.49.0
return sdk.post('chat.update', {
roomId: message.rid,
msgId: message.id,
text: message.msg || ''
});
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid' | 'content' | 'e2eMentions'>) => { | |
const result = await Encryption.encryptMessage(message as IMessage); | |
if (!result) { | |
throw new Error('Failed to encrypt message'); | |
} | |
if (result.content) { | |
// RC 0.49.0 | |
return sdk.post('chat.update', { | |
roomId: message.rid, | |
msgId: message.id, | |
content: result.content, | |
e2eMentions: result.e2eMentions | |
}); | |
} | |
// RC 0.49.0 | |
return sdk.post('chat.update', { roomId: rid, msgId: message.id, text: msg }); | |
return sdk.post('chat.update', { | |
roomId: message.rid, | |
msgId: message.id, | |
text: message.msg || '' | |
}); | |
}; | |
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid' | 'content' | 'e2eMentions'>) => { | |
const result = await Encryption.encryptMessage(message as IMessage); | |
if (!result) { | |
throw new Error('Failed to encrypt message'); | |
} | |
if (result.content) { | |
try { | |
// Prefer new API with encrypted content | |
return await sdk.post('chat.update', { | |
roomId: message.rid, | |
msgId: message.id, | |
content: result.content, | |
e2eMentions: result.e2eMentions | |
}); | |
} catch (e) { | |
// Fallback for older servers: send ciphertext as text | |
const ciphertext = (result as any).msg ?? result.content.ciphertext ?? message.msg ?? ''; | |
return sdk.post('chat.update', { | |
roomId: message.rid, | |
msgId: message.id, | |
text: ciphertext | |
}); | |
} | |
} | |
// RC 0.49.0 | |
return sdk.post('chat.update', { | |
roomId: message.rid, | |
msgId: message.id, | |
text: message.msg || '' | |
}); | |
}; |
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid'>) => { | ||
const { rid, msg } = await Encryption.encryptMessage(message as IMessage); | ||
export const editMessage = async (message: Pick<IMessage, 'id' | 'msg' | 'rid' | 'content' | 'e2eMentions'>) => { | ||
const result = await Encryption.encryptMessage(message as IMessage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposed changes
Sends the extra params needed for
chat.update
to work.Issue(s)
Counterpart of RocketChat/Rocket.Chat#37138
https://rocketchat.atlassian.net/browse/ESH-47
How to test or reproduce
Tested on workspaces with and without RocketChat/Rocket.Chat#37138.
The app doesn't crash.
Screenshots
Types of changes
Checklist
Further comments
Summary by CodeRabbit
New Features
Bug Fixes