Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/real-zoos-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@rocket.chat/federation-matrix': patch
'@rocket.chat/meteor': patch
---

Fixes federation endpoints rejecting valid requests, which broke:

- room history backfill
- image thumbnails
- room message pagination
- accepting an invite from another homeserver
8 changes: 5 additions & 3 deletions ee/packages/federation-matrix/src/api/_matrix/client/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ const isMediaParamsProps = ajv.compile(MediaParamsSchema);
const ThumbnailQuerySchema = {
type: 'object',
properties: {
width: { oneOf: [{ type: 'number' }, { type: 'string' }] },
height: { oneOf: [{ type: 'number' }, { type: 'string' }] },
// union type lists rather than `oneOf`: ajvQuery coerces between number and string, so both
// `oneOf` branches would match a numeric value and fail validation
width: { type: ['number', 'string'] },
height: { type: ['number', 'string'] },
method: { type: 'string', enum: ['crop', 'scale'] },
timeout_ms: { oneOf: [{ type: 'number' }, { type: 'string' }] },
timeout_ms: { type: ['number', 'string'] },
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ const MessagesQuerySchema = {
from: { type: 'string' },
to: { type: 'string' },
dir: { type: 'string', enum: ['b', 'f'] },
limit: { oneOf: [{ type: 'number' }, { type: 'string' }] },
// a union type list rather than `oneOf`: ajvQuery coerces between number and string, so both
// `oneOf` branches would match a numeric value and fail validation
limit: { type: ['number', 'string'] },
filter: { type: 'string' },
},
};
Expand Down
144 changes: 21 additions & 123 deletions ee/packages/federation-matrix/src/api/_matrix/send-join.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { EventID } from '@rocket.chat/federation-sdk';
import { federationSDK } from '@rocket.chat/federation-sdk';
import { Router } from '@rocket.chat/http-router';
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
Expand Down Expand Up @@ -29,12 +28,6 @@ const TimestampSchema = {
description: 'Unix timestamp in milliseconds',
};

const DepthSchema = {
type: 'number',
minimum: 0,
description: 'Event depth',
};

const ServerNameSchema = {
type: 'string',
description: 'Matrix server name',
Expand All @@ -51,137 +44,42 @@ const SendJoinParamsSchema = {

const isSendJoinParamsProps = ajv.compile(SendJoinParamsSchema);

const EventHashSchema = {
type: 'object',
properties: {
sha256: {
type: 'string',
description: 'SHA256 hash of the event',
},
},
required: ['sha256'],
};

const EventSignatureSchema = {
type: 'object',
description: 'Event signatures by server and key ID',
};

const MembershipEventContentSchema = {
type: 'object',
properties: {
membership: {
type: 'string',
enum: ['join', 'leave', 'invite', 'ban', 'knock'],
description: 'Membership state',
},
displayname: {
type: 'string',
nullable: true,
},
avatar_url: {
type: 'string',
nullable: true,
},
join_authorised_via_users_server: {
type: 'string',
nullable: true,
},
is_direct: {
type: 'boolean',
nullable: true,
},
reason: {
type: 'string',
description: 'Reason for membership change',
nullable: true,
},
},
required: ['membership'],
};

const EventBaseSchema = {
const SendJoinEventSchema = {
type: 'object',
properties: {
type: {
type: 'string',
description: 'Event type',
},
content: {
type: 'object',
description: 'Event content',
const: 'm.room.member',
},
sender: UsernameSchema,
room_id: RoomIdSchema,
origin_server_ts: TimestampSchema,
depth: DepthSchema,
prev_events: {
type: 'array',
items: {
type: 'string',
},
description: 'Previous events in the room',
state_key: {
...UsernameSchema,
Comment thread
sampaiodiego marked this conversation as resolved.
description: 'Matrix user ID of the joining member',
},
auth_events: {
type: 'array',
items: {
type: 'string',
},
description: 'Authorization events',
sender: {
...UsernameSchema,
description: 'Matrix user ID of the joining member',
},
origin: {
type: 'string',
description: 'Origin server',
},
hashes: {
...EventHashSchema,
nullable: true,
...ServerNameSchema,
description: 'The name of the joining homeserver',
},
signatures: {
...EventSignatureSchema,
nullable: true,
},
unsigned: {
type: 'object',
description: 'Unsigned data',
nullable: true,
},
},
required: ['type', 'content', 'sender', 'room_id', 'origin_server_ts', 'depth', 'prev_events', 'auth_events', 'origin'],
};

const SendJoinEventSchema = {
type: 'object',
allOf: [
EventBaseSchema,
{
origin_server_ts: TimestampSchema,
content: {
type: 'object',
properties: {
type: {
membership: {
type: 'string',
const: 'm.room.member',
const: 'join',
},
content: {
type: 'object',
allOf: [
MembershipEventContentSchema,
{
type: 'object',
properties: {
membership: {
type: 'string',
const: 'join',
},
},
required: ['membership'],
},
],
join_authorised_via_users_server: {
...UsernameSchema,
description: 'User ID of a resident server member authorizing the join into a restricted room',
},
state_key: UsernameSchema,
},
required: ['type', 'content', 'state_key'],
required: ['membership'],
},
],
},
required: ['type', 'state_key', 'sender', 'origin', 'origin_server_ts', 'content'],
};

const isSendJoinEventProps = ajv.compile(SendJoinEventSchema);
Expand Down Expand Up @@ -235,7 +133,7 @@ export const getMatrixSendJoinRoutes = () => {
const { roomId, stateKey } = c.req.param();
const body = await c.req.json();

const response = await federationSDK.sendJoin(roomId, stateKey as EventID, body);
const response = await federationSDK.sendJoin(roomId, stateKey, body);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return {
body: response,
Expand Down
7 changes: 5 additions & 2 deletions ee/packages/federation-matrix/src/api/_matrix/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,10 @@ const BackfillQuerySchema = {
description: 'Maximum number of events to retrieve',
},
v: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
// a string branch here would be redundant: ajvQuery coerces a single `?v=` into a
// one-element array, and in a `oneOf` both branches would match and fail validation
type: 'array',
items: { type: 'string' },
description: 'Event ID(s) to backfill from',
},
},
Expand All @@ -289,7 +292,7 @@ const BackfillQuerySchema = {

const isBackfillQueryProps = ajvQuery.compile<{
limit: number;
v: string | string[];
v: string[];
}>(BackfillQuerySchema);

const BackfillResponseSchema = {
Expand Down
Loading