Skip to content

Commit f44030f

Browse files
ricardogarimsampaiodiegoggazzo
authored
refactor(federation): add isAuthenticated and canAccessResource middlewares (#37067)
Co-authored-by: Diego Sampaio <chinello@gmail.com> Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz>
1 parent fbbcf2a commit f44030f

File tree

12 files changed

+213
-156
lines changed

12 files changed

+213
-156
lines changed

ee/packages/federation-matrix/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"@rocket.chat/core-services": "workspace:^",
3939
"@rocket.chat/core-typings": "workspace:^",
4040
"@rocket.chat/emitter": "^0.31.25",
41-
"@rocket.chat/federation-sdk": "0.1.23",
41+
"@rocket.chat/federation-sdk": "0.1.25",
4242
"@rocket.chat/http-router": "workspace:^",
4343
"@rocket.chat/license": "workspace:^",
4444
"@rocket.chat/models": "workspace:^",

ee/packages/federation-matrix/src/api/_matrix/invite.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Rooms, Users } from '@rocket.chat/models';
1414
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
1515

1616
import { createOrUpdateFederatedUser, getUsernameServername } from '../../FederationMatrix';
17+
import { isAuthenticatedMiddleware } from '../middlewares/isAuthenticated';
1718

1819
const EventBaseSchema = {
1920
type: 'object',
@@ -181,7 +182,7 @@ async function joinRoom({
181182
const isDM = inviteEvent.getContent<PduMembershipEventContent>().is_direct;
182183

183184
if (!isDM && !matrixRoom.isPublic() && !matrixRoom.isInviteOnly()) {
184-
throw new Error('room is neither public, private, nor direct message - rocketchat is unable to join for now');
185+
throw new Error('room is neither direct message - rocketchat is unable to join for now');
185186
}
186187

187188
// need both the sender and the participating user to exist in the room
@@ -320,7 +321,7 @@ export const acceptInvite = async (
320321
};
321322

322323
export const getMatrixInviteRoutes = (services: HomeserverServices) => {
323-
const { invite, state, room } = services;
324+
const { invite, state, room, federationAuth } = services;
324325

325326
return new Router('/federation').put(
326327
'/v2/invite/:roomId/:eventId',
@@ -333,6 +334,7 @@ export const getMatrixInviteRoutes = (services: HomeserverServices) => {
333334
tags: ['Federation'],
334335
license: ['federation'],
335336
},
337+
isAuthenticatedMiddleware(federationAuth),
336338
async (c) => {
337339
const { roomId, eventId } = c.req.param();
338340
const { event, room_version: roomVersion } = await c.req.json();
@@ -353,7 +355,13 @@ export const getMatrixInviteRoutes = (services: HomeserverServices) => {
353355
throw new Error('user not found not processing invite');
354356
}
355357

356-
const inviteEvent = await invite.processInvite(event, roomIdSchema.parse(roomId), eventIdSchema.parse(eventId), roomVersion);
358+
const inviteEvent = await invite.processInvite(
359+
event,
360+
roomIdSchema.parse(roomId),
361+
eventIdSchema.parse(eventId),
362+
roomVersion,
363+
c.get('authenticatedServer'),
364+
);
357365

358366
setTimeout(
359367
() => {

ee/packages/federation-matrix/src/api/_matrix/media.ts

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Router } from '@rocket.chat/http-router';
66
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
77

88
import { MatrixMediaService } from '../../services/MatrixMediaService';
9-
import { canAccessMedia } from '../middlewares';
9+
import { canAccessResourceMiddleware } from '../middlewares/canAccessResource';
1010

1111
const MediaDownloadParamsSchema = {
1212
type: 'object',
@@ -75,79 +75,76 @@ async function getMediaFile(mediaId: string, serverName: string): Promise<{ file
7575

7676
export const getMatrixMediaRoutes = (homeserverServices: HomeserverServices) => {
7777
const { config, federationAuth } = homeserverServices;
78-
const router = new Router('/federation');
79-
80-
router.get(
81-
'/v1/media/download/:mediaId',
82-
{
83-
params: isMediaDownloadParamsProps,
84-
response: {
85-
200: isBufferResponseProps,
86-
401: isErrorResponseProps,
87-
403: isErrorResponseProps,
88-
404: isErrorResponseProps,
89-
429: isErrorResponseProps,
90-
500: isErrorResponseProps,
78+
return new Router('/federation')
79+
.get(
80+
'/v1/media/download/:mediaId',
81+
{
82+
params: isMediaDownloadParamsProps,
83+
response: {
84+
200: isBufferResponseProps,
85+
401: isErrorResponseProps,
86+
403: isErrorResponseProps,
87+
404: isErrorResponseProps,
88+
429: isErrorResponseProps,
89+
500: isErrorResponseProps,
90+
},
91+
tags: ['Federation', 'Media'],
9192
},
92-
tags: ['Federation', 'Media'],
93-
},
94-
canAccessMedia(federationAuth),
95-
async (c) => {
96-
try {
97-
const { mediaId } = c.req.param();
98-
const { serverName } = config;
99-
100-
// TODO: Add file streaming support
101-
const result = await getMediaFile(mediaId, serverName);
102-
if (!result) {
93+
canAccessResourceMiddleware(federationAuth, 'media'),
94+
async (c) => {
95+
try {
96+
const { mediaId } = c.req.param();
97+
const { serverName } = config;
98+
99+
// TODO: Add file streaming support
100+
const result = await getMediaFile(mediaId, serverName);
101+
if (!result) {
102+
return {
103+
statusCode: 404,
104+
body: { errcode: 'M_NOT_FOUND', error: 'Media not found' },
105+
};
106+
}
107+
108+
const { file, buffer } = result;
109+
110+
const mimeType = file.type || 'application/octet-stream';
111+
const fileName = file.name || mediaId;
112+
113+
const multipartResponse = createMultipartResponse(buffer, mimeType, fileName);
114+
103115
return {
104-
statusCode: 404,
105-
body: { errcode: 'M_NOT_FOUND', error: 'Media not found' },
116+
statusCode: 200,
117+
headers: {
118+
...SECURITY_HEADERS,
119+
'content-type': multipartResponse.contentType,
120+
'content-length': String(multipartResponse.body.length),
121+
},
122+
body: multipartResponse.body,
123+
};
124+
} catch (error) {
125+
return {
126+
statusCode: 500,
127+
body: { errcode: 'M_UNKNOWN', error: 'Internal server error' },
106128
};
107129
}
108-
109-
const { file, buffer } = result;
110-
111-
const mimeType = file.type || 'application/octet-stream';
112-
const fileName = file.name || mediaId;
113-
114-
const multipartResponse = createMultipartResponse(buffer, mimeType, fileName);
115-
116-
return {
117-
statusCode: 200,
118-
headers: {
119-
...SECURITY_HEADERS,
120-
'content-type': multipartResponse.contentType,
121-
'content-length': String(multipartResponse.body.length),
122-
},
123-
body: multipartResponse.body,
124-
};
125-
} catch (error) {
126-
return {
127-
statusCode: 500,
128-
body: { errcode: 'M_UNKNOWN', error: 'Internal server error' },
129-
};
130-
}
131-
},
132-
);
133-
134-
router.get(
135-
'/v1/media/thumbnail/:mediaId',
136-
{
137-
params: isMediaDownloadParamsProps,
138-
response: {
139-
404: isErrorResponseProps,
140130
},
141-
tags: ['Federation', 'Media'],
142-
},
143-
async () => ({
144-
statusCode: 404,
145-
body: {
146-
errcode: 'M_UNRECOGNIZED',
147-
error: 'This endpoint is not implemented on the homeserver side',
131+
)
132+
.get(
133+
'/v1/media/thumbnail/:mediaId',
134+
{
135+
params: isMediaDownloadParamsProps,
136+
response: {
137+
404: isErrorResponseProps,
138+
},
139+
tags: ['Federation', 'Media'],
148140
},
149-
}),
150-
);
151-
152-
return router;
141+
canAccessResourceMiddleware(federationAuth, 'media'),
142+
async (_c) => ({
143+
statusCode: 404,
144+
body: {
145+
errcode: 'M_UNRECOGNIZED',
146+
error: 'This endpoint is not implemented on the homeserver side',
147+
},
148+
}),
149+
);
153150
};

ee/packages/federation-matrix/src/api/_matrix/profiles.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { eventIdSchema, roomIdSchema, userIdSchema, type HomeserverServices, typ
22
import { Router } from '@rocket.chat/http-router';
33
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
44

5+
import { canAccessResourceMiddleware } from '../middlewares/canAccessResource';
6+
import { isAuthenticatedMiddleware } from '../middlewares/isAuthenticated';
7+
58
const UsernameSchema = {
69
type: 'string',
710
pattern: '^@[A-Za-z0-9_=\\/.+-]+:(.+)$',
@@ -350,9 +353,10 @@ const EventAuthResponseSchema = {
350353
const isEventAuthResponseProps = ajv.compile(EventAuthResponseSchema);
351354

352355
export const getMatrixProfilesRoutes = (services: HomeserverServices) => {
353-
const { profile } = services;
356+
const { profile, federationAuth } = services;
354357

355358
return new Router('/federation')
359+
.use(isAuthenticatedMiddleware(federationAuth))
356360
.get(
357361
'/v1/query/profile',
358362
{
@@ -414,14 +418,13 @@ export const getMatrixProfilesRoutes = (services: HomeserverServices) => {
414418
tags: ['Federation'],
415419
license: ['federation'],
416420
},
417-
async (c) => {
418-
const { userId } = c.req.param();
419-
420-
const response = await profile.getDevices(userId);
421-
421+
async (_c) => {
422422
return {
423-
body: response,
424-
statusCode: 200,
423+
body: {
424+
errcode: 'M_UNRECOGNIZED',
425+
error: 'This endpoint is not implemented on the homeserver side',
426+
},
427+
statusCode: 501,
425428
};
426429
},
427430
)
@@ -436,6 +439,7 @@ export const getMatrixProfilesRoutes = (services: HomeserverServices) => {
436439
tags: ['Federation'],
437440
license: ['federation'],
438441
},
442+
canAccessResourceMiddleware(federationAuth, 'room'),
439443
async (c) => {
440444
const { roomId, userId } = c.req.param();
441445
const url = new URL(c.req.url);
@@ -467,6 +471,7 @@ export const getMatrixProfilesRoutes = (services: HomeserverServices) => {
467471
tags: ['Federation'],
468472
license: ['federation'],
469473
},
474+
canAccessResourceMiddleware(federationAuth, 'room'),
470475
async (c) => {
471476
const { roomId } = c.req.param();
472477
const body = await c.req.json();
@@ -489,6 +494,7 @@ export const getMatrixProfilesRoutes = (services: HomeserverServices) => {
489494
tags: ['Federation'],
490495
license: ['federation'],
491496
},
497+
canAccessResourceMiddleware(federationAuth, 'room'),
492498
async (c) => {
493499
const { roomId, eventId } = c.req.param();
494500

ee/packages/federation-matrix/src/api/_matrix/rooms.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { HomeserverServices } from '@rocket.chat/federation-sdk';
22
import { Router } from '@rocket.chat/http-router';
33
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
44

5+
import { isAuthenticatedMiddleware } from '../middlewares/isAuthenticated';
6+
57
const PublicRoomsQuerySchema = {
68
type: 'object',
79
properties: {
@@ -122,9 +124,10 @@ const PublicRoomsPostBodySchema = {
122124
const isPublicRoomsPostBodyProps = ajv.compile(PublicRoomsPostBodySchema);
123125

124126
export const getMatrixRoomsRoutes = (services: HomeserverServices) => {
125-
const { state } = services;
127+
const { state, federationAuth } = services;
126128

127129
return new Router('/federation')
130+
.use(isAuthenticatedMiddleware(federationAuth))
128131
.get(
129132
'/v1/publicRooms',
130133
{

ee/packages/federation-matrix/src/api/_matrix/send-join.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { HomeserverServices, EventID } from '@rocket.chat/federation-sdk';
22
import { Router } from '@rocket.chat/http-router';
33
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
44

5+
import { canAccessResourceMiddleware } from '../middlewares/canAccessResource';
6+
57
const UsernameSchema = {
68
type: 'string',
79
pattern: '^@[A-Za-z0-9_=\\/.+-]+:(.+)$',
@@ -222,7 +224,7 @@ const SendJoinResponseSchema = {
222224
const isSendJoinResponseProps = ajv.compile(SendJoinResponseSchema);
223225

224226
export const getMatrixSendJoinRoutes = (services: HomeserverServices) => {
225-
const { sendJoin } = services;
227+
const { sendJoin, federationAuth } = services;
226228

227229
return new Router('/federation').put(
228230
'/v2/send_join/:roomId/:stateKey',
@@ -235,6 +237,7 @@ export const getMatrixSendJoinRoutes = (services: HomeserverServices) => {
235237
tags: ['Federation'],
236238
license: ['federation'],
237239
},
240+
canAccessResourceMiddleware(federationAuth, 'room'),
238241
async (c) => {
239242
const { roomId, stateKey } = c.req.param();
240243
const body = await c.req.json();

ee/packages/federation-matrix/src/api/_matrix/transactions.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import type { HomeserverServices, EventID } from '@rocket.chat/federation-sdk';
22
import { Router } from '@rocket.chat/http-router';
33
import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv';
44

5-
import { canAccessEvent } from '../middlewares';
5+
import { canAccessResourceMiddleware } from '../middlewares/canAccessResource';
6+
import { isAuthenticatedMiddleware } from '../middlewares/isAuthenticated';
67

78
const SendTransactionParamsSchema = {
89
type: 'object',
@@ -319,6 +320,7 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
319320
// PUT /_matrix/federation/v1/send/{txnId}
320321
return (
321322
new Router('/federation')
323+
.use(isAuthenticatedMiddleware(federationAuth))
322324
.put(
323325
'/v1/send/:txnId',
324326
{
@@ -365,7 +367,6 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
365367
)
366368

367369
// GET /_matrix/federation/v1/state_ids/{roomId}
368-
369370
.get(
370371
'/v1/state_ids/:roomId',
371372
{
@@ -374,6 +375,7 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
374375
200: isGetStateIdsResponseProps,
375376
},
376377
},
378+
canAccessResourceMiddleware(federationAuth, 'room'),
377379
async (c) => {
378380
const roomId = c.req.param('roomId');
379381
const eventId = c.req.query('event_id');
@@ -404,6 +406,7 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
404406
200: isGetStateResponseProps,
405407
},
406408
},
409+
canAccessResourceMiddleware(federationAuth, 'room'),
407410
async (c) => {
408411
const roomId = c.req.param('roomId');
409412
const eventId = c.req.query('event_id');
@@ -435,7 +438,7 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
435438
tags: ['Federation'],
436439
license: ['federation'],
437440
},
438-
canAccessEvent(federationAuth),
441+
canAccessResourceMiddleware(federationAuth, 'event'),
439442
async (c) => {
440443
const eventData = await event.getEventById(c.req.param('eventId') as EventID);
441444
if (!eventData) {
@@ -470,6 +473,7 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => {
470473
tags: ['Federation'],
471474
license: ['federation'],
472475
},
476+
canAccessResourceMiddleware(federationAuth, 'room'),
473477
async (c) => {
474478
const roomId = c.req.param('roomId');
475479
const limit = Number(c.req.query('limit') || 100);

0 commit comments

Comments
 (0)