snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
446
ee/packages/federation-matrix/tests/end-to-end/ban.spec.ts
Normal file
446
ee/packages/federation-matrix/tests/end-to-end/ban.spec.ts
Normal file
@@ -0,0 +1,446 @@
|
||||
import type { IRoomNativeFederated, IUser } from '@rocket.chat/core-typings';
|
||||
import { Visibility } from 'matrix-js-sdk';
|
||||
|
||||
import type {} from '../../../../../apps/meteor/app/api/server/v1/rooms.ts';
|
||||
import { api } from '../../../../../apps/meteor/tests/data/api-data';
|
||||
import { sendMessage } from '../../../../../apps/meteor/tests/data/messages.helper';
|
||||
import { createRoom, acceptRoomInvite, getRoomMembers } from '../../../../../apps/meteor/tests/data/rooms.helper';
|
||||
import { type IRequestConfig, getRequestConfig, createUser } from '../../../../../apps/meteor/tests/data/users.helper';
|
||||
import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants';
|
||||
import { retry } from '../../../../../apps/meteor/tests/end-to-end/api/helpers/retry';
|
||||
import { federationConfig } from '../helper/config';
|
||||
import { SynapseClient } from '../helper/synapse-client';
|
||||
|
||||
(IS_EE ? describe : describe.skip)('Federation Ban/Unban', () => {
|
||||
let rc1AdminRequestConfig: IRequestConfig;
|
||||
let rc1User1RequestConfig: IRequestConfig;
|
||||
let hs1AdminApp: SynapseClient;
|
||||
|
||||
beforeAll(async () => {
|
||||
rc1AdminRequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
federationConfig.rc1.adminUser,
|
||||
federationConfig.rc1.adminPassword,
|
||||
);
|
||||
|
||||
await createUser(
|
||||
{
|
||||
username: federationConfig.rc1.additionalUser1.username,
|
||||
password: federationConfig.rc1.additionalUser1.password,
|
||||
email: `${federationConfig.rc1.additionalUser1.username}@rocket.chat`,
|
||||
name: federationConfig.rc1.additionalUser1.username,
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
rc1User1RequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
federationConfig.rc1.additionalUser1.username,
|
||||
federationConfig.rc1.additionalUser1.password,
|
||||
);
|
||||
|
||||
hs1AdminApp = new SynapseClient(federationConfig.hs1.url, federationConfig.hs1.adminUser, federationConfig.hs1.adminPassword);
|
||||
await hs1AdminApp.initialize();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (hs1AdminApp) {
|
||||
await hs1AdminApp.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe('Ban from RC side', () => {
|
||||
let channelName: string;
|
||||
let federatedChannelId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `fed-ban-rc-${Date.now()}`;
|
||||
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [federationConfig.hs1.adminMatrixUserId, federationConfig.rc1.additionalUser1.username],
|
||||
extraData: { federated: true },
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
federatedChannelId = createResponse.body.group._id;
|
||||
|
||||
// Accept invitation on Synapse side
|
||||
await hs1AdminApp.acceptInvitationForRoomName(channelName);
|
||||
|
||||
// Accept invitation for the local RC user
|
||||
await acceptRoomInvite(federatedChannelId, rc1User1RequestConfig);
|
||||
|
||||
// Wait for Synapse to see the RC user
|
||||
await retry(
|
||||
'wait for RC user on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('join');
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
it('should ban the RC user via rooms.banUser', async () => {
|
||||
const response = await rc1AdminRequestConfig.request.post(api('rooms.banUser')).set(rc1AdminRequestConfig.credentials).send({
|
||||
roomId: federatedChannelId,
|
||||
userId: rc1User1RequestConfig.credentials['X-User-Id'],
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should list the banned user via rooms.bannedUsers', async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('rooms.bannedUsers'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('success', true);
|
||||
expect(response.body.bannedUsers).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ _id: rc1User1RequestConfig.credentials['X-User-Id'] })]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should reflect ban on Synapse side', async () => {
|
||||
await retry(
|
||||
'wait for ban on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('ban');
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('should not list banned user in room members', async () => {
|
||||
const membersResponse = await getRoomMembers(federatedChannelId, rc1AdminRequestConfig);
|
||||
const banned = membersResponse.members.find((m: IUser) => m._id === rc1User1RequestConfig.credentials['X-User-Id']);
|
||||
expect(banned).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should unban the user via rooms.unbanUser', async () => {
|
||||
const response = await rc1AdminRequestConfig.request.post(api('rooms.unbanUser')).set(rc1AdminRequestConfig.credentials).send({
|
||||
roomId: federatedChannelId,
|
||||
userId: rc1User1RequestConfig.credentials['X-User-Id'],
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should no longer list the user as banned', async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('rooms.bannedUsers'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
const bannedIds = (response.body.bannedUsers || []).map((u: any) => u._id);
|
||||
expect(bannedIds).not.toContain(rc1User1RequestConfig.credentials['X-User-Id']);
|
||||
});
|
||||
|
||||
it('should reflect unban on Synapse side', async () => {
|
||||
await retry(
|
||||
'wait for unban on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).not.toBe('ban');
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ban and unban invited user (invite status preservation)', () => {
|
||||
let channelName: string;
|
||||
let federatedChannelId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `fed-ban-invite-${Date.now()}`;
|
||||
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [federationConfig.hs1.adminMatrixUserId, federationConfig.rc1.additionalUser1.username],
|
||||
extraData: { federated: true },
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
federatedChannelId = createResponse.body.group._id;
|
||||
|
||||
// Accept invitation on Synapse side only — RC user stays as INVITED
|
||||
await hs1AdminApp.acceptInvitationForRoomName(channelName);
|
||||
}, 30000);
|
||||
|
||||
it('should ban the invited user before they accept', async () => {
|
||||
const response = await rc1AdminRequestConfig.request.post(api('rooms.banUser')).set(rc1AdminRequestConfig.credentials).send({
|
||||
roomId: federatedChannelId,
|
||||
userId: rc1User1RequestConfig.credentials['X-User-Id'],
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should have the user listed as banned', async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('rooms.bannedUsers'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.bannedUsers).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ _id: rc1User1RequestConfig.credentials['X-User-Id'] })]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should unban the user (removing the subscription entirely)', async () => {
|
||||
const response = await rc1AdminRequestConfig.request.post(api('rooms.unbanUser')).set(rc1AdminRequestConfig.credentials).send({
|
||||
roomId: federatedChannelId,
|
||||
userId: rc1User1RequestConfig.credentials['X-User-Id'],
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should have no subscription after unban (user must be re-invited)', async () => {
|
||||
const response = await rc1User1RequestConfig.request
|
||||
.get(api('subscriptions.getOne'))
|
||||
.set(rc1User1RequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.body.subscription).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ban from Synapse side', () => {
|
||||
let channelName: string;
|
||||
let federatedChannelId: string;
|
||||
let synapseRoomId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `fed-ban-synapse-${Date.now()}`;
|
||||
synapseRoomId = await hs1AdminApp.createRoom(channelName, Visibility.Private);
|
||||
|
||||
await hs1AdminApp.inviteUserToRoom(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
await hs1AdminApp.inviteUserToRoom(synapseRoomId, federationConfig.rc1.adminMatrixUserId);
|
||||
|
||||
const roomsResponse = await rc1AdminRequestConfig.request.get(api('rooms.get')).set(rc1AdminRequestConfig.credentials).expect(200);
|
||||
|
||||
expect(roomsResponse.body).toHaveProperty('success', true);
|
||||
expect(roomsResponse.body).toHaveProperty('update');
|
||||
|
||||
const rcRoom = roomsResponse.body.update.find(
|
||||
(room: IRoomNativeFederated) => room.federation?.mrid === synapseRoomId,
|
||||
) as IRoomNativeFederated | null;
|
||||
|
||||
expect(rcRoom).not.toBeNull();
|
||||
|
||||
federatedChannelId = rcRoom!._id;
|
||||
|
||||
// Accept invitation for the local RC user
|
||||
await acceptRoomInvite(federatedChannelId, rc1User1RequestConfig);
|
||||
await acceptRoomInvite(federatedChannelId, rc1AdminRequestConfig);
|
||||
|
||||
// Wait for Synapse to see the RC user
|
||||
await retry(
|
||||
'wait for RC user on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('join');
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
it('should ban the RC user from Synapse', async () => {
|
||||
await hs1AdminApp.banUser(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId, 'federation ban test');
|
||||
});
|
||||
|
||||
it('should reflect ban on RC side', async () => {
|
||||
await retry(
|
||||
'wait for ban to propagate to RC',
|
||||
async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('rooms.bannedUsers'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.bannedUsers).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ _id: rc1User1RequestConfig.credentials['X-User-Id'] })]),
|
||||
);
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('should not list banned user in room members on RC side', async () => {
|
||||
const membersResponse = await getRoomMembers(federatedChannelId, rc1AdminRequestConfig);
|
||||
const banned = membersResponse.members.find((m: IUser) => m._id === rc1User1RequestConfig.credentials['X-User-Id']);
|
||||
expect(banned).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should unban the RC user from Synapse', async () => {
|
||||
await hs1AdminApp.unbanUser(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
});
|
||||
|
||||
it('should reflect unban on RC side', async () => {
|
||||
await retry(
|
||||
'wait for unban to propagate to RC',
|
||||
async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('rooms.bannedUsers'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
const bannedIds = (response.body.bannedUsers || []).map((u: any) => u._id);
|
||||
expect(bannedIds).not.toContain(rc1User1RequestConfig.credentials['X-User-Id']);
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ban from Synapse, re-invite and messaging after unban', () => {
|
||||
let channelName: string;
|
||||
let federatedChannelId: string;
|
||||
let synapseRoomId: string;
|
||||
|
||||
it('should create room on Synapse and have RC user accept invite', async () => {
|
||||
channelName = `fed-ban-reinvite-${Date.now()}`;
|
||||
synapseRoomId = await hs1AdminApp.createRoom(channelName, Visibility.Private);
|
||||
|
||||
await hs1AdminApp.inviteUserToRoom(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
|
||||
// Wait for the invite to reach RC and find the room
|
||||
await retry(
|
||||
'wait for invite to reach RC',
|
||||
async () => {
|
||||
const roomsResponse = await rc1User1RequestConfig.request
|
||||
.get(api('rooms.get'))
|
||||
.set(rc1User1RequestConfig.credentials)
|
||||
.expect(200);
|
||||
|
||||
const rcRoom = roomsResponse.body.update.find(
|
||||
(room: IRoomNativeFederated) => room.federation?.mrid === synapseRoomId,
|
||||
) as IRoomNativeFederated | null;
|
||||
|
||||
expect(rcRoom).not.toBeNull();
|
||||
federatedChannelId = rcRoom!._id;
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
|
||||
await acceptRoomInvite(federatedChannelId, rc1User1RequestConfig);
|
||||
|
||||
// Wait for Synapse to see the RC user as joined
|
||||
await retry(
|
||||
'wait for RC user join on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('join');
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
it('should ban the RC user from Synapse', async () => {
|
||||
await hs1AdminApp.banUser(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId, 'ban before re-invite test');
|
||||
|
||||
// Wait for ban to propagate to RC — the banned user should no longer see the room
|
||||
await retry(
|
||||
'wait for ban on RC',
|
||||
async () => {
|
||||
const roomsResponse = await rc1User1RequestConfig.request
|
||||
.get(api('rooms.get'))
|
||||
.set(rc1User1RequestConfig.credentials)
|
||||
.expect(200);
|
||||
|
||||
const rcRoom = roomsResponse.body.update.find((room: IRoomNativeFederated) => room.federation?.mrid === synapseRoomId);
|
||||
|
||||
expect(rcRoom).toBeUndefined();
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('should send a message from Synapse while RC user is banned', async () => {
|
||||
const messageText = `message-while-banned-${Date.now()}`;
|
||||
await hs1AdminApp.sendTextMessage(channelName, messageText);
|
||||
|
||||
const synapseMessage = await hs1AdminApp.findMessageInRoom(channelName, messageText);
|
||||
expect(synapseMessage?.content.body).toBe(messageText);
|
||||
});
|
||||
|
||||
it('should unban the RC user from Synapse', async () => {
|
||||
await hs1AdminApp.unbanUser(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
|
||||
// Verify unban on Synapse side — membership should no longer be 'ban'
|
||||
await retry(
|
||||
'wait for unban on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).not.toBe('ban');
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('should re-invite the RC user from Synapse and have them accept', async () => {
|
||||
await hs1AdminApp.inviteUserToRoom(synapseRoomId, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
|
||||
// Wait for the re-invite to reach RC
|
||||
await retry(
|
||||
'wait for re-invite to reach RC',
|
||||
async () => {
|
||||
const response = await rc1User1RequestConfig.request
|
||||
.get(api('subscriptions.getOne'))
|
||||
.set(rc1User1RequestConfig.credentials)
|
||||
.query({ roomId: federatedChannelId });
|
||||
|
||||
expect(response.body.subscription).not.toBeNull();
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
|
||||
await acceptRoomInvite(federatedChannelId, rc1User1RequestConfig);
|
||||
|
||||
// Wait for Synapse to see the RC user as joined again
|
||||
await retry(
|
||||
'wait for RC user re-join on Synapse',
|
||||
async () => {
|
||||
const member = await hs1AdminApp.findRoomMember(channelName, federationConfig.rc1.additionalUser1.matrixUserId);
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('join');
|
||||
},
|
||||
{ retries: 5, delayMs: 1000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
it('should allow the RC user to send a message after re-joining', async () => {
|
||||
const messageText = `message-after-rejoin-${Date.now()}`;
|
||||
|
||||
const sendResponse = await sendMessage({ rid: federatedChannelId, msg: messageText, config: rc1User1RequestConfig });
|
||||
expect(sendResponse.body).toHaveProperty('success', true);
|
||||
|
||||
// Validate message is received on Synapse
|
||||
const synapseMessage = await hs1AdminApp.findMessageInRoom(channelName, messageText);
|
||||
expect(synapseMessage).not.toBeNull();
|
||||
expect(synapseMessage?.content.body).toBe(messageText);
|
||||
});
|
||||
});
|
||||
});
|
||||
1957
ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts
Normal file
1957
ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,190 @@
|
||||
import type { IRoomNativeFederated, IUser } from '@rocket.chat/core-typings';
|
||||
import { Visibility } from 'matrix-js-sdk';
|
||||
|
||||
import { api } from '../../../../../apps/meteor/tests/data/api-data';
|
||||
import { acceptRoomInvite } from '../../../../../apps/meteor/tests/data/rooms.helper';
|
||||
import {
|
||||
type IRequestConfig,
|
||||
createUser,
|
||||
deleteUser,
|
||||
getRequestConfig,
|
||||
getUserByUsername,
|
||||
} from '../../../../../apps/meteor/tests/data/users.helper';
|
||||
import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants';
|
||||
import { retry } from '../../../../../apps/meteor/tests/end-to-end/api/helpers/retry';
|
||||
import { federationConfig } from '../helper/config';
|
||||
import { SynapseClient } from '../helper/synapse-client';
|
||||
|
||||
const remoteUser = federationConfig.hs1.firstContactUser;
|
||||
const localUser = federationConfig.rc1.firstContactUser;
|
||||
|
||||
/**
|
||||
* Every other federation spec reuses Synapse users that earlier specs have already pulled into
|
||||
* the local database, so the membership handlers always find a complete user document and the
|
||||
* creation path is never observed. This spec reserves a Synapse user nobody else touches, removes
|
||||
* the local document if a previous run left one behind, and only then lets that user reach in.
|
||||
*
|
||||
* The user is therefore created by the inbound invite itself, which is the one code path whose
|
||||
* result is consumed rather than discarded.
|
||||
*/
|
||||
(IS_EE ? describe : describe.skip)('Federation first contact', () => {
|
||||
let rc1AdminRequestConfig: IRequestConfig;
|
||||
let rc1InviteeRequestConfig: IRequestConfig;
|
||||
let hs1FirstContactApp: SynapseClient;
|
||||
|
||||
const forgetRemoteUserLocally = async () => {
|
||||
const known = await getUserByUsername(remoteUser.matrixUserId, rc1AdminRequestConfig);
|
||||
if (known?._id) {
|
||||
await deleteUser({ _id: known._id }, { confirmRelinquish: true }, rc1AdminRequestConfig);
|
||||
}
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
rc1AdminRequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
federationConfig.rc1.adminUser,
|
||||
federationConfig.rc1.adminPassword,
|
||||
);
|
||||
|
||||
const existingLocalUser = await getUserByUsername(localUser.username, rc1AdminRequestConfig);
|
||||
if (!existingLocalUser?._id) {
|
||||
await createUser(
|
||||
{
|
||||
username: localUser.username,
|
||||
password: localUser.password,
|
||||
email: `${localUser.username}@rocket.chat`,
|
||||
name: localUser.username,
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
}
|
||||
|
||||
rc1InviteeRequestConfig = await getRequestConfig(federationConfig.rc1.url, localUser.username, localUser.password);
|
||||
|
||||
// a previous run leaves the user behind, which would make this spec exercise the warm path instead
|
||||
await forgetRemoteUserLocally();
|
||||
|
||||
hs1FirstContactApp = new SynapseClient(federationConfig.hs1.url, remoteUser.username, remoteUser.password);
|
||||
await hs1FirstContactApp.initialize();
|
||||
}, 60000);
|
||||
|
||||
afterAll(async () => {
|
||||
// leave the environment cold so a rerun against persistent containers still tests first contact
|
||||
await forgetRemoteUserLocally();
|
||||
await hs1FirstContactApp?.close();
|
||||
});
|
||||
|
||||
it('should not know the remote user before the first interaction', async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('users.info'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ username: remoteUser.matrixUserId });
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body).toHaveProperty('success', false);
|
||||
});
|
||||
|
||||
describe('when the first interaction is an invite from Synapse', () => {
|
||||
let channelName: string;
|
||||
let synapseRoomId: string;
|
||||
let federatedRoomId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `fed-first-contact-${Date.now()}`;
|
||||
synapseRoomId = await hs1FirstContactApp.createRoom(channelName, Visibility.Private);
|
||||
|
||||
await hs1FirstContactApp.inviteUserToRoom(synapseRoomId, localUser.matrixUserId);
|
||||
}, 60000);
|
||||
|
||||
it('should create the room on the Rocket.Chat side', async () => {
|
||||
await retry(
|
||||
'waiting for the federated room to reach RC',
|
||||
async () => {
|
||||
// rooms.get is scoped to the caller's subscriptions, and only the invitee is in this room
|
||||
const response = await rc1InviteeRequestConfig.request.get(api('rooms.get')).set(rc1InviteeRequestConfig.credentials).expect(200);
|
||||
|
||||
const rcRoom = response.body.update.find(
|
||||
(room: IRoomNativeFederated) => room.federation?.mrid === synapseRoomId,
|
||||
) as IRoomNativeFederated | null;
|
||||
|
||||
expect(rcRoom).toBeTruthy();
|
||||
federatedRoomId = rcRoom!._id;
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
// this covers the persisted document only. The shape of the object the invite handler reads back
|
||||
// is not observable from here — it belongs to the createOrUpdateFederatedUser and
|
||||
// getOrCreateFederatedUser unit tests, and when it regresses the room and subscription
|
||||
// assertions below are what fail.
|
||||
it('should persist the remote user locally as a complete document', async () => {
|
||||
const response = await rc1AdminRequestConfig.request
|
||||
.get(api('users.info'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.query({ username: remoteUser.matrixUserId })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.user).toMatchObject({
|
||||
username: remoteUser.matrixUserId,
|
||||
name: remoteUser.matrixUserId,
|
||||
type: 'user',
|
||||
active: true,
|
||||
federated: true,
|
||||
roles: expect.arrayContaining(['federated-external']),
|
||||
});
|
||||
expect(response.body.user.createdAt).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create the invited subscription for the local user', async () => {
|
||||
const response = await rc1InviteeRequestConfig.request
|
||||
.get(api('subscriptions.getOne'))
|
||||
.set(rc1InviteeRequestConfig.credentials)
|
||||
.query({ roomId: federatedRoomId })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.subscription).toBeTruthy();
|
||||
expect(response.body.subscription).toHaveProperty('status', 'INVITED');
|
||||
});
|
||||
|
||||
it('should let the local user accept the invite', async () => {
|
||||
const response = await acceptRoomInvite(federatedRoomId, rc1InviteeRequestConfig);
|
||||
|
||||
expect(response).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should reach the local user on the Synapse side', async () => {
|
||||
await retry(
|
||||
'waiting for the local user to appear as joined on Synapse',
|
||||
async () => {
|
||||
const member = await hs1FirstContactApp.findRoomMember(channelName, localUser.matrixUserId);
|
||||
|
||||
expect(member).not.toBeNull();
|
||||
expect(member!.membership).toBe('join');
|
||||
},
|
||||
{ retries: 10, delayMs: 2000 },
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
// a named, invite-only Synapse room becomes a private group on RC, so groups.members applies.
|
||||
// it gates on canAccessRoomAsync without includeInvitations, meaning the accepted subscription
|
||||
// has to have settled first — hence the retry and the ordering after the Synapse round-trip
|
||||
it('should list the remote user among the room members', async () => {
|
||||
await retry(
|
||||
'waiting for the room members to include the remote user',
|
||||
async () => {
|
||||
const response = await rc1InviteeRequestConfig.request
|
||||
.get(api('groups.members'))
|
||||
.set(rc1InviteeRequestConfig.credentials)
|
||||
.query({ roomId: federatedRoomId })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.members).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ username: remoteUser.matrixUserId } as Partial<IUser>)]),
|
||||
);
|
||||
},
|
||||
{ retries: 5, delayMs: 2000 },
|
||||
);
|
||||
}, 30000);
|
||||
});
|
||||
});
|
||||
1387
ee/packages/federation-matrix/tests/end-to-end/messaging.spec.ts
Normal file
1387
ee/packages/federation-matrix/tests/end-to-end/messaging.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,890 @@
|
||||
import type { IRoomNativeFederated, IUser } from '@rocket.chat/core-typings';
|
||||
|
||||
import type {} from '../../../../../apps/meteor/app/api/server/v1/permissions.ts';
|
||||
import { api } from '../../../../../apps/meteor/tests/data/api-data';
|
||||
import {
|
||||
addUserToRoomViaMethod,
|
||||
createRoom,
|
||||
getSubscriptionByRoomId,
|
||||
getSubscriptions,
|
||||
} from '../../../../../apps/meteor/tests/data/rooms.helper';
|
||||
import { createUser, deleteUser, getRequestConfig } from '../../../../../apps/meteor/tests/data/users.helper';
|
||||
import type { IRequestConfig, TestUser } from '../../../../../apps/meteor/tests/data/users.helper';
|
||||
import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants';
|
||||
import { retry } from '../../../../../apps/meteor/tests/end-to-end/api/helpers/retry.ts';
|
||||
import { federationConfig } from '../helper/config';
|
||||
import { SynapseClient } from '../helper/synapse-client';
|
||||
|
||||
(IS_EE ? describe : describe.skip)('Federation Permissions', () => {
|
||||
let rc1AdminRequestConfig: IRequestConfig;
|
||||
let rc1User1RequestConfig: IRequestConfig;
|
||||
let hs1AdminApp: SynapseClient;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Create admin request config for RC1
|
||||
rc1AdminRequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
federationConfig.rc1.adminUser,
|
||||
federationConfig.rc1.adminPassword,
|
||||
);
|
||||
|
||||
// Create user1 request config for RC1
|
||||
rc1User1RequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
federationConfig.rc1.additionalUser1.username,
|
||||
federationConfig.rc1.additionalUser1.password,
|
||||
);
|
||||
|
||||
// Create admin Synapse client for HS1
|
||||
hs1AdminApp = new SynapseClient(federationConfig.hs1.url, federationConfig.hs1.adminUser, federationConfig.hs1.adminPassword);
|
||||
await hs1AdminApp.initialize();
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterAll(async () =>
|
||||
// Add permissions for access-federation to any user but admin
|
||||
rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200),
|
||||
);
|
||||
|
||||
afterAll(async () => hs1AdminApp.close());
|
||||
|
||||
describe('Access Federation Permission', () => {
|
||||
describe('Users without access-federation permission', () => {
|
||||
beforeAll(async () => {
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Add permissions for access-federation to any user but admin
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
describe('Inviting from a remote server', () => {
|
||||
let user: TestUser<IUser>;
|
||||
|
||||
let matrixRoomId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
user = await createUser(
|
||||
{
|
||||
username: `g3-${Date.now()}`,
|
||||
password: '1',
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(user, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
let channelName: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `federated-room-${Date.now()}`;
|
||||
matrixRoomId = await hs1AdminApp.createRoom(channelName);
|
||||
});
|
||||
|
||||
it('should throw an error if a remote user tries to invite a user without access-federation permission to a room', async () => {
|
||||
await expect(hs1AdminApp.matrixClient.invite(matrixRoomId, `@${user.username}:${federationConfig.rc1.domain}`)).rejects.toThrow();
|
||||
const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
|
||||
const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName));
|
||||
expect(invitedSub).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should be able to invite a user to a room if the user has access-federation permission', async () => {
|
||||
await expect(hs1AdminApp.matrixClient.invite(matrixRoomId, federationConfig.rc1.adminMatrixUserId)).resolves.not.toThrow();
|
||||
|
||||
await retry('waiting for invitation to be processed', async () => {
|
||||
const subscriptions = await getSubscriptions(rc1AdminRequestConfig);
|
||||
|
||||
const pendingInvitation = subscriptions.update.find(
|
||||
(subscription) => subscription.status === 'INVITED' && subscription.fname?.includes(channelName),
|
||||
);
|
||||
expect(pendingInvitation).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if a user without access-federation permission tries to create a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rc1User1RequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(400);
|
||||
expect(createResponse.body).toHaveProperty('success', false);
|
||||
expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation');
|
||||
});
|
||||
|
||||
describe('Inviting from a local server', () => {
|
||||
let channelName: string;
|
||||
|
||||
let createResponse;
|
||||
let addUserResponse;
|
||||
|
||||
beforeAll(async () => {
|
||||
channelName = `federated-room-${Date.now()}`;
|
||||
createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
expect(createResponse.status).toBe(200);
|
||||
expect(createResponse.body).toHaveProperty('success', true);
|
||||
expect(createResponse.body).toHaveProperty('group');
|
||||
expect(createResponse.body.group).toHaveProperty('_id');
|
||||
expect(createResponse.body.group).toHaveProperty('t', 'p');
|
||||
expect(createResponse.body.group).toHaveProperty('federated', true);
|
||||
});
|
||||
let user: TestUser<IUser>;
|
||||
|
||||
beforeAll(async () => {
|
||||
user = await createUser(
|
||||
{
|
||||
username: `g3-${Date.now()}`,
|
||||
password: '1',
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(user, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
it('should not be able to add a user without access-federation permission to a room', async () => {
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [user.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(400);
|
||||
expect(addUserResponse.body).toHaveProperty('success', false);
|
||||
expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/);
|
||||
});
|
||||
|
||||
it("should be able to add a remote user to a room regardless of the user's access-federation permission defined locally", async () => {
|
||||
addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [federationConfig.hs1.adminMatrixUserId],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(200);
|
||||
expect(addUserResponse.body).toHaveProperty('success', true);
|
||||
expect(addUserResponse.body).toHaveProperty('message');
|
||||
expect(addUserResponse.body.message).toMatch('{"msg":"result","id":"id","result":true}');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Users with access-federation permission', () => {
|
||||
let user: TestUser<IUser>;
|
||||
|
||||
beforeAll(async () => {
|
||||
user = await createUser(
|
||||
{
|
||||
username: `g3-${Date.now()}`,
|
||||
password: '1',
|
||||
roles: ['user', 'admin'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(user, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should be able to create a federated room if the user has access-federation permission', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
expect(createResponse.body).toHaveProperty('success', true);
|
||||
expect(createResponse.body).toHaveProperty('group');
|
||||
expect(createResponse.body.group).toHaveProperty('_id');
|
||||
expect(createResponse.body.group).toHaveProperty('t', 'p');
|
||||
expect(createResponse.body.group).toHaveProperty('federated', true);
|
||||
});
|
||||
|
||||
describe('Add a user with access-federation permission to a room', () => {
|
||||
beforeAll(async () =>
|
||||
rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200),
|
||||
);
|
||||
|
||||
it('should be able to add a user with access-federation permission to a room', async () => {
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: `federated-room-${Date.now()}`,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rc1AdminRequestConfig,
|
||||
}).expect(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [user.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rc1AdminRequestConfig,
|
||||
}).expect(200);
|
||||
|
||||
expect(addUserResponse.body).toHaveProperty('success', true);
|
||||
expect(addUserResponse.body).toHaveProperty('message');
|
||||
expect(addUserResponse.body.message).toMatch('{"msg":"result","id":"id","result":true}');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Federation_Service_Validate_User_Domain Setting', () => {
|
||||
const rcValidUser1 = {
|
||||
username: `valid-user1-${Date.now()}`,
|
||||
fullName: `Valid User1 ${Date.now()}`,
|
||||
get matrixId() {
|
||||
return `@${this.username}:${federationConfig.rc1.domain}`;
|
||||
},
|
||||
config: {} as IRequestConfig,
|
||||
user: {} as TestUser<IUser>,
|
||||
};
|
||||
|
||||
const rcValidUser2 = {
|
||||
username: `valid-user2-${Date.now()}`,
|
||||
fullName: `Valid User2 ${Date.now()}`,
|
||||
get matrixId() {
|
||||
return `@${this.username}:${federationConfig.rc1.domain}`;
|
||||
},
|
||||
config: {} as IRequestConfig,
|
||||
user: {} as TestUser<IUser>,
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
// Ensure access-federation is granted to all users
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('permissions.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
// Create RC users
|
||||
rcValidUser1.user = await createUser(
|
||||
{
|
||||
username: rcValidUser1.username,
|
||||
password: 'random',
|
||||
email: `${rcValidUser1.username}@${federationConfig.rc1.domain}`,
|
||||
name: rcValidUser1.fullName,
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: rcValidUser1.user._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
rcValidUser1.config = await getRequestConfig(federationConfig.rc1.url, rcValidUser1.username, 'random');
|
||||
|
||||
rcValidUser2.user = await createUser(
|
||||
{
|
||||
username: rcValidUser2.username,
|
||||
password: 'random',
|
||||
email: `${rcValidUser2.username}@${federationConfig.rc1.domain}`,
|
||||
name: rcValidUser2.fullName,
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: rcValidUser2.user._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
rcValidUser2.config = await getRequestConfig(federationConfig.rc1.url, rcValidUser2.username, 'random');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await Promise.all([
|
||||
deleteUser(rcValidUser1.user, {}, rc1AdminRequestConfig),
|
||||
deleteUser(rcValidUser2.user, {}, rc1AdminRequestConfig),
|
||||
]);
|
||||
});
|
||||
|
||||
describe('When setting is enabled', () => {
|
||||
beforeAll(async () => {
|
||||
// Enable email domain validation
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('settings/Federation_Service_Validate_User_Domain'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ value: true })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Disable email domain validation
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('settings/Federation_Service_Validate_User_Domain'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ value: false })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
describe('User with verified email matching federation domain', () => {
|
||||
it('should be able to create a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
expect(createResponse.body).toHaveProperty('success', true);
|
||||
expect(createResponse.body).toHaveProperty('group');
|
||||
expect(createResponse.body.group).toHaveProperty('federated', true);
|
||||
});
|
||||
|
||||
it('should be able to be added to a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [rcValidUser2.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(200);
|
||||
expect(addUserResponse.body).toHaveProperty('success', true);
|
||||
});
|
||||
|
||||
it('should be able to be added to a federated room during creation', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [rcValidUser2.username],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
expect(createResponse.body).toHaveProperty('success', true);
|
||||
expect(createResponse.body).toHaveProperty('group');
|
||||
expect(createResponse.body.group).toHaveProperty('federated', true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User with verified email NOT matching federation domain', () => {
|
||||
let userWithNonMatchingEmail: TestUser<IUser>;
|
||||
let userRequestConfig: IRequestConfig;
|
||||
|
||||
beforeAll(async () => {
|
||||
userWithNonMatchingEmail = await createUser(
|
||||
{
|
||||
username: `user-nonmatching-${Date.now()}`,
|
||||
password: 'password123',
|
||||
email: `user-nonmatching-${Date.now()}@external-domain.com`,
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
// Verify the user's email
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: userWithNonMatchingEmail._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
userRequestConfig = await getRequestConfig(federationConfig.rc1.url, userWithNonMatchingEmail.username, 'password123');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(userWithNonMatchingEmail, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should NOT be able to create a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: userRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(400);
|
||||
expect(createResponse.body).toHaveProperty('success', false);
|
||||
expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation');
|
||||
});
|
||||
|
||||
it('should NOT be able to be added to a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [userWithNonMatchingEmail.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(400);
|
||||
expect(addUserResponse.body).toHaveProperty('success', false);
|
||||
expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/);
|
||||
});
|
||||
|
||||
it('should NOT be able to be added to a federated room during creation', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [userWithNonMatchingEmail.username],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: userRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(400);
|
||||
expect(createResponse.body).toHaveProperty('success', false);
|
||||
expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation');
|
||||
});
|
||||
});
|
||||
|
||||
describe('User with unverified email matching federation domain', () => {
|
||||
let userWithUnverifiedEmail: TestUser<IUser>;
|
||||
let userRequestConfig: IRequestConfig;
|
||||
|
||||
beforeAll(async () => {
|
||||
userWithUnverifiedEmail = await createUser(
|
||||
{
|
||||
username: `user-unverified-${Date.now()}`,
|
||||
password: 'password123',
|
||||
email: `user-unverified-${Date.now()}@${federationConfig.rc1.domain}`,
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
userRequestConfig = await getRequestConfig(federationConfig.rc1.url, userWithUnverifiedEmail.username, 'password123');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(userWithUnverifiedEmail, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should NOT be able to create a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: userRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(400);
|
||||
expect(createResponse.body).toHaveProperty('success', false);
|
||||
expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation');
|
||||
});
|
||||
|
||||
it('should NOT be able to be added to a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [userWithUnverifiedEmail.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(400);
|
||||
expect(addUserResponse.body).toHaveProperty('success', false);
|
||||
expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User without email', () => {
|
||||
let userWithoutEmail: TestUser<IUser>;
|
||||
let userRequestConfig: IRequestConfig;
|
||||
|
||||
beforeAll(async () => {
|
||||
userWithoutEmail = await createUser(
|
||||
{
|
||||
username: `user-noemail-${Date.now()}`,
|
||||
password: 'password123',
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
userRequestConfig = await getRequestConfig(federationConfig.rc1.url, userWithoutEmail.username, 'password123');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(userWithoutEmail, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should NOT be able to create a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: userRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(400);
|
||||
expect(createResponse.body).toHaveProperty('success', false);
|
||||
expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation');
|
||||
});
|
||||
|
||||
it('should NOT be able to be added to a federated room', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [userWithoutEmail.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rcValidUser1.config,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(400);
|
||||
expect(addUserResponse.body).toHaveProperty('success', false);
|
||||
expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Remote invitations with email domain validation', () => {
|
||||
let userWithMatchingEmail: TestUser<IUser>;
|
||||
let userWithNonMatchingEmail: TestUser<IUser>;
|
||||
let matrixRoomId: string;
|
||||
|
||||
let userWithMatchingEmailRequestConfig: IRequestConfig;
|
||||
let userWithNonMatchingEmailRequestConfig: IRequestConfig;
|
||||
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
|
||||
beforeAll(async () => {
|
||||
userWithMatchingEmail = await createUser(
|
||||
{
|
||||
username: `user-remote-matching-${Date.now()}`,
|
||||
password: 'password123',
|
||||
email: `user-remote-matching-${Date.now()}@${federationConfig.rc1.domain}`,
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
userWithMatchingEmailRequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
userWithMatchingEmail.username,
|
||||
'password123',
|
||||
);
|
||||
|
||||
// Verify the user's email
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: userWithMatchingEmail._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
userWithNonMatchingEmail = await createUser(
|
||||
{
|
||||
username: `user-remote-nonmatching-${Date.now()}`,
|
||||
password: 'password123',
|
||||
email: `user-remote-nonmatching-${Date.now()}@external-domain.com`,
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
userWithNonMatchingEmailRequestConfig = await getRequestConfig(
|
||||
federationConfig.rc1.url,
|
||||
userWithNonMatchingEmail.username,
|
||||
'password123',
|
||||
);
|
||||
|
||||
// Verify the user's email
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: userWithNonMatchingEmail._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
matrixRoomId = await hs1AdminApp.createRoom(channelName);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(userWithMatchingEmail, {}, rc1AdminRequestConfig);
|
||||
await deleteUser(userWithNonMatchingEmail, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should accept invitation for user with verified email matching federation domain', async () => {
|
||||
await expect(
|
||||
hs1AdminApp.matrixClient.invite(matrixRoomId, `@${userWithMatchingEmail.username}:${federationConfig.rc1.domain}`),
|
||||
).resolves.not.toThrow();
|
||||
|
||||
await retry('this is an async operation, so we need to wait for the room to be created in RC', async () => {
|
||||
const roomsResponse = await userWithMatchingEmailRequestConfig.request
|
||||
.get(api('rooms.get'))
|
||||
.set(userWithMatchingEmailRequestConfig.credentials)
|
||||
.expect(200);
|
||||
|
||||
expect(roomsResponse.body).toHaveProperty('success', true);
|
||||
expect(roomsResponse.body).toHaveProperty('update');
|
||||
|
||||
const rcRoomConverted = roomsResponse.body.update.find((room: IRoomNativeFederated) => room.federation.mrid === matrixRoomId);
|
||||
|
||||
expect(rcRoomConverted).toHaveProperty('_id');
|
||||
expect(rcRoomConverted).toHaveProperty('t', 'p');
|
||||
|
||||
const subA = await getSubscriptionByRoomId(
|
||||
rcRoomConverted._id,
|
||||
userWithMatchingEmailRequestConfig.credentials,
|
||||
userWithMatchingEmailRequestConfig.request,
|
||||
);
|
||||
|
||||
expect(subA).toHaveProperty('fname', `${channelName}:${federationConfig.hs1.domain}`);
|
||||
expect(subA).toHaveProperty('status', 'INVITED');
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject invitation for user with verified email NOT matching federation domain', async () => {
|
||||
await expect(
|
||||
hs1AdminApp.matrixClient.invite(matrixRoomId, `@${userWithNonMatchingEmail.username}:${federationConfig.rc1.domain}`),
|
||||
).rejects.toThrow();
|
||||
|
||||
const subscriptions = await getSubscriptions(userWithNonMatchingEmailRequestConfig);
|
||||
const invitedSub = subscriptions.update.find((sub) => sub.fname === `${channelName}:${federationConfig.hs1.domain}`);
|
||||
expect(invitedSub).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When setting is disabled', () => {
|
||||
beforeAll(async () => {
|
||||
// Disable email domain validation
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('settings/Federation_Service_Validate_User_Domain'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({ value: false })
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
describe('User with any email domain', () => {
|
||||
let userWithNonMatchingEmail: TestUser<IUser>;
|
||||
let userRequestConfig: IRequestConfig;
|
||||
|
||||
beforeAll(async () => {
|
||||
userWithNonMatchingEmail = await createUser(
|
||||
{
|
||||
username: `user-any-domain-${Date.now()}`,
|
||||
password: 'password123',
|
||||
email: `user-any-domain-${Date.now()}@external-domain.com`,
|
||||
roles: ['user'],
|
||||
},
|
||||
rc1AdminRequestConfig,
|
||||
);
|
||||
|
||||
// Verify the user's email
|
||||
await rc1AdminRequestConfig.request
|
||||
.post(api('users.update'))
|
||||
.set(rc1AdminRequestConfig.credentials)
|
||||
.send({
|
||||
userId: userWithNonMatchingEmail._id,
|
||||
data: {
|
||||
verified: true,
|
||||
},
|
||||
})
|
||||
.expect('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
userRequestConfig = await getRequestConfig(federationConfig.rc1.url, userWithNonMatchingEmail.username, 'password123');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUser(userWithNonMatchingEmail, {}, rc1AdminRequestConfig);
|
||||
});
|
||||
|
||||
it('should be able to create a federated room regardless of email domain', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: userRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
expect(createResponse.body).toHaveProperty('success', true);
|
||||
expect(createResponse.body).toHaveProperty('group');
|
||||
expect(createResponse.body.group).toHaveProperty('federated', true);
|
||||
});
|
||||
|
||||
it('should be able to be added to a federated room regardless of email domain', async () => {
|
||||
const channelName = `federated-room-${Date.now()}`;
|
||||
const createResponse = await createRoom({
|
||||
type: 'p',
|
||||
name: channelName,
|
||||
members: [],
|
||||
extraData: {
|
||||
federated: true,
|
||||
},
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
expect(createResponse.status).toBe(200);
|
||||
|
||||
const addUserResponse = await addUserToRoomViaMethod({
|
||||
usernames: [userWithNonMatchingEmail.username],
|
||||
rid: createResponse.body.group._id,
|
||||
config: rc1AdminRequestConfig,
|
||||
});
|
||||
|
||||
expect(addUserResponse.status).toBe(200);
|
||||
expect(addUserResponse.body).toHaveProperty('success', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
2206
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
Normal file
2206
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user