Skip to content

Commit 23ba66a

Browse files
authored
feat(federation): add verifyMatrixIds method and API (RocketChat#37080)
1 parent b4444e6 commit 23ba66a

3 files changed

Lines changed: 87 additions & 1 deletion

File tree

apps/meteor/ee/server/api/federation.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,51 @@
11
import type { IFederationMatrixService } from '@rocket.chat/core-services';
22
import { Logger } from '@rocket.chat/logger';
3+
import { ajv } from '@rocket.chat/rest-typings';
34
import type express from 'express';
45
import { WebApp } from 'meteor/webapp';
56

7+
import { API } from '../../../app/api/server';
68
import { isRunningMs } from '../../../server/lib/isRunningMs';
79

810
const logger = new Logger('FederationRoutes');
911

10-
export async function registerFederationRoutes(federationService: IFederationMatrixService): Promise<void> {
12+
let federationService: IFederationMatrixService | undefined;
13+
API.v1.get(
14+
'/federation/matrixIds.verify',
15+
{
16+
authRequired: true,
17+
query: ajv.compile<{
18+
matrixIds: string[];
19+
}>({
20+
type: 'object',
21+
properties: {
22+
matrixIds: { type: 'array', items: { type: 'string' } },
23+
},
24+
}),
25+
response: {
26+
200: ajv.compile<{
27+
results: { [key: string]: string };
28+
}>({
29+
type: 'object',
30+
properties: {
31+
results: { type: 'object', additionalProperties: { type: 'string' } },
32+
},
33+
}),
34+
},
35+
},
36+
async function () {
37+
const { matrixIds } = this.queryParams;
38+
if (!federationService) {
39+
throw new Error('Federation service not registered');
40+
}
41+
return API.v1.success({
42+
results: await federationService.verifyMatrixIds(matrixIds),
43+
});
44+
},
45+
);
46+
47+
export async function registerFederationRoutes(f: IFederationMatrixService): Promise<void> {
48+
federationService = f;
1149
if (isRunningMs()) {
1250
return;
1351
}

ee/packages/federation-matrix/src/FederationMatrix.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,4 +944,51 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS
944944

945945
void this.homeserverServices.edu.sendTypingNotification(room.federation.mrid, userMui, isTyping);
946946
}
947+
948+
async verifyMatrixIds(matrixIds: string[]): Promise<{ [key: string]: string }> {
949+
const results = Object.fromEntries(
950+
await Promise.all(
951+
matrixIds.map(async (matrixId) => {
952+
// Split only on the first ':' (after the leading '@') so we keep any port in the homeserver
953+
const separatorIndex = matrixId.indexOf(':', 1);
954+
if (separatorIndex === -1) {
955+
return [matrixId, 'UNABLE_TO_VERIFY'];
956+
}
957+
const userId = matrixId.slice(0, separatorIndex);
958+
const homeserverUrl = matrixId.slice(separatorIndex + 1);
959+
960+
if (homeserverUrl === this.serverName) {
961+
const user = await Users.findOneByUsername(userId.slice(1));
962+
return [matrixId, user ? 'VERIFIED' : 'UNVERIFIED'];
963+
}
964+
965+
if (!homeserverUrl) {
966+
return [matrixId, 'UNABLE_TO_VERIFY'];
967+
}
968+
try {
969+
const result = await this.homeserverServices.request.get<
970+
| {
971+
avatar_url: string;
972+
displayname: string;
973+
}
974+
| {
975+
errcode: string;
976+
error: string;
977+
}
978+
>(homeserverUrl, `/_matrix/federation/v1/query/profile`, { user_id: matrixId });
979+
980+
if ('errcode' in result && result.errcode === 'M_NOT_FOUND') {
981+
return [matrixId, 'UNVERIFIED'];
982+
}
983+
984+
return [matrixId, 'VERIFIED'];
985+
} catch (e) {
986+
return [matrixId, 'UNABLE_TO_VERIFY'];
987+
}
988+
}),
989+
),
990+
);
991+
992+
return results;
993+
}
947994
}

packages/core-services/src/types/IFederationMatrixService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ export interface IFederationMatrixService {
2727
): Promise<void>;
2828
inviteUsersToRoom(room: IRoomFederated, usersUserName: string[], inviter: IUser): Promise<void>;
2929
notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void>;
30+
verifyMatrixIds(matrixIds: string[]): Promise<{ [key: string]: string }>;
3031
}

0 commit comments

Comments
 (0)