fix(api): only require permissions a channel overwrite grants (#2867)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-20 17:56:22 +02:00
1 parent 416af4bec4
commit eedfd9275f
4 files changed
+112 -22

No files matched your search

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {overwriteGrantedBits} from '@app/api/utils/PermissionUtils';
import {Permissions} from '@fluxer/constants/src/ChannelConstants';
import {describe, expect, it} from 'vitest';
const BOT_OVERWRITE = {
allow: Permissions.ADD_REACTIONS | Permissions.SEND_MESSAGES | Permissions.MANAGE_MESSAGES | Permissions.PIN_MESSAGES,
deny: 0n,
};
describe('overwriteGrantedBits', () => {
it('grants nothing when an overwrite is resubmitted unmodified', () => {
expect(overwriteGrantedBits(BOT_OVERWRITE, {...BOT_OVERWRITE})).toBe(0n);
});
it('ignores allow bits that were already set when another bit is flipped', () => {
const before = {allow: Permissions.PIN_MESSAGES, deny: 0n};
const after = {allow: Permissions.PIN_MESSAGES | Permissions.SEND_MESSAGES, deny: 0n};
expect(overwriteGrantedBits(before, after)).toBe(Permissions.SEND_MESSAGES);
});
it('grants nothing when an allow bit is withdrawn', () => {
const before = {allow: Permissions.SEND_MESSAGES | Permissions.MANAGE_MESSAGES, deny: 0n};
const after = {allow: Permissions.SEND_MESSAGES, deny: 0n};
expect(overwriteGrantedBits(before, after)).toBe(0n);
});
it('grants nothing when a deny is added for a permission the editor lacks', () => {
const after = {allow: Permissions.VIEW_CHANNEL, deny: Permissions.MANAGE_MESSAGES};
expect(overwriteGrantedBits(null, after)).toBe(Permissions.VIEW_CHANNEL);
});
it('grants the bits lifted out of deny', () => {
const before = {allow: 0n, deny: Permissions.ADD_REACTIONS | Permissions.SEND_MESSAGES};
const after = {allow: 0n, deny: Permissions.ADD_REACTIONS};
expect(overwriteGrantedBits(before, after)).toBe(Permissions.SEND_MESSAGES);
});
it('treats a removed overwrite as granting everything it denied', () => {
const before = {allow: Permissions.SEND_MESSAGES, deny: Permissions.ADD_REACTIONS};
expect(overwriteGrantedBits(before, undefined)).toBe(Permissions.ADD_REACTIONS);
});
});
@@ -51,3 +51,14 @@ export async function hasPermission(
): Promise<boolean> {
return await gatewayService.checkPermission(params);
}
export function overwriteGrantedBits(
before: {allow: bigint; deny: bigint} | null | undefined,
after: {allow: bigint; deny: bigint} | null | undefined,
): bigint {
const beforeAllow = before?.allow ?? 0n;
const beforeDeny = before?.deny ?? 0n;
const afterAllow = after?.allow ?? 0n;
const afterDeny = after?.deny ?? 0n;
return (afterAllow & ~beforeAllow) | (beforeDeny & ~afterDeny);
}