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

Add E2E tests for the privacy filter. #1766

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions changelog.d/1766.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a test for the privacy filter.
209 changes: 209 additions & 0 deletions spec/e2e/privacyfilter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import { TestIrcServer } from "matrix-org-irc";
import { IrcBridgeE2ETest } from "../util/e2e-test";
import { describe, it, expect } from "@jest/globals";


describe('Connection pooling', () => {
let testEnv: IrcBridgeE2ETest;

beforeEach(async () => {
const alice = TestIrcServer.generateUniqueNick('alice');
const bannedUser = TestIrcServer.generateUniqueNick('banneduser');
// Initial run of the bridge to setup a testing environment
testEnv = await IrcBridgeE2ETest.createTestEnv({
matrixLocalparts: [alice, bannedUser],
ircNicks: ['bob'],
ircServerConfig: {
membershipLists: {
enabled: true,
floodDelayMs: 100,
global: {
ircToMatrix: {
incremental: true,
initial: true,
requireMatrixJoined: true,
},
matrixToIrc: {
incremental: true,
initial: true,
}
}
},
excludedUsers: [{
regex: `@${bannedUser}.*`,
kickReason: 'Test kick',
}]
}
});
await testEnv.setUp();
});

// Ensure we always tear down
afterEach(() => {
return testEnv.tearDown();
});

it('should be able to send a message with the privacy filter on', async () => {
const channel = `#${TestIrcServer.generateUniqueNick("test")}`;

const { homeserver } = testEnv;
const alice = homeserver.users[0].client;
const { bob } = testEnv.ircTest.clients;

// Create the channel
await bob.join(channel);

const adminRoomId = await testEnv.createAdminRoomHelper(alice);
const cRoomId = await testEnv.joinChannelHelper(alice, adminRoomId, channel);

// And finally wait for bob to appear.
const bobUserId = `@irc_${bob.nick}:${homeserver.domain}`;
await alice.waitForRoomEvent(
{eventType: 'm.room.member', sender: bobUserId, stateKey: bobUserId, roomId: cRoomId}
);


// Send some messages
const aliceMsg = bob.waitForEvent('message', 10000);
const bobMsg = alice.waitForRoomEvent(
{eventType: 'm.room.message', sender: bobUserId, roomId: cRoomId}
);
alice.sendText(cRoomId, "Hello bob!");
await aliceMsg;
bob.say(channel, "Hi alice!");
await bobMsg;
});

it('should kick an excluded user if the bridge has permission', async () => {
const channel = `#${TestIrcServer.generateUniqueNick("test")}`;

const { homeserver } = testEnv;
const alice = homeserver.users[0].client;
const bannedUser = homeserver.users[1].client;
const { bob } = testEnv.ircTest.clients;

// Create the channel
await bob.join(channel);

const adminRoomId = await testEnv.createAdminRoomHelper(alice);
const cRoomId = await testEnv.createProvisionedRoom(alice, adminRoomId, channel, true);

// And finally wait for bob to appear.
const bobUserId = `@irc_${bob.nick}:${homeserver.domain}`;
await alice.waitForRoomEvent(
{eventType: 'm.room.member', sender: bobUserId, stateKey: bobUserId, roomId: cRoomId}
);
const aliceMsg = bob.waitForEvent('message', 10000);
alice.sendText(cRoomId, "Hello bob!");
await aliceMsg;

// Note, the bridge can't kick bannedUser due to lacking perms.
const kick = alice.waitForRoomEvent({
eventType: 'm.room.member',
sender: testEnv.ircBridge.appServiceUserId,
roomId: cRoomId,
stateKey: homeserver.users[1].userId,
});
await bannedUser.joinRoom(cRoomId);
const kickContent = (await kick).data;
expect(kickContent.content.reason).toEqual('Test kick');
expect(kickContent.content.membership).toEqual('leave');
});

it('should not bridge messages with an excluded user', async () => {
const channel = `#${TestIrcServer.generateUniqueNick("test")}`;

const { homeserver } = testEnv;
const alice = homeserver.users[0].client;
const bannedUser = homeserver.users[1].client;
const { bob } = testEnv.ircTest.clients;

// Create the channel
await bob.join(channel);

const adminRoomId = await testEnv.createAdminRoomHelper(alice);
const cRoomId = await testEnv.createProvisionedRoom(alice, adminRoomId, channel, false);

// And finally wait for bob to appear.
const bobUserId = `@irc_${bob.nick}:${homeserver.domain}`;
await alice.waitForRoomEvent(
{eventType: 'm.room.member', sender: bobUserId, stateKey: bobUserId, roomId: cRoomId}
);
const aliceMsg = bob.waitForEvent('message', 10000);
alice.sendText(cRoomId, "Hello bob!");
await aliceMsg;

// Note, the bridge can't kick bannedUser due to lacking perms.
await bannedUser.joinRoom(cRoomId);
const message = alice.waitForRoomEvent(
{eventType: 'm.room.message', sender: bobUserId, roomId: cRoomId}
);
const connectionStateEv = alice.waitForRoomEvent({
eventType: 'org.matrix.appservice-irc.connection',
sender: testEnv.ircBridge.appServiceUserId,
roomId: cRoomId
});
await bob.say(channel, "Hi alice!");
try {
await message;
throw Error('Expected message to not be viewable.');
}
catch (ex) {
if (!ex.message.startsWith(`Timed out waiting for m.room.message from ${bobUserId} in ${cRoomId}`)) {
throw ex;
}
}
const connectionEventData = (await connectionStateEv).data;
expect(connectionEventData.content.blocked).toBe(true);
});

it('should unblock a blocked channel if all excluded users leave', async () => {
const channel = `#${TestIrcServer.generateUniqueNick("test")}`;

const { homeserver } = testEnv;
const alice = homeserver.users[0].client;
const bannedUser = homeserver.users[1].client;
const { bob } = testEnv.ircTest.clients;

// Create the channel
await bob.join(channel);

const adminRoomId = await testEnv.createAdminRoomHelper(alice);
const cRoomId = await testEnv.createProvisionedRoom(alice, adminRoomId, channel, false);

// And finally wait for bob to appear.
const bobUserId = `@irc_${bob.nick}:${homeserver.domain}`;
await alice.waitForRoomEvent(
{eventType: 'm.room.member', sender: bobUserId, stateKey: bobUserId, roomId: cRoomId}
);
const aliceMsg = bob.waitForEvent('message', 10000);
alice.sendText(cRoomId, "Hello bob!");
await aliceMsg;

// Note, the bridge can't kick bannedUser due to lacking perms.
await bannedUser.joinRoom(cRoomId);
const connectionStateEv = alice.waitForRoomEvent({
eventType: 'org.matrix.appservice-irc.connection',
sender: testEnv.ircBridge.appServiceUserId,
roomId: cRoomId
});
await bob.say(channel, "Hi alice!");
const connectionEventData = (await connectionStateEv).data;
expect(connectionEventData.content.blocked).toBe(true);

await bannedUser.leaveRoom(cRoomId);
const bobMsg = alice.waitForRoomEvent(
{eventType: 'm.room.message', sender: bobUserId, roomId: cRoomId}
);
const connectionStateEvUnblocked = alice.waitForRoomEvent({
eventType: 'org.matrix.appservice-irc.connection',
sender: testEnv.ircBridge.appServiceUserId,
roomId: cRoomId
});
await bob.say(channel, "Hi alice!");

const connectionEventDataUnblocked = (await connectionStateEvUnblocked).data;
expect(connectionEventDataUnblocked.content.blocked).toBe(false);
await bobMsg;
});
});
30 changes: 28 additions & 2 deletions spec/util/e2e-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { BridgeConfig } from "../../src/config/BridgeConfig";
import { Client as PgClient } from "pg";
import { ComplementHomeServer, createHS, destroyHS } from "./homerunner";
import { IrcBridge } from '../../src/bridge/IrcBridge';
import { IrcServer } from "../../src/irc/IrcServer";
import { IrcServer, IrcServerConfig } from "../../src/irc/IrcServer";
import { MatrixClient } from "matrix-bot-sdk";
import { TestIrcServer } from "matrix-org-irc";
import { IrcConnectionPool } from "../../src/pool-service/IrcConnectionPool";
import { expect } from "@jest/globals";
import dns from 'node:dns';
import fs from "node:fs/promises";
import { WriteStream, createWriteStream } from "node:fs";

// Needed to make tests work on GitHub actions. Node 17+ defaults
// to IPv6, and the homerunner domain resolves to IPv6, but the
// runtime doesn't actually support IPv6 🤦
Expand All @@ -27,6 +28,7 @@ interface Opts {
ircNicks?: string[];
timeout?: number;
config?: Partial<BridgeConfig>,
ircServerConfig?: Partial<IrcServerConfig>,
traceToFile?: boolean,
}

Expand Down Expand Up @@ -268,7 +270,8 @@ export class IrcBridgeE2ETest {
initial: true,
}
}
}
},
...opts.ircServerConfig,
}
},
provisioning: {
Expand All @@ -290,6 +293,9 @@ export class IrcBridgeE2ETest {
debugApi: {
enabled: false,
port: 0,
},
permissions: {
[homeserver.users[0].userId]: "admin",
}
},
...config,
Expand Down Expand Up @@ -392,4 +398,24 @@ export class IrcBridgeE2ETest {
await client.joinRoom(cRoomId);
return cRoomId;
}

public async createProvisionedRoom(
client: E2ETestMatrixClient, adminRoomId: string, channel: string, setPl = true
): Promise<string> {
const plumbedRoomId = await client.createRoom({
name: `Plumbed room for ${channel}`,
preset: "public_chat",
invite: [this.ircBridge.appServiceUserId],
power_level_content_override: {
users: {
[this.ircBridge.appServiceUserId]: setPl ? 100 : 50,
[await client.getUserId()]: 100,
},
kick: 75,
state_default: 50
}
});
await client.sendText(adminRoomId, `!plumb ${plumbedRoomId} localhost ${channel}`);
return plumbedRoomId;
}
}
Loading