feat(federation): add verifyMatrixIds method and API (#37080)

pull/36973/head
Guilherme Gazzo 3 months ago committed by GitHub
parent b4444e6d06
commit 23ba66ae81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 40
      apps/meteor/ee/server/api/federation.ts
  2. 47
      ee/packages/federation-matrix/src/FederationMatrix.ts
  3. 1
      packages/core-services/src/types/IFederationMatrixService.ts

@ -1,13 +1,51 @@
import type { IFederationMatrixService } from '@rocket.chat/core-services';
import { Logger } from '@rocket.chat/logger';
import { ajv } from '@rocket.chat/rest-typings';
import type express from 'express';
import { WebApp } from 'meteor/webapp';
import { API } from '../../../app/api/server';
import { isRunningMs } from '../../../server/lib/isRunningMs';
const logger = new Logger('FederationRoutes');
export async function registerFederationRoutes(federationService: IFederationMatrixService): Promise<void> {
let federationService: IFederationMatrixService | undefined;
API.v1.get(
'/federation/matrixIds.verify',
{
authRequired: true,
query: ajv.compile<{
matrixIds: string[];
}>({
type: 'object',
properties: {
matrixIds: { type: 'array', items: { type: 'string' } },
},
}),
response: {
200: ajv.compile<{
results: { [key: string]: string };
}>({
type: 'object',
properties: {
results: { type: 'object', additionalProperties: { type: 'string' } },
},
}),
},
},
async function () {
const { matrixIds } = this.queryParams;
if (!federationService) {
throw new Error('Federation service not registered');
}
return API.v1.success({
results: await federationService.verifyMatrixIds(matrixIds),
});
},
);
export async function registerFederationRoutes(f: IFederationMatrixService): Promise<void> {
federationService = f;
if (isRunningMs()) {
return;
}

@ -944,4 +944,51 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS
void this.homeserverServices.edu.sendTypingNotification(room.federation.mrid, userMui, isTyping);
}
async verifyMatrixIds(matrixIds: string[]): Promise<{ [key: string]: string }> {
const results = Object.fromEntries(
await Promise.all(
matrixIds.map(async (matrixId) => {
// Split only on the first ':' (after the leading '@') so we keep any port in the homeserver
const separatorIndex = matrixId.indexOf(':', 1);
if (separatorIndex === -1) {
return [matrixId, 'UNABLE_TO_VERIFY'];
}
const userId = matrixId.slice(0, separatorIndex);
const homeserverUrl = matrixId.slice(separatorIndex + 1);
if (homeserverUrl === this.serverName) {
const user = await Users.findOneByUsername(userId.slice(1));
return [matrixId, user ? 'VERIFIED' : 'UNVERIFIED'];
}
if (!homeserverUrl) {
return [matrixId, 'UNABLE_TO_VERIFY'];
}
try {
const result = await this.homeserverServices.request.get<
| {
avatar_url: string;
displayname: string;
}
| {
errcode: string;
error: string;
}
>(homeserverUrl, `/_matrix/federation/v1/query/profile`, { user_id: matrixId });
if ('errcode' in result && result.errcode === 'M_NOT_FOUND') {
return [matrixId, 'UNVERIFIED'];
}
return [matrixId, 'VERIFIED'];
} catch (e) {
return [matrixId, 'UNABLE_TO_VERIFY'];
}
}),
),
);
return results;
}
}

@ -27,4 +27,5 @@ export interface IFederationMatrixService {
): Promise<void>;
inviteUsersToRoom(room: IRoomFederated, usersUserName: string[], inviter: IUser): Promise<void>;
notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void>;
verifyMatrixIds(matrixIds: string[]): Promise<{ [key: string]: string }>;
}

Loading…
Cancel
Save