-
Notifications
You must be signed in to change notification settings - Fork 13k
fix: fixes reviews of chore/federation-backup #37016
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
Changes from all commits
0a11db5
dfe825a
6954664
d5c43ac
1adad4b
55f1044
8bcf528
27931e8
6d59e0c
044e830
648bfac
bf0769a
5096371
b76e50b
b30aaef
558e8d6
d5cbc09
87636ef
89f1d59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,3 @@ | ||
| export type Config = { | ||
| port: number; | ||
| host: string; | ||
| routePrefix: string; | ||
| rocketchatUrl: string; | ||
| authMode: 'jwt' | 'api-key' | 'internal'; | ||
| logLevel: 'debug' | 'info' | 'warn' | 'error'; | ||
| nodeEnv: 'development' | 'production' | 'test'; | ||
| }; | ||
|
|
||
| export function isRunningMs(): boolean { | ||
| return !!process.env.TRANSPORTER?.match(/^(?:nats|TCP)/); | ||
| } | ||
|
|
||
| export const config = { | ||
| port: parseInt(process.env.FEDERATION_SERVICE_PORT || '3030'), | ||
| host: process.env.FEDERATION_SERVICE_HOST || '0.0.0.0', | ||
| routePrefix: process.env.FEDERATION_ROUTE_PREFIX || '/_matrix', | ||
| rocketchatUrl: process.env.ROCKETCHAT_URL || '', | ||
| authMode: (process.env.FEDERATION_AUTH_MODE as any) || 'jwt', | ||
| logLevel: (process.env.LOG_LEVEL as any) || 'info', | ||
| nodeEnv: (process.env.NODE_ENV as any) || 'development', | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,7 +85,7 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS | |
| version: process.env.SERVER_VERSION || '1.0', | ||
| port: Number.parseInt(process.env.SERVER_PORT || '8080', 10), | ||
| signingKey: `${settingsSigningAlg} ${settingsSigningVersion} ${settingsSigningKey}`, | ||
| signingKeyPath: process.env.CONFIG_FOLDER || './rc1.signing.key', | ||
| signingKeyPath: process.env.CONFIG_FOLDER || './rocketchat.signing.key', | ||
| database: { | ||
| uri: mongoUri, | ||
| name: dbName, | ||
|
|
@@ -243,8 +243,10 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS | |
|
|
||
| if (typeof member === 'string') { | ||
| username = member; | ||
| } else if (typeof member.username === 'string') { | ||
| username = member.username; | ||
| } else { | ||
| username = member.username as string; | ||
| continue; | ||
| } | ||
|
|
||
| if (!username.includes(':') && !username.includes('@')) { | ||
|
|
@@ -428,22 +430,26 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS | |
| } | ||
|
|
||
| try { | ||
| // TODO: Handle multiple files | ||
| const file = message.files[0]; | ||
| const mxcUri = await MatrixMediaService.prepareLocalFileForMatrix(file._id, matrixDomain); | ||
|
|
||
| const msgtype = this.getMatrixMessageType(file.type); | ||
| const fileContent = { | ||
| body: file.name, | ||
| msgtype, | ||
| url: mxcUri, | ||
| info: { | ||
| mimetype: file.type, | ||
| size: file.size, | ||
| }, | ||
| }; | ||
| let lastEventId: { eventId: string } | null = null; | ||
|
|
||
| for await (const file of message.files) { | ||
| const mxcUri = await MatrixMediaService.prepareLocalFileForMatrix(file._id, matrixDomain); | ||
|
|
||
| const msgtype = this.getMatrixMessageType(file.type); | ||
| const fileContent = { | ||
| body: file.name, | ||
| msgtype, | ||
| url: mxcUri, | ||
| info: { | ||
| mimetype: file.type, | ||
| size: file.size, | ||
| }, | ||
| }; | ||
|
|
||
| lastEventId = await this.homeserverServices.message.sendFileMessage(matrixRoomId, fileContent, matrixUserId); | ||
| } | ||
|
|
||
| return this.homeserverServices.message.sendFileMessage(matrixRoomId, fileContent, matrixUserId); | ||
| return lastEventId; | ||
| } catch (error) { | ||
|
Comment on lines
+433
to
453
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Multi-file messages lose all but last Matrix event ID.
If schema changes aren’t feasible now, gate multi-file sending or send a single aggregated file until persistence supports multiples. Also applies to: 571-571 |
||
| this.logger.error('Failed to handle file message', { | ||
| messageId: message._id, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,7 +149,7 @@ | |
| required: ['roomId', 'userId'], | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 152 in ee/packages/federation-matrix/src/api/_matrix/profiles.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isMakeJoinParamsProps = ajv.compile(MakeJoinParamsSchema); | ||
|
|
||
|
|
@@ -167,7 +167,7 @@ | |
| }, | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 170 in ee/packages/federation-matrix/src/api/_matrix/profiles.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isMakeJoinQueryProps = ajv.compile(MakeJoinQuerySchema); | ||
|
|
||
|
|
@@ -253,7 +253,7 @@ | |
| required: ['room_version', 'event'], | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 256 in ee/packages/federation-matrix/src/api/_matrix/profiles.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isMakeJoinResponseProps = ajv.compile(MakeJoinResponseSchema); | ||
|
|
||
|
|
@@ -421,11 +421,10 @@ | |
| .get( | ||
| '/v1/make_join/:roomId/:userId', | ||
| { | ||
| // TODO: fix types here, likely import from room package | ||
| params: ajv.compile({ type: 'object' }), | ||
| query: ajv.compile({ type: 'object' }), | ||
| params: isMakeJoinParamsProps, | ||
| query: isMakeJoinQueryProps, | ||
| response: { | ||
| 200: ajv.compile({ type: 'object' }), | ||
| 200: isMakeJoinResponseProps, | ||
| }, | ||
| tags: ['Federation'], | ||
| license: ['federation'], | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,7 +47,7 @@ | |
| required: ['roomId', 'stateKey'], | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 50 in ee/packages/federation-matrix/src/api/_matrix/send-join.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isSendJoinParamsProps = ajv.compile(SendJoinParamsSchema); | ||
|
|
||
|
|
@@ -184,7 +184,7 @@ | |
| ], | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 187 in ee/packages/federation-matrix/src/api/_matrix/send-join.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isSendJoinEventProps = ajv.compile(SendJoinEventSchema); | ||
|
|
||
|
|
@@ -218,7 +218,7 @@ | |
| required: ['event', 'state', 'auth_chain', 'members_omitted', 'origin'], | ||
| }; | ||
|
|
||
| // @ts-ignore | ||
|
Check warning on line 221 in ee/packages/federation-matrix/src/api/_matrix/send-join.ts
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const isSendJoinResponseProps = ajv.compile(SendJoinResponseSchema); | ||
|
|
||
|
|
@@ -228,10 +228,10 @@ | |
| return new Router('/federation').put( | ||
| '/v2/send_join/:roomId/:stateKey', | ||
| { | ||
| params: ajv.compile({ type: 'object' }), | ||
| body: ajv.compile({ type: 'object' }), | ||
| params: isSendJoinParamsProps, | ||
| body: isSendJoinEventProps, | ||
| response: { | ||
| 200: ajv.compile({ type: 'object' }), | ||
| 200: isSendJoinResponseProps, | ||
| }, | ||
| tags: ['Federation'], | ||
| license: ['federation'], | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,8 @@ | ||||||||||||||||||||||
| import type { FileMessageType, MessageType } from '@hs/core'; | ||||||||||||||||||||||
| import type { FileMessageType, MessageType, FileMessageContent } from '@hs/core'; | ||||||||||||||||||||||
| import type { HomeserverEventSignatures } from '@hs/federation-sdk'; | ||||||||||||||||||||||
| import type { EventID } from '@hs/room'; | ||||||||||||||||||||||
| import { FederationMatrix, Message, MeteorService } from '@rocket.chat/core-services'; | ||||||||||||||||||||||
| import type { IUser, IRoom } from '@rocket.chat/core-typings'; | ||||||||||||||||||||||
| import type { IUser, IRoom, FileAttachmentProps } from '@rocket.chat/core-typings'; | ||||||||||||||||||||||
| import type { Emitter } from '@rocket.chat/emitter'; | ||||||||||||||||||||||
| import { Logger } from '@rocket.chat/logger'; | ||||||||||||||||||||||
| import { Users, Rooms, Messages } from '@rocket.chat/models'; | ||||||||||||||||||||||
|
|
@@ -25,40 +25,37 @@ async function getThreadMessageId(threadRootEventId: EventID): Promise<{ tmid: s | |||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| async function handleMediaMessage( | ||||||||||||||||||||||
| // TODO improve typing | ||||||||||||||||||||||
| content: any, | ||||||||||||||||||||||
| url: string, | ||||||||||||||||||||||
| fileInfo: FileMessageContent['info'], | ||||||||||||||||||||||
| msgtype: MessageType, | ||||||||||||||||||||||
| messageBody: string, | ||||||||||||||||||||||
| user: IUser, | ||||||||||||||||||||||
| room: IRoom, | ||||||||||||||||||||||
| eventId: string, | ||||||||||||||||||||||
| eventId: EventID, | ||||||||||||||||||||||
| tmid?: string, | ||||||||||||||||||||||
| ): Promise<{ | ||||||||||||||||||||||
| fromId: string; | ||||||||||||||||||||||
| rid: string; | ||||||||||||||||||||||
| msg: string; | ||||||||||||||||||||||
| federation_event_id: string; | ||||||||||||||||||||||
| tmid?: string; | ||||||||||||||||||||||
| file: any; | ||||||||||||||||||||||
| files: any[]; | ||||||||||||||||||||||
| attachments: any[]; | ||||||||||||||||||||||
| attachments: [FileAttachmentProps]; | ||||||||||||||||||||||
| }> { | ||||||||||||||||||||||
| const fileInfo = content.info; | ||||||||||||||||||||||
| const mimeType = fileInfo.mimetype; | ||||||||||||||||||||||
| const mimeType = fileInfo?.mimetype; | ||||||||||||||||||||||
| const fileName = messageBody; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const fileRefId = await MatrixMediaService.downloadAndStoreRemoteFile(content.url, { | ||||||||||||||||||||||
| const fileRefId = await MatrixMediaService.downloadAndStoreRemoteFile(url, { | ||||||||||||||||||||||
| name: messageBody, | ||||||||||||||||||||||
| size: fileInfo.size, | ||||||||||||||||||||||
| size: fileInfo?.size, | ||||||||||||||||||||||
| type: mimeType, | ||||||||||||||||||||||
| roomId: room._id, | ||||||||||||||||||||||
| userId: user._id, | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| let fileExtension = ''; | ||||||||||||||||||||||
| if (fileName && fileName.includes('.')) { | ||||||||||||||||||||||
| if (fileName?.includes('.')) { | ||||||||||||||||||||||
| fileExtension = fileName.split('.').pop()?.toLowerCase() || ''; | ||||||||||||||||||||||
| } else if (mimeType && mimeType.includes('/')) { | ||||||||||||||||||||||
| } else if (mimeType?.includes('/')) { | ||||||||||||||||||||||
| fileExtension = mimeType.split('/')[1] || ''; | ||||||||||||||||||||||
| if (fileExtension === 'jpeg') { | ||||||||||||||||||||||
| fileExtension = 'jpg'; | ||||||||||||||||||||||
|
|
@@ -67,55 +64,50 @@ async function handleMediaMessage( | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| const fileUrl = `/file-upload/${fileRefId}/${encodeURIComponent(fileName)}`; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // TODO improve typing | ||||||||||||||||||||||
| const attachment: any = { | ||||||||||||||||||||||
| let attachment: FileAttachmentProps = { | ||||||||||||||||||||||
| title: fileName, | ||||||||||||||||||||||
| type: 'file', | ||||||||||||||||||||||
| title_link: fileUrl, | ||||||||||||||||||||||
| title_link_download: true, | ||||||||||||||||||||||
| description: '', | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (msgtype === 'm.image') { | ||||||||||||||||||||||
| attachment.image_url = fileUrl; | ||||||||||||||||||||||
| attachment.image_type = mimeType; | ||||||||||||||||||||||
| attachment.image_size = fileInfo.size || 0; | ||||||||||||||||||||||
| attachment.description = ''; | ||||||||||||||||||||||
| if (fileInfo.w && fileInfo.h) { | ||||||||||||||||||||||
| attachment.image_dimensions = { | ||||||||||||||||||||||
| width: fileInfo.w, | ||||||||||||||||||||||
| height: fileInfo.h, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| attachment = { | ||||||||||||||||||||||
| ...attachment, | ||||||||||||||||||||||
| image_url: fileUrl, | ||||||||||||||||||||||
| image_type: mimeType, | ||||||||||||||||||||||
| image_size: fileInfo?.size || 0, | ||||||||||||||||||||||
| ...(fileInfo?.w && | ||||||||||||||||||||||
| fileInfo?.h && { | ||||||||||||||||||||||
| image_dimensions: { | ||||||||||||||||||||||
| width: fileInfo.w, | ||||||||||||||||||||||
| height: fileInfo.h, | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| }), | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| } else if (msgtype === 'm.video') { | ||||||||||||||||||||||
| attachment.video_url = fileUrl; | ||||||||||||||||||||||
| attachment.video_type = mimeType; | ||||||||||||||||||||||
| attachment.video_size = fileInfo.size || 0; | ||||||||||||||||||||||
| attachment.description = ''; | ||||||||||||||||||||||
| attachment = { | ||||||||||||||||||||||
| ...attachment, | ||||||||||||||||||||||
| video_url: fileUrl, | ||||||||||||||||||||||
| video_type: mimeType, | ||||||||||||||||||||||
| video_size: fileInfo?.size || 0, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| } else if (msgtype === 'm.audio') { | ||||||||||||||||||||||
| attachment.audio_url = fileUrl; | ||||||||||||||||||||||
| attachment.audio_type = mimeType; | ||||||||||||||||||||||
| attachment.audio_size = fileInfo.size || 0; | ||||||||||||||||||||||
| attachment.description = ''; | ||||||||||||||||||||||
| } else { | ||||||||||||||||||||||
| attachment.description = ''; | ||||||||||||||||||||||
| attachment = { | ||||||||||||||||||||||
| ...attachment, | ||||||||||||||||||||||
| audio_url: fileUrl, | ||||||||||||||||||||||
| audio_type: mimeType, | ||||||||||||||||||||||
| audio_size: fileInfo?.size || 0, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const fileData = { | ||||||||||||||||||||||
| _id: fileRefId, | ||||||||||||||||||||||
| name: fileName, | ||||||||||||||||||||||
| type: mimeType, | ||||||||||||||||||||||
| size: fileInfo.size || 0, | ||||||||||||||||||||||
| format: fileExtension, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| fromId: user._id, | ||||||||||||||||||||||
| rid: room._id, | ||||||||||||||||||||||
| msg: '', | ||||||||||||||||||||||
| federation_event_id: eventId, | ||||||||||||||||||||||
| tmid, | ||||||||||||||||||||||
| file: fileData, | ||||||||||||||||||||||
| files: [fileData], | ||||||||||||||||||||||
| attachments: [attachment], | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
@@ -124,8 +116,8 @@ export function message(emitter: Emitter<HomeserverEventSignatures>, serverName: | |||||||||||||||||||||
| emitter.on('homeserver.matrix.message', async (data) => { | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| const { content } = data; | ||||||||||||||||||||||
| const msgtype = content?.msgtype; | ||||||||||||||||||||||
| const messageBody = content?.body?.toString(); | ||||||||||||||||||||||
| const { msgtype } = content; | ||||||||||||||||||||||
| const messageBody = content.body.toString(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (!messageBody && !msgtype) { | ||||||||||||||||||||||
| logger.debug('No message content found in event'); | ||||||||||||||||||||||
|
Comment on lines
+119
to
123
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible TypeError: content.body may be undefined. Guard before -const messageBody = content.body.toString();
+const messageBody = content.body != null ? String(content.body) : '';📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
@@ -152,8 +144,6 @@ export function message(emitter: Emitter<HomeserverEventSignatures>, serverName: | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| const thread = threadRootEventId ? await getThreadMessageId(threadRootEventId) : undefined; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const isMediaMessage = Object.values(fileTypes).includes(msgtype as FileMessageType); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const isEditedMessage = relation?.rel_type === 'm.replace'; | ||||||||||||||||||||||
| if (isEditedMessage && relation?.event_id && data.content['m.new_content']) { | ||||||||||||||||||||||
| logger.debug('Received edited message from Matrix, updating existing message'); | ||||||||||||||||||||||
|
|
@@ -236,8 +226,9 @@ export function message(emitter: Emitter<HomeserverEventSignatures>, serverName: | |||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (isMediaMessage && content?.url) { | ||||||||||||||||||||||
| const result = await handleMediaMessage(content, msgtype, messageBody, user, room, data.event_id, thread?.tmid); | ||||||||||||||||||||||
| const isMediaMessage = Object.values(fileTypes).includes(msgtype as FileMessageType); | ||||||||||||||||||||||
| if (isMediaMessage && content.url) { | ||||||||||||||||||||||
| const result = await handleMediaMessage(content.url, content.info, msgtype, messageBody, user, room, data.event_id, thread?.tmid); | ||||||||||||||||||||||
| await Message.saveMessageFromFederation(result); | ||||||||||||||||||||||
| } else { | ||||||||||||||||||||||
| const formatted = toInternalMessageFormat({ | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.