Skip to content
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

[NEW] Alpha Matrix Federation #23688

Merged
merged 22 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
89ee547
POC - initial commit
alansikora Mar 30, 2022
2bc0237
POC - initial commit
alansikora Mar 30, 2022
d9f46ac
adding settings/better names
alansikora Apr 1, 2022
63e6965
a few patches to get it working
geekgonecrazy Apr 4, 2022
1cc4219
importing settings
alansikora Apr 6, 2022
ffd9fce
fixing automatic generation for yaml file
alansikora Apr 6, 2022
ea8d9a1
Some changes to the user creation flow to better support remote and
geekgonecrazy Apr 6, 2022
0eedbea
fixing config
alansikora Apr 7, 2022
2fc10e1
fix: fix wrong reference
MarcosSpessatto Apr 7, 2022
cb9801b
fix: fix prettier and lint
MarcosSpessatto Apr 7, 2022
5ee790b
better bridge setup
alansikora Apr 12, 2022
5d0a0ec
Merge branch 'develop' into feature/federation-v2
geekgonecrazy Apr 20, 2022
872f07e
clarify comment
geekgonecrazy Apr 20, 2022
4210300
revised yarn lock with the matrix-bridge dependency
geekgonecrazy Apr 21, 2022
49feb37
Fix typescript issues. Rename settings. Move to Federation section. A…
geekgonecrazy Apr 21, 2022
ee82669
Fix remaining linting errors
geekgonecrazy Apr 21, 2022
5aabad2
fix slashcommand definition for ts typescript check
geekgonecrazy Apr 21, 2022
8d07ef7
Merge branch 'develop' into feature/federation-v2
geekgonecrazy Apr 21, 2022
302e176
add migration to put settings into the Rocket.Chat Federation section
geekgonecrazy Apr 21, 2022
dbab8ab
remove migration. Its not needed
geekgonecrazy Apr 21, 2022
bad68f1
Remove unneeded Meteor.startup wrappers for settings registration
rodrigok Apr 21, 2022
109b443
Merge branch 'feature/federation-v2' of https://github.com/RocketChat…
rodrigok Apr 21, 2022
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
63 changes: 0 additions & 63 deletions app/federation-matrix/server/bridge.ts

This file was deleted.

10 changes: 0 additions & 10 deletions app/federation-matrix/server/config.ts

This file was deleted.

3 changes: 0 additions & 3 deletions app/federation-matrix/server/index.ts

This file was deleted.

72 changes: 72 additions & 0 deletions app/federation-v2/server/bridge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Bridge, AppServiceRegistration } from 'matrix-appservice-bridge';

import { IMatrixEvent } from './definitions/IMatrixEvent';
import { MatrixEventType } from './definitions/MatrixEventType';
import { addToQueue } from './queue';
import { isFederationV2Enabled } from './tools';
import { settings } from '../../settings/server';

let bridge;

((): void => {
if (!isFederationV2Enabled()) return;

/* eslint-disable @typescript-eslint/camelcase */
const registrationConfig = AppServiceRegistration.fromObject({
id: settings.get('FederationV2_id') as string,
hs_token: settings.get('FederationV2_hs_token') as string,
as_token: settings.get('FederationV2_as_token') as string,
url: settings.get('FederationV2_bridge_url') as string,
sender_localpart: settings.get('FederationV2_bridge_localpart') as string,
namespaces: {
users: [
{
exclusive: false,
// Reserve these MXID's (usernames)
regex: `.*`,
},
],
aliases: [
{
exclusive: false,
// Reserve these room aliases
regex: `.*`,
},
],
rooms: [
{
exclusive: false,
// This regex is used to define which rooms we listen to with the bridge.
// This does not reserve the rooms like the other namespaces.
regex: '.*',
},
],
},
rate_limited: false,
protocols: null,
});
/* eslint-enable @typescript-eslint/camelcase */

bridge = new Bridge({
homeserverUrl: settings.get('FederationV2_homeserver_url') as string,
alansikora marked this conversation as resolved.
Show resolved Hide resolved
domain: settings.get('FederationV2_homeserver_domain') as string,
registration: registrationConfig,
disableStores: true,
controller: {
onAliasQuery: (alias, matrixRoomId): void => {
console.log('onAliasQuery', alias, matrixRoomId);
},
onEvent: async (request /* , context*/): Promise<void> => {
// Get the event
const event = request.getData() as unknown as IMatrixEvent<MatrixEventType>;

addToQueue(event);
},
onLog: async (line, isError): Promise<void> => {
console.log(line, isError);
},
},
});
})();

export const matrixBridge = bridge;
24 changes: 24 additions & 0 deletions app/federation-v2/server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { settings } from '../../settings/server';

type bridgeUrlString = `${string}:${string}`;
export type bridgeUrlTuple = [string, number];

interface IBridgeConfig {
id: string;
hsToken: string;
asToken: string;
homeserverUrl: string;
homeserverDomain: string;
bridgeUrl: bridgeUrlString;
bridgeLocalpart: string;
}

export const config: IBridgeConfig = {
id: settings.get('FederationV2_id') as string,
hsToken: settings.get('FederationV2_hs_token') as string,
asToken: settings.get('FederationV2_as_token') as string,
homeserverUrl: settings.get('FederationV2_homeserver_url') as string,
homeserverDomain: settings.get('FederationV2_homeserver_domain') as string,
bridgeUrl: settings.get('FederationV2_bridge_url') as bridgeUrlString,
bridgeLocalpart: settings.get('FederationV2_bridge_localpart') as string,
};
18 changes: 18 additions & 0 deletions app/federation-v2/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { matrixBridge } from './bridge';
import { bridgeUrlTuple, config } from './config';
import { bridgeLogger } from './logger';

((): void => {
if (!matrixBridge) return;

bridgeLogger.info(`Running Federation V2:
id: ${config.id}
bridgeUrl: ${config.bridgeUrl}
homeserverURL: ${config.homeserverUrl}
homeserverDomain: ${config.homeserverDomain}
`);

const [, port] = config.bridgeUrl.split(':') as bridgeUrlTuple;

matrixBridge?.run(port);
})();
6 changes: 6 additions & 0 deletions app/federation-v2/server/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Logger } from '../../logger/server';

const logger = new Logger('FederationV2');

export const bridgeLogger = logger.section('bridge');
export const setupLogger = logger.section('setup');
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,5 @@ export const create = async (user: IUser, room: IRoom): Promise<ICreateRoomResul
// Add to the map
MatrixBridgedRoom.insert({ rid: room._id, mri: matrixRoom.room_id });

// Add our user
await intent.invite(matrixRoom.room_id, userMatrixId);

return { rid: room._id, mri: matrixRoom.room_id };
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { MatrixProfileInfo } from 'matrix-bot-sdk';
import { IUser } from '../../../../definition/IUser';
import { matrixBridge } from '../bridge';
import { MatrixBridgedUser, MatrixBridgedRoom, Users } from '../../../models/server';
import { config } from '../config';
import { getConfig } from '../config';
import { matrixClient } from '.';
import { dataInterface } from '../data-interface';

Expand Down Expand Up @@ -48,10 +48,13 @@ export const invite = async (inviterId: string, roomId: string, invitedId: strin
console.log(`[${inviterId}-${invitedId}-${roomId}] Inviter user created as ${inviterUser.mui}...`);
}

// Normalize the user situation
// If the user does not exist locally, we might need to create one

// Determine if the user is local or remote
let invitedUserMatrixId = invitedId;
const invitedUserDomain = invitedId.includes(':') ? invitedId.split(':').pop() : '';
const invitedUserIsRemote = invitedUserDomain && invitedUserDomain !== config.serverDomain;
const invitedUserIsRemote = invitedUserDomain && invitedUserDomain !== getConfig().homeserverDomain;

console.log(invitedUserMatrixId, invitedUserDomain, invitedUserIsRemote);

Expand Down Expand Up @@ -90,7 +93,7 @@ export const invite = async (inviterId: string, roomId: string, invitedId: strin
};

export const createRemote = async (u: IUser): Promise<ICreateUserResult> => {
const matrixUserId = `@${u.username?.toLowerCase()}:${config.serverDomain}`;
const matrixUserId = `@${u.username?.toLowerCase()}:${getConfig().homeserverDomain}`;

console.log(`Creating remote user ${matrixUserId}...`);

Expand Down
129 changes: 129 additions & 0 deletions app/federation-v2/server/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import yaml from 'js-yaml';
import { Meteor } from 'meteor/meteor';
import { SHA256 } from 'meteor/sha';

import { settings, settingsRegistry } from '../../settings/server';
import { Settings } from '../../models/server/raw';
import { setupLogger } from './logger';

Meteor.startup(async function () {
const uniqueId = await settings.get('uniqueID');
const hsToken = SHA256(`hs_${uniqueId}`);
const asToken = SHA256(`as_${uniqueId}`);

settingsRegistry.addGroup('FederationV2', function () {
this.add('FederationV2_enabled', false, {
readonly: false,
type: 'boolean',
i18nLabel: 'FederationV2_enabled',
i18nDescription: 'FederationV2_enabled_desc',
});

this.add('FederationV2_id', `rocketchat_${uniqueId}`, {
readonly: true,
type: 'string',
i18nLabel: 'FederationV2_id',
i18nDescription: 'FederationV2_id_desc',
});

this.add('FederationV2_hs_token', hsToken, {
readonly: true,
type: 'string',
i18nLabel: 'FederationV2_hs_token',
i18nDescription: 'FederationV2_hs_token_desc',
});

this.add('FederationV2_as_token', asToken, {
readonly: true,
type: 'string',
i18nLabel: 'FederationV2_as_token',
i18nDescription: 'FederationV2_as_token_desc',
});

this.add('FederationV2_homeserver_url', 'http://localhost:8008', {
type: 'string',
i18nLabel: 'FederationV2_homeserver_url',
i18nDescription: 'FederationV2_homeserver_url_desc',
});

this.add('FederationV2_homeserver_domain', 'local.rocket.chat', {
type: 'string',
i18nLabel: 'FederationV2_homeserver_domain',
i18nDescription: 'FederationV2_homeserver_domain_desc',
});

this.add('FederationV2_bridge_url', 'http://host.docker.internal:3300', {
type: 'string',
i18nLabel: 'FederationV2_bridge_url',
i18nDescription: 'FederationV2_bridge_url_desc',
});

this.add('FederationV2_bridge_localpart', 'rocket.cat', {
type: 'string',
i18nLabel: 'FederationV2_bridge_localpart',
i18nDescription: 'FederationV2_bridge_localpart_desc',
});

this.add('FederationV2_registration_file', '', {
readonly: true,
type: 'code',
i18nLabel: 'FederationV2_registration_file',
i18nDescription: 'FederationV2_registration_file_desc',
});
});
});

let registrationFile = {};

const updateRegistrationFile = async function (): Promise<void> {
let bridgeUrl = (await Settings.getValueById('FederationV2_bridge_url')) as string;

if (!bridgeUrl.includes(':')) {
bridgeUrl = `${bridgeUrl}:3300`;
}

/* eslint-disable @typescript-eslint/camelcase */
registrationFile = {
id: await Settings.getValueById('FederationV2_id'),
hs_token: await Settings.getValueById('FederationV2_hs_token'),
as_token: await Settings.getValueById('FederationV2_as_token'),
url: bridgeUrl,
sender_localpart: await Settings.getValueById('FederationV2_bridge_localpart'),
namespaces: {
users: {
exclusive: false,
regex: '.*',
},
rooms: {
exclusive: false,
regex: '.*',
},
aliases: {
exclusive: false,
regex: '.*',
},
},
};
/* eslint-enable @typescript-eslint/camelcase */

// Update the registration file
await Settings.updateValueById('FederationV2_registration_file', yaml.dump(registrationFile));
};

// Add settings listeners
settings.watch('FederationV2_enabled', (value) => {
setupLogger.info(`Federation V2 is ${value ? 'enabled' : 'disabled'}`);
});

settings.watchMultiple(
[
'FederationV2_id',
'FederationV2_hs_token',
'FederationV2_as_token',
'FederationV2_homeserver_url',
'FederationV2_homeserver_domain',
'FederationV2_bridge_url',
'FederationV2_bridge_localpart',
],
updateRegistrationFile,
);
3 changes: 3 additions & 0 deletions app/federation-v2/server/tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { settings } from '../../settings/server';

export const isFederationV2Enabled = () => settings.get('FederationV2_enabled');
2 changes: 1 addition & 1 deletion app/lib/server/methods/sendMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { RateLimiter } from '../lib';
import { canSendMessage } from '../../../authorization/server';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { api } from '../../../../server/sdk/api';
import { matrixClient } from '../../../federation-matrix/server/matrix-client';
import { matrixClient } from '../../../federation-v2/server/matrix-client';

export function executeSendMessage(uid, message) {
if (message.tshow && !message.tmid) {
Expand Down
2 changes: 1 addition & 1 deletion app/slashcommands-bridge/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Match } from 'meteor/check';

import { slashCommands } from '../../utils/lib/slashCommand';
import { matrixClient } from '../../federation-matrix/server/matrix-client';
import { matrixClient } from '../../federation-v2/server/matrix-client';

function Bridge(_command: 'bridge', stringParams: string, item: Record<string, string>): void {
if (_command !== 'bridge' || !Match.test(stringParams, String)) {
Expand Down
Loading