Merge pull request #1056 from bbassie/fix/subscription-permission-revoke

Drop subscriptions when a user loses permission for them
This commit is contained in:
Cooldude2606 authored and GitHub committed 2026-10-08 17:23:43 +01:00
commit 208ecb826e
6 files changed
+188 -17

No files matched your search

+66 -1
View File
@@ -10,7 +10,7 @@ import { fileURLToPath } from "node:url";
import {
ControllerConfig, Address, RequestError,
InstanceConfig, SystemInfo, Role, ModPack,
InstanceConfig, SystemInfo, Role, ModPack, AccountUpdateEvent,
addPluginConfigFields,
} from "@clusterio/lib";
@@ -279,6 +279,71 @@ describe("controller/src/Controller", function() {
});
});
function mockPermissionChanges() {
const role = new Role(1, "Test", "", new Set(["core.log.follow"]));
const otherRole = new Role(2, "Other", "", new Set());
const user = { roles: new Set([role]) };
const otherUser = { roles: new Set([otherRole]) };
const sent = [];
const checked = [];
const connection = {
user,
logChecked: false,
send(message) { sent.push(message); },
checkLogPermission() { this.logChecked = true; },
};
const otherConnection = {
user: otherUser,
send(message) { sent.push(message); },
checkLogPermission() {},
};
const originalWsServer = controller.wsServer;
controller.wsServer = { controlConnections: new Map([[1, connection], [2, otherConnection]]) };
controller.subscriptions.checkLinkPermissions = (link, linkUser) => checked.push([link, linkUser]);
return {
role, user, connection, sent, checked,
restore() {
controller.wsServer = originalWsServer;
delete controller.subscriptions.checkLinkPermissions;
},
};
}
function assertAccountUpdate(sent, role) {
assert.equal(sent.length, 1);
assert(sent[0] instanceof AccountUpdateEvent);
assert.deepEqual(sent[0].roles, [{ name: role.name, id: role.id, permissions: [...role.permissions] }]);
}
describe(".userPermissionsUpdated()", function() {
let mocked;
beforeEach(function() { mocked = mockPermissionChanges(); });
afterEach(function() { mocked.restore(); });
it("should send an account update to connections of the user", function() {
controller.userPermissionsUpdated(mocked.user);
assertAccountUpdate(mocked.sent, mocked.role);
});
it("should recheck subscriptions and log following of the user", function() {
controller.userPermissionsUpdated(mocked.user);
assert.deepEqual(mocked.checked, [[mocked.connection, mocked.user]]);
assert(mocked.connection.logChecked, "log permission was not checked");
});
});
describe(".rolesUpdated()", function() {
let mocked;
beforeEach(function() { mocked = mockPermissionChanges(); });
afterEach(function() { mocked.restore(); });
it("should send an account update to connections with the role", function() {
controller.rolesUpdated([mocked.role]);
assertAccountUpdate(mocked.sent, mocked.role);
});
it("should recheck subscriptions and log following of users with the role", function() {
controller.rolesUpdated([mocked.role]);
assert.deepEqual(mocked.checked, [[mocked.connection, mocked.user]]);
assert(mocked.connection.logChecked, "log permission was not checked");
});
});
describe(".instances", function() {
it("should set the dirty flag if the config is updated", function() {
controller.instances.records.dirty = false;