mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
332 lines
14 KiB
TypeScript
332 lines
14 KiB
TypeScript
import {
|
|
addMemberRole,
|
|
createChannel,
|
|
createPermissionOverwrite,
|
|
createRole,
|
|
getChannel,
|
|
setupTestGuildWithMembers,
|
|
} from '@app/api/channel/tests/ChannelTestUtils';
|
|
import {type ApiTestHarness, createApiTestHarness} from '@app/api/test/ApiTestHarness';
|
|
import {HTTP_STATUS} from '@app/api/test/TestConstants';
|
|
import {createBuilder} from '@app/api/test/TestRequestBuilder';
|
|
import {ChannelTypes, Permissions} from '@fluxer/constants/src/ChannelConstants';
|
|
import type {ChannelResponse} from '@fluxer/schema/src/domains/channel/ChannelSchemas';
|
|
import {afterEach, beforeEach, describe, expect, test} from 'vitest';
|
|
|
|
describe('Channel Permission Overwrites', () => {
|
|
let harness: ApiTestHarness;
|
|
beforeEach(async () => {
|
|
harness = await createApiTestHarness();
|
|
});
|
|
afterEach(async () => {
|
|
await harness?.shutdown();
|
|
});
|
|
test('should deny permission via overwrite', async () => {
|
|
const {owner, members, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const member = members[0];
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, member.userId, {
|
|
type: 1,
|
|
allow: '0',
|
|
deny: Permissions.SEND_MESSAGES.toString(),
|
|
});
|
|
await createBuilder(harness, member.token)
|
|
.post(`/channels/${systemChannel.id}/messages`)
|
|
.body({content: 'Test message'})
|
|
.expect(HTTP_STATUS.FORBIDDEN)
|
|
.execute();
|
|
});
|
|
test('should allow updating an overwrite when unchanged deny bits use permissions the editor lacks', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const manager = members[0];
|
|
const managerRole = await createRole(harness, owner.token, guild.id, {
|
|
name: 'Channel Manager',
|
|
permissions: (Permissions.MANAGE_ROLES | Permissions.MANAGE_CHANNELS).toString(),
|
|
});
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Community Team'});
|
|
await addMemberRole(harness, owner.token, guild.id, manager.userId, managerRole.id);
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, targetRole.id, {
|
|
type: 0,
|
|
allow: '0',
|
|
deny: Permissions.MANAGE_MESSAGES.toString(),
|
|
});
|
|
await createBuilder(harness, manager.token)
|
|
.put(`/channels/${systemChannel.id}/permissions/${targetRole.id}`)
|
|
.body({
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: Permissions.MANAGE_MESSAGES.toString(),
|
|
})
|
|
.expect(HTTP_STATUS.NO_CONTENT)
|
|
.execute();
|
|
const channelData = await getChannel(harness, owner.token, systemChannel.id);
|
|
const overwrite = channelData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(overwrite?.allow).toBe(Permissions.VIEW_CHANNEL.toString());
|
|
expect(overwrite?.deny).toBe(Permissions.MANAGE_MESSAGES.toString());
|
|
});
|
|
test('should require MANAGE_ROLES to create overwrites', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const member = members[0];
|
|
const role = await createRole(harness, owner.token, guild.id, {name: 'Test Role'});
|
|
await createBuilder(harness, member.token)
|
|
.put(`/channels/${systemChannel.id}/permissions/${role.id}`)
|
|
.body({
|
|
type: 0,
|
|
allow: Permissions.SEND_MESSAGES.toString(),
|
|
deny: '0',
|
|
})
|
|
.expect(HTTP_STATUS.FORBIDDEN)
|
|
.execute();
|
|
});
|
|
test('should prioritize member overwrite over role overwrite', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const member = members[0];
|
|
const role = await createRole(harness, owner.token, guild.id, {name: 'Deny Role'});
|
|
await createBuilder<void>(harness, owner.token)
|
|
.put(`/guilds/${guild.id}/members/${member.userId}/roles/${role.id}`)
|
|
.expect(HTTP_STATUS.NO_CONTENT)
|
|
.execute();
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, role.id, {
|
|
type: 0,
|
|
allow: '0',
|
|
deny: Permissions.SEND_MESSAGES.toString(),
|
|
});
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, member.userId, {
|
|
type: 1,
|
|
allow: Permissions.SEND_MESSAGES.toString(),
|
|
deny: '0',
|
|
});
|
|
await createBuilder(harness, member.token)
|
|
.post(`/channels/${systemChannel.id}/messages`)
|
|
.body({content: 'Test message'})
|
|
.execute();
|
|
});
|
|
test('should allow patching overwrites when unchanged denies use permissions the editor lacks', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const manager = members[0];
|
|
const managerRole = await createRole(harness, owner.token, guild.id, {
|
|
name: 'Channel Manager',
|
|
permissions: (Permissions.MANAGE_ROLES | Permissions.MANAGE_CHANNELS).toString(),
|
|
});
|
|
const existingRole = await createRole(harness, owner.token, guild.id, {name: 'Existing Deny Role'});
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Community Team'});
|
|
await addMemberRole(harness, owner.token, guild.id, manager.userId, managerRole.id);
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, existingRole.id, {
|
|
type: 0,
|
|
allow: '0',
|
|
deny: Permissions.MANAGE_MESSAGES.toString(),
|
|
});
|
|
await createBuilder(harness, manager.token)
|
|
.patch(`/channels/${systemChannel.id}`)
|
|
.body({
|
|
permission_overwrites: [
|
|
{
|
|
id: existingRole.id,
|
|
type: 0,
|
|
allow: '0',
|
|
deny: Permissions.MANAGE_MESSAGES.toString(),
|
|
},
|
|
{
|
|
id: targetRole.id,
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: '0',
|
|
},
|
|
],
|
|
})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const channelData = await getChannel(harness, owner.token, systemChannel.id);
|
|
const existingOverwrite = channelData.permission_overwrites?.find((o) => o.id === existingRole.id);
|
|
const targetOverwrite = channelData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(existingOverwrite?.deny).toBe(Permissions.MANAGE_MESSAGES.toString());
|
|
expect(targetOverwrite?.allow).toBe(Permissions.VIEW_CHANNEL.toString());
|
|
});
|
|
test('should allow copying category overwrites that deny permissions the editor lacks', async () => {
|
|
const {owner, members, guild} = await setupTestGuildWithMembers(harness, 1);
|
|
const manager = members[0];
|
|
const managerRole = await createRole(harness, owner.token, guild.id, {
|
|
name: 'Channel Manager',
|
|
permissions: (Permissions.MANAGE_ROLES | Permissions.MANAGE_CHANNELS).toString(),
|
|
});
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Community Team'});
|
|
const category = await createChannel(harness, owner.token, guild.id, 'mods', ChannelTypes.GUILD_CATEGORY);
|
|
const textChannel = await createChannel(harness, owner.token, guild.id, 'bot-moderation-log');
|
|
await addMemberRole(harness, owner.token, guild.id, manager.userId, managerRole.id);
|
|
await createPermissionOverwrite(harness, owner.token, category.id, targetRole.id, {
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: Permissions.MANAGE_MESSAGES.toString(),
|
|
});
|
|
const parentChannel = await getChannel(harness, owner.token, category.id);
|
|
expect(parentChannel.permission_overwrites).toBeDefined();
|
|
await createBuilder(harness, manager.token)
|
|
.patch(`/channels/${textChannel.id}`)
|
|
.body({
|
|
permission_overwrites: parentChannel.permission_overwrites,
|
|
})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const channelData = await getChannel(harness, owner.token, textChannel.id);
|
|
const overwrite = channelData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(overwrite?.allow).toBe(Permissions.VIEW_CHANNEL.toString());
|
|
expect(overwrite?.deny).toBe(Permissions.MANAGE_MESSAGES.toString());
|
|
});
|
|
test('should let an editor change an overwrite that already allows a permission they lack', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const manager = members[0];
|
|
const managerRole = await createRole(harness, owner.token, guild.id, {
|
|
name: 'Queue Manager',
|
|
permissions: Permissions.MANAGE_ROLES.toString(),
|
|
});
|
|
const botRole = await createRole(harness, owner.token, guild.id, {name: 'Bot'});
|
|
await addMemberRole(harness, owner.token, guild.id, manager.userId, managerRole.id);
|
|
await createPermissionOverwrite(harness, owner.token, systemChannel.id, botRole.id, {
|
|
type: 0,
|
|
allow: Permissions.PIN_MESSAGES.toString(),
|
|
deny: '0',
|
|
});
|
|
await createBuilder(harness, manager.token)
|
|
.put(`/channels/${systemChannel.id}/permissions/${botRole.id}`)
|
|
.body({
|
|
type: 0,
|
|
allow: (Permissions.PIN_MESSAGES | Permissions.SEND_MESSAGES).toString(),
|
|
deny: '0',
|
|
})
|
|
.expect(HTTP_STATUS.NO_CONTENT)
|
|
.execute();
|
|
const updated = await getChannel(harness, owner.token, systemChannel.id);
|
|
const botOverwrite = updated.permission_overwrites?.find((o) => o.id === botRole.id);
|
|
expect(botOverwrite?.allow).toBe((Permissions.PIN_MESSAGES | Permissions.SEND_MESSAGES).toString());
|
|
});
|
|
test('should reject an editor granting a permission they lack', async () => {
|
|
const {owner, members, guild, systemChannel} = await setupTestGuildWithMembers(harness, 1);
|
|
const manager = members[0];
|
|
const managerRole = await createRole(harness, owner.token, guild.id, {
|
|
name: 'Queue Manager',
|
|
permissions: Permissions.MANAGE_ROLES.toString(),
|
|
});
|
|
const botRole = await createRole(harness, owner.token, guild.id, {name: 'Bot'});
|
|
await addMemberRole(harness, owner.token, guild.id, manager.userId, managerRole.id);
|
|
await createBuilder(harness, manager.token)
|
|
.put(`/channels/${systemChannel.id}/permissions/${botRole.id}`)
|
|
.body({type: 0, allow: Permissions.PIN_MESSAGES.toString(), deny: '0'})
|
|
.expect(HTTP_STATUS.FORBIDDEN)
|
|
.execute();
|
|
});
|
|
test('should propagate category permission patches only to children that were synced when the category changed', async () => {
|
|
const {owner, guild} = await setupTestGuildWithMembers(harness, 0);
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Readers'});
|
|
const category = await createChannel(harness, owner.token, guild.id, 'restricted', ChannelTypes.GUILD_CATEGORY);
|
|
await createPermissionOverwrite(harness, owner.token, category.id, targetRole.id, {
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: '0',
|
|
});
|
|
const syncedChild = await createBuilder<ChannelResponse>(harness, owner.token)
|
|
.post(`/guilds/${guild.id}/channels`)
|
|
.body({
|
|
name: 'synced-child',
|
|
type: ChannelTypes.GUILD_TEXT,
|
|
parent_id: category.id,
|
|
})
|
|
.execute();
|
|
const unsyncedChild = await createBuilder<ChannelResponse>(harness, owner.token)
|
|
.post(`/guilds/${guild.id}/channels`)
|
|
.body({
|
|
name: 'unsynced-child',
|
|
type: ChannelTypes.GUILD_TEXT,
|
|
parent_id: category.id,
|
|
})
|
|
.execute();
|
|
await createBuilder(harness, owner.token)
|
|
.patch(`/channels/${unsyncedChild.id}`)
|
|
.body({
|
|
permission_overwrites: [
|
|
{
|
|
id: targetRole.id,
|
|
type: 0,
|
|
allow: (Permissions.VIEW_CHANNEL | Permissions.SEND_MESSAGES).toString(),
|
|
deny: '0',
|
|
},
|
|
],
|
|
})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
await createBuilder(harness, owner.token)
|
|
.patch(`/channels/${category.id}`)
|
|
.body({
|
|
permission_overwrites: [
|
|
{
|
|
id: targetRole.id,
|
|
type: 0,
|
|
allow: (Permissions.VIEW_CHANNEL | Permissions.EMBED_LINKS).toString(),
|
|
deny: '0',
|
|
},
|
|
],
|
|
})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const syncedChildData = await getChannel(harness, owner.token, syncedChild.id);
|
|
const unsyncedChildData = await getChannel(harness, owner.token, unsyncedChild.id);
|
|
const syncedOverwrite = syncedChildData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
const unsyncedOverwrite = unsyncedChildData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(syncedOverwrite?.allow).toBe((Permissions.VIEW_CHANNEL | Permissions.EMBED_LINKS).toString());
|
|
expect(unsyncedOverwrite?.allow).toBe((Permissions.VIEW_CHANNEL | Permissions.SEND_MESSAGES).toString());
|
|
});
|
|
test('should propagate category overwrite updates from the single-overwrite endpoint to synced children', async () => {
|
|
const {owner, guild} = await setupTestGuildWithMembers(harness, 0);
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Moderators'});
|
|
const category = await createChannel(harness, owner.token, guild.id, 'ops', ChannelTypes.GUILD_CATEGORY);
|
|
await createPermissionOverwrite(harness, owner.token, category.id, targetRole.id, {
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: '0',
|
|
});
|
|
const childChannel = await createBuilder<ChannelResponse>(harness, owner.token)
|
|
.post(`/guilds/${guild.id}/channels`)
|
|
.body({
|
|
name: 'ops-log',
|
|
type: ChannelTypes.GUILD_TEXT,
|
|
parent_id: category.id,
|
|
})
|
|
.execute();
|
|
await createBuilder(harness, owner.token)
|
|
.put(`/channels/${category.id}/permissions/${targetRole.id}`)
|
|
.body({
|
|
type: 0,
|
|
allow: (Permissions.VIEW_CHANNEL | Permissions.SEND_MESSAGES).toString(),
|
|
deny: '0',
|
|
})
|
|
.expect(HTTP_STATUS.NO_CONTENT)
|
|
.execute();
|
|
const childData = await getChannel(harness, owner.token, childChannel.id);
|
|
const overwrite = childData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(overwrite?.allow).toBe((Permissions.VIEW_CHANNEL | Permissions.SEND_MESSAGES).toString());
|
|
});
|
|
test('should propagate category overwrite deletions from the single-overwrite endpoint to synced children', async () => {
|
|
const {owner, guild} = await setupTestGuildWithMembers(harness, 0);
|
|
const targetRole = await createRole(harness, owner.token, guild.id, {name: 'Moderators'});
|
|
const category = await createChannel(harness, owner.token, guild.id, 'ops', ChannelTypes.GUILD_CATEGORY);
|
|
await createPermissionOverwrite(harness, owner.token, category.id, targetRole.id, {
|
|
type: 0,
|
|
allow: Permissions.VIEW_CHANNEL.toString(),
|
|
deny: '0',
|
|
});
|
|
const childChannel = await createBuilder<ChannelResponse>(harness, owner.token)
|
|
.post(`/guilds/${guild.id}/channels`)
|
|
.body({
|
|
name: 'ops-log',
|
|
type: ChannelTypes.GUILD_TEXT,
|
|
parent_id: category.id,
|
|
})
|
|
.execute();
|
|
await createBuilder(harness, owner.token)
|
|
.delete(`/channels/${category.id}/permissions/${targetRole.id}`)
|
|
.expect(HTTP_STATUS.NO_CONTENT)
|
|
.execute();
|
|
const childData = await getChannel(harness, owner.token, childChannel.id);
|
|
const overwrite = childData.permission_overwrites?.find((o) => o.id === targetRole.id);
|
|
expect(overwrite).toBeUndefined();
|
|
});
|
|
});
|