Skip to content

Commit

Permalink
Merge pull request #32016 from RocketChat/release-6.6.4
Browse files Browse the repository at this point in the history
Release 6.6.4
  • Loading branch information
sampaiodiego authored Mar 19, 2024
2 parents 6098bc5 + 28b59b5 commit 65d59ea
Show file tree
Hide file tree
Showing 19 changed files with 132 additions and 114 deletions.
5 changes: 5 additions & 0 deletions .changeset/bump-patch-1710772454766.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Bump @rocket.chat/meteor version.
5 changes: 5 additions & 0 deletions .changeset/cyan-countries-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixed matrix homeserver domain setting not being visible in admin panel
5 changes: 5 additions & 0 deletions .changeset/moody-ghosts-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Don't use the registration.yaml file to configure Matrix Federation anymore.
6 changes: 6 additions & 0 deletions .changeset/slimy-clocks-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/core-services": patch
---

`stopped` lifecycle method was unexpectedly synchronous when using microservices, causing our code to create race conditions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ yarn-error.log*
.envrc

*.sublime-workspace

**/.vim/
4 changes: 2 additions & 2 deletions apps/meteor/app/search/server/search.internalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ class Search extends ServiceClassInternal {

const service = new Search();

settings.watch('Search.Provider', () => {
settings.watch('Search.Provider', async () => {
if (searchProviderService.activeProvider?.on) {
api.registerService(service);
} else {
api.destroyService(service);
await api.destroyService(service);
}
});
4 changes: 2 additions & 2 deletions apps/meteor/ee/server/NetworkBroker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ export class NetworkBroker implements IBroker {
return this.broker.call(method, data);
}

destroyService(instance: IServiceClass): void {
async destroyService(instance: IServiceClass): Promise<void> {
const name = instance.getName();
if (!name) {
return;
}
void this.broker.destroyService(name);
await this.broker.destroyService(name);
instance.removeAllListeners();
}

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/ee/server/startup/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ if (!License.hasValidLicense()) {
void License.onLicense('federation', async () => {
const federationServiceEE = await FederationServiceEE.createFederationService();
if (federationService) {
api.destroyService(federationService);
await api.destroyService(federationService);
}
api.registerService(federationServiceEE);
});
39 changes: 39 additions & 0 deletions apps/meteor/ee/tests/unit/server/NetworkBroker.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ServiceClass } from '@rocket.chat/core-services';
import { expect } from 'chai';
import sinon from 'sinon';

import { BrokerMocked } from '../../../../tests/mocks/server/BrokerMocked';
import { NetworkBroker } from '../../../server/NetworkBroker';

class DelayedStopBroker extends BrokerMocked {
async destroyService(name: string) {
const instance = this.services.get(name);

await new Promise((resolve) => setTimeout(resolve, 1000));

await instance.stopped();

await super.destroyService(name);
}
}

const broker = new NetworkBroker(new DelayedStopBroker() as any);

describe('NetworkBroker', () => {
it('should wait services to be fully destroyed', async () => {
const stoppedStub = sinon.stub();

const instance = new (class extends ServiceClass {
name = 'test';

async stopped() {
stoppedStub();
}
})();

broker.createService(instance);
await broker.destroyService(instance);

expect(stoppedStub.called).to.be.true;
});
});
2 changes: 2 additions & 0 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,8 @@
"Federation_Description": "Federation allows an unlimited number of workspaces to communicate with each other.",
"Federation_Enable": "Enable Federation",
"Federation_Example_matrix_server": "Example: matrix.org",
"Federation_Matrix_enable_ephemeral_events": "Enable Matrix ephemeral events",
"Federation_Matrix_enable_ephemeral_events_Alert": "This requires a restart. </br> Enabling ephemeral events like user typing indicator can affect the performance of your Matrix Homeserver and Rocket.Chat server for federated communication",
"Federation_Federated_room_search": "Federated room search",
"Federation_Public_key": "Public Key",
"Federation_Search_federated_rooms": "Search federated rooms",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ export class MatrixBridge implements IFederationBridge {
// Dynamic import to prevent Rocket.Chat from loading the module until needed and then handle if that fails
const { Bridge, AppServiceRegistration, MatrixUser } = await import('@rocket.chat/forked-matrix-appservice-bridge');
MatrixUserInstance = MatrixUser;
const registrationFile = this.internalSettings.generateRegistrationFileObject();
const registrationFile = this.internalSettings.getAppServiceRegistrationObject();

this.bridgeInstance = new Bridge({
homeserverUrl: this.internalSettings.getHomeServerUrl(),
Expand All @@ -730,7 +730,7 @@ export class MatrixBridge implements IFederationBridge {
onLog: (line, isError) => {
console.log(line, isError);
},
...(this.internalSettings.generateRegistrationFileObject().enableEphemeralEvents
...(this.internalSettings.getAppServiceRegistrationObject().enableEphemeralEvents
? {
onEphemeralEvent: (request) => {
const event = request.getData() as unknown as AbstractMatrixEvent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import crypto from 'crypto';
import fs from 'fs';
import { resolve } from 'path';

import { Settings } from '@rocket.chat/models';
import yaml from 'js-yaml';
Expand All @@ -16,7 +14,6 @@ export class RocketChatSettingsAdapter {
public async initialize() {
await this.addFederationSettings();
this.watchChangesAndUpdateRegistrationFile();
await this.updateSettingsWithProvidedConfigFileIfNecessary();
}

public getApplicationServiceId(): string {
Expand Down Expand Up @@ -65,12 +62,8 @@ export class RocketChatSettingsAdapter {
return settings.get('Federation_Matrix_enabled') === true;
}

public areEphemeralEventsEnabled(): boolean {
return this.isTypingStatusEnabled();
}

public isTypingStatusEnabled(): boolean {
return this.getRegistrationFileFromHomeserver()?.enableEphemeralEvents === true;
return settings.get('Federation_Matrix_enable_ephemeral_events') === true;
}

public onFederationEnabledStatusChanged(
Expand Down Expand Up @@ -103,19 +96,19 @@ export class RocketChatSettingsAdapter {
this.getHomeServerDomain(),
this.getBridgeUrl(),
this.getBridgePort(),
this.generateRegistrationFileObject(),
this.getAppServiceRegistrationObject(),
),
);
}

public generateRegistrationFileObject(): IFederationBridgeRegistrationFile {
public getAppServiceRegistrationObject(): IFederationBridgeRegistrationFile {
return {
id: this.getApplicationServiceId(),
homeserverToken: this.getApplicationHomeServerToken(),
applicationServiceToken: this.getApplicationApplicationServiceToken(),
bridgeUrl: this.getBridgeUrl(),
botName: this.getBridgeBotUsername(),
enableEphemeralEvents: this.areEphemeralEventsEnabled(),
enableEphemeralEvents: this.isTypingStatusEnabled(),
listenTo: {
users: [
{
Expand All @@ -140,7 +133,7 @@ export class RocketChatSettingsAdapter {
}

private async updateRegistrationFile(): Promise<void> {
const registrationFile = this.generateRegistrationFileObject();
const registrationFile = this.getAppServiceRegistrationObject();

await Settings.updateValueById(
'Federation_Matrix_registration_file',
Expand Down Expand Up @@ -172,9 +165,7 @@ export class RocketChatSettingsAdapter {
}

private async addFederationSettings(): Promise<void> {
const preExistingConfiguration = this.getRegistrationFileFromHomeserver();

await settingsRegistry.add('Federation_Matrix_enabled', Boolean(preExistingConfiguration), {
await settingsRegistry.add('Federation_Matrix_enabled', false, {
readonly: false,
type: 'boolean',
i18nLabel: 'Federation_Matrix_enabled',
Expand All @@ -185,11 +176,24 @@ export class RocketChatSettingsAdapter {
section: 'Matrix Bridge',
});

await settingsRegistry.add('Federation_Matrix_enable_ephemeral_events', false, {
readonly: false,
type: 'boolean',
i18nLabel: 'Federation_Matrix_enable_ephemeral_events',
i18nDescription: 'Federation_Matrix_enable_ephemeral_events_desc',
alert: 'Federation_Matrix_enable_ephemeral_events_Alert',
public: true,
group: 'Federation',
section: 'Matrix Bridge',
});

const uniqueId = settings.get('uniqueID') || uuidv4().slice(0, 15).replace(new RegExp('-', 'g'), '_');
const homeserverToken = crypto.createHash('sha256').update(`hs_${uniqueId}`).digest('hex');
const applicationServiceToken = crypto.createHash('sha256').update(`as_${uniqueId}`).digest('hex');

await settingsRegistry.add('Federation_Matrix_id', preExistingConfiguration?.id || `rocketchat_${uniqueId}`, {
const siteUrl = settings.get<string>('Site_Url');

await settingsRegistry.add('Federation_Matrix_id', `rocketchat_${uniqueId}`, {
readonly: true,
type: 'string',
i18nLabel: 'Federation_Matrix_id',
Expand All @@ -198,7 +202,7 @@ export class RocketChatSettingsAdapter {
section: 'Matrix Bridge',
});

await settingsRegistry.add('Federation_Matrix_hs_token', preExistingConfiguration?.homeserverToken || homeserverToken, {
await settingsRegistry.add('Federation_Matrix_hs_token', homeserverToken, {
readonly: true,
type: 'string',
i18nLabel: 'Federation_Matrix_hs_token',
Expand All @@ -207,7 +211,7 @@ export class RocketChatSettingsAdapter {
section: 'Matrix Bridge',
});

await settingsRegistry.add('Federation_Matrix_as_token', preExistingConfiguration?.applicationServiceToken || applicationServiceToken, {
await settingsRegistry.add('Federation_Matrix_as_token', applicationServiceToken, {
readonly: true,
type: 'string',
i18nLabel: 'Federation_Matrix_as_token',
Expand All @@ -216,39 +220,33 @@ export class RocketChatSettingsAdapter {
section: 'Matrix Bridge',
});

await settingsRegistry.add(
'Federation_Matrix_homeserver_url',
preExistingConfiguration?.rocketchat?.homeServerUrl || 'http://localhost:8008',
{
type: 'string',
i18nLabel: 'Federation_Matrix_homeserver_url',
i18nDescription: 'Federation_Matrix_homeserver_url_desc',
alert: 'Federation_Matrix_homeserver_url_alert',
group: 'Federation',
section: 'Matrix Bridge',
},
);
await settingsRegistry.add('Federation_Matrix_homeserver_url', 'http://localhost:8008', {
type: 'string',
i18nLabel: 'Federation_Matrix_homeserver_url',
i18nDescription: 'Federation_Matrix_homeserver_url_desc',
alert: 'Federation_Matrix_homeserver_url_alert',
group: 'Federation',
section: 'Matrix Bridge',
});

await settingsRegistry.add(
'Federation_Matrix_homeserver_domain',
preExistingConfiguration?.rocketchat?.domainName || 'local.rocket.chat',
{
type: 'string',
i18nLabel: 'Federation_Matrix_homeserver_domain',
i18nDescription: 'Federation_Matrix_homeserver_domain_desc',
alert: 'Federation_Matrix_homeserver_domain_alert',
},
);
await settingsRegistry.add('Federation_Matrix_homeserver_domain', siteUrl, {
type: 'string',
i18nLabel: 'Federation_Matrix_homeserver_domain',
i18nDescription: 'Federation_Matrix_homeserver_domain_desc',
alert: 'Federation_Matrix_homeserver_domain_alert',
group: 'Federation',
section: 'Matrix Bridge',
});

await settingsRegistry.add('Federation_Matrix_bridge_url', preExistingConfiguration?.bridgeUrl || 'http://host.docker.internal:3300', {
await settingsRegistry.add('Federation_Matrix_bridge_url', 'http://localhost:3300', {
type: 'string',
i18nLabel: 'Federation_Matrix_bridge_url',
i18nDescription: 'Federation_Matrix_bridge_url_desc',
group: 'Federation',
section: 'Matrix Bridge',
});

await settingsRegistry.add('Federation_Matrix_bridge_localpart', preExistingConfiguration?.botName || 'rocket.cat', {
await settingsRegistry.add('Federation_Matrix_bridge_localpart', 'rocket.cat', {
type: 'string',
i18nLabel: 'Federation_Matrix_bridge_localpart',
i18nDescription: 'Federation_Matrix_bridge_localpart_desc',
Expand All @@ -258,7 +256,6 @@ export class RocketChatSettingsAdapter {

await settingsRegistry.add('Federation_Matrix_registration_file', '', {
readonly: true,
hidden: Boolean(preExistingConfiguration),
type: 'code',
i18nLabel: 'Federation_Matrix_registration_file',
i18nDescription: 'Federation_Matrix_registration_file_desc',
Expand All @@ -280,49 +277,4 @@ export class RocketChatSettingsAdapter {
section: 'Matrix Bridge',
});
}

private getRegistrationFileFromHomeserver(): Record<string, any> | undefined {
try {
const registrationYaml = fs.readFileSync(this.getFilePathForHomeserverConfig(), 'utf8');

const parsedFile = yaml.load(registrationYaml as string) as Record<string, any>;
return {
applicationServiceToken: parsedFile.as_token,
bridgeUrl: parsedFile.url,
botName: parsedFile.sender_localpart,
homeserverToken: parsedFile.hs_token,
id: parsedFile.id,
listenTo: parsedFile.namespaces,
enableEphemeralEvents: parsedFile['de.sorunome.msc2409.push_ephemeral'],
rocketchat: { domainName: parsedFile.rocketchat?.homeserver_domain, homeServerUrl: parsedFile.rocketchat?.homeserver_url },
};
} catch (e) {
// no-op
}
}

private getFilePathForHomeserverConfig(): string {
return process.env.NODE_ENV === 'development'
? '../../../../../matrix-federation-config/registration.yaml'
: resolve(process.cwd(), '../../../matrix-federation-config/registration.yaml');
}

private async updateSettingsWithProvidedConfigFileIfNecessary() {
const existingConfiguration = this.getRegistrationFileFromHomeserver();
if (!existingConfiguration) {
return;
}

await Promise.all([
Settings.updateValueById('Federation_Matrix_enabled', true),
Settings.updateValueById('Federation_Matrix_id', existingConfiguration.id),
Settings.updateValueById('Federation_Matrix_hs_token', existingConfiguration.homeserverToken),
Settings.updateValueById('Federation_Matrix_as_token', existingConfiguration.applicationServiceToken),
Settings.updateValueById('Federation_Matrix_homeserver_url', existingConfiguration.rocketchat?.homeServerUrl),
Settings.updateValueById('Federation_Matrix_homeserver_domain', existingConfiguration.rocketchat?.domainName),
Settings.updateValueById('Federation_Matrix_bridge_url', existingConfiguration.bridgeUrl),
Settings.updateValueById('Federation_Matrix_bridge_localpart', existingConfiguration.botName),
Settings.update({ _id: 'Federation_Matrix_registration_file' }, { $set: { hidden: Boolean(existingConfiguration) } }),
]);
}
}
10 changes: 6 additions & 4 deletions apps/meteor/tests/mocks/server/BrokerMocked.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export class BrokerMocked {
actions: Record<string, (...params: unknown[]) => Promise<unknown>> = {};

destroyService(): void {
// no op
services: Map<string, any> = new Map();

async destroyService(name: string): Promise<void> {
this.services.delete(name);
}

createService(): void {
// no op
createService(instance: any): void {
this.services.set(instance.name, instance);
}

async call(method: string, data: any): Promise<any> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const broker = new BrokerMocked();

describe('Check MAC', () => {
before(() => {
api.setBroker(broker);
api.setBroker(broker as any);
});

it('should do nothing if not omnichannel room', async () => {
Expand Down
Loading

0 comments on commit 65d59ea

Please sign in to comment.