mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
fix(api): correct guild permission and mfa checks (#2499)
This commit is contained in:
1 parent
f392636857
commit
908e1b8bd4
12 files changed
+303
-86
No files matched your search
@@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {JoinSourceTypes} from '@fluxer/constants/src/GuildConstants';
|
||||
import {Permissions} from '@fluxer/constants/src/ChannelConstants';
|
||||
import {GuildMFALevel, JoinSourceTypes} from '@fluxer/constants/src/GuildConstants';
|
||||
import type {GuildMemberSearchResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSearchSchemas';
|
||||
import {afterEach, beforeEach, describe, expect, test} from 'vitest';
|
||||
import {createTestAccount} from '../../auth/tests/AuthTestUtils';
|
||||
import {createTestAccount, type TestAccount, totpCodeNow} from '../../auth/tests/AuthTestUtils';
|
||||
import {createGuildID, createUserID} from '../../BrandedTypes';
|
||||
import {GuildRepository} from '../../guild/repositories/GuildRepository';
|
||||
import {
|
||||
@@ -17,7 +18,37 @@ import {
|
||||
} from '../../guild/tests/GuildTestUtils';
|
||||
import {type ApiTestHarness, createApiTestHarness} from '../../test/ApiTestHarness';
|
||||
import {HTTP_STATUS, wait} from '../../test/TestConstants';
|
||||
import {createBuilder} from '../../test/TestRequestBuilder';
|
||||
import {createBuilder, createBuilderWithoutAuth} from '../../test/TestRequestBuilder';
|
||||
|
||||
const TOTP_SECRET = 'JBSWY3DPEHPK3PXP';
|
||||
|
||||
async function elevateGuildMfaLevel(harness: ApiTestHarness, owner: TestAccount, guildId: string): Promise<void> {
|
||||
await createBuilder(harness, owner.token)
|
||||
.post('/users/@me/mfa/totp/enable')
|
||||
.body({secret: TOTP_SECRET, code: totpCodeNow(TOTP_SECRET), password: owner.password})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
const loginResp = await createBuilderWithoutAuth<{
|
||||
mfa: true;
|
||||
ticket: string;
|
||||
}>(harness)
|
||||
.post('/auth/login')
|
||||
.body({email: owner.email, password: owner.password})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
const mfaResp = await createBuilderWithoutAuth<{
|
||||
token: string;
|
||||
}>(harness)
|
||||
.post('/auth/login/mfa/totp')
|
||||
.body({code: totpCodeNow(TOTP_SECRET), ticket: loginResp.ticket})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
await createBuilder(harness, mfaResp.token)
|
||||
.patch(`/guilds/${guildId}`)
|
||||
.body({mfa_level: GuildMFALevel.ELEVATED, mfa_method: 'totp', mfa_code: totpCodeNow(TOTP_SECRET)})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
}
|
||||
|
||||
async function indexGuildMembers(harness: ApiTestHarness, guildId: string): Promise<void> {
|
||||
await createBuilder<{
|
||||
@@ -325,6 +356,39 @@ describe('Guild Member Search Endpoint', () => {
|
||||
.execute();
|
||||
expect(result.members.length).toBeGreaterThan(0);
|
||||
});
|
||||
test('rejects an elevated-permission holder without MFA in an elevated guild (400)', async () => {
|
||||
const {owner, members, guild} = await setupTestGuildWithMembers(harness, 1);
|
||||
const moderator = members[0]!;
|
||||
const banRole = await createRole(harness, owner.token, guild.id, {
|
||||
name: 'Ban Members',
|
||||
permissions: Permissions.BAN_MEMBERS.toString(),
|
||||
});
|
||||
await updateMember(harness, owner.token, guild.id, moderator.userId, {roles: [banRole.id]});
|
||||
await indexGuildMembers(harness, guild.id);
|
||||
await elevateGuildMfaLevel(harness, owner, guild.id);
|
||||
await createBuilder(harness, moderator.token)
|
||||
.post(`/guilds/${guild.id}/members-search`)
|
||||
.body({})
|
||||
.expect(HTTP_STATUS.BAD_REQUEST, 'TWO_FACTOR_REQUIRED')
|
||||
.execute();
|
||||
});
|
||||
test('allows a MANAGE_NICKNAMES holder without MFA in an elevated guild', async () => {
|
||||
const {owner, members, guild} = await setupTestGuildWithMembers(harness, 1);
|
||||
const nicknameManager = members[0]!;
|
||||
const nicknameRole = await createRole(harness, owner.token, guild.id, {
|
||||
name: 'Manage Nicknames',
|
||||
permissions: Permissions.MANAGE_NICKNAMES.toString(),
|
||||
});
|
||||
await updateMember(harness, owner.token, guild.id, nicknameManager.userId, {roles: [nicknameRole.id]});
|
||||
await indexGuildMembers(harness, guild.id);
|
||||
await elevateGuildMfaLevel(harness, owner, guild.id);
|
||||
const result = await createBuilder<GuildMemberSearchResponse>(harness, nicknameManager.token)
|
||||
.post(`/guilds/${guild.id}/members-search`)
|
||||
.body({})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
expect(result.members.length).toBeGreaterThan(0);
|
||||
});
|
||||
test('returns 404 for non-guild-member', async () => {
|
||||
const {guild} = await setupTestGuildWithMembers(harness, 1);
|
||||
const outsider = await createTestAccount(harness);
|
||||
|
||||
Reference in new issue
Block a user