fix(guild): treat very high as high without phone verification (#3095)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-01 20:33:02 +02:00
1 parent d691047884
commit 2df82b2b5e
28 files changed
+289 -18

No files matched your search

@@ -434,7 +434,11 @@ export class GuildDiscoveryService extends IGuildDiscoveryService {
member_count: hit.memberCount,
online_count: 0,
features: hit.features,
verification_level: getEffectiveGuildVerificationLevel(hit.verificationLevel, hit.isDiscoverable),
verification_level: getEffectiveGuildVerificationLevel(
hit.verificationLevel,
hit.isDiscoverable,
Config.instance.phoneVerificationEnabled,
),
}));
const total = results.total;
if (guilds.length > 0) {
@@ -2,6 +2,7 @@
import type {ChannelID, GuildID, RoleID, UserID} from '@app/api/BrandedTypes';
import {createChannelID, createGuildID, createRoleID, guildIdToRoleId} from '@app/api/BrandedTypes';
import {Config} from '@app/api/Config';
import type {IChannelRepository} from '@app/api/channel/IChannelRepository';
import {
type ChannelFollowerRemovalCopyMode,
@@ -481,6 +482,17 @@ export class GuildOperationsService {
ValidationErrorCodes.DISCOVERABLE_GUILD_VERIFICATION_LEVEL_TOO_LOW,
);
}
if (
data.verification_level === GuildVerificationLevel.VERY_HIGH &&
data.verification_level !== currentGuild.verificationLevel &&
!Config.instance.phoneVerificationEnabled
) {
throw InputValidationError.fromCode('verification_level', ValidationErrorCodes.VALUE_MUST_BE_INTEGER_IN_RANGE, {
name: 'verification_level',
minValue: GuildVerificationLevel.NONE,
maxValue: GuildVerificationLevel.HIGH,
});
}
const isMfaLevelChange = data.mfa_level !== undefined && data.mfa_level !== currentGuild.mfaLevel;
if (isMfaLevelChange) {
const isOwner = guildData.owner_id === userId.toString();
@@ -1177,7 +1189,12 @@ export class GuildOperationsService {
private sanitiseTemplateGuildSettings(template?: TemplateSerializedGuild): TemplateGuildSettings {
return {
verificationLevel: this.clampTemplateSetting(template?.verification_level, 0, 4, 0),
verificationLevel: this.clampTemplateSetting(
template?.verification_level,
GuildVerificationLevel.NONE,
Config.instance.phoneVerificationEnabled ? GuildVerificationLevel.VERY_HIGH : GuildVerificationLevel.HIGH,
GuildVerificationLevel.NONE,
),
explicitContentFilter: this.clampTemplateSetting(template?.explicit_content_filter, 0, 2, 0),
defaultMessageNotifications: this.clampTemplateSetting(template?.default_message_notifications, 0, 1, 0),
systemChannelFlags: (template?.system_channel_flags ?? 0) & SUPPORTED_SYSTEM_CHANNEL_FLAGS,
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createTestAccount} from '@app/api/auth/tests/AuthTestUtils';
import {Config} from '@app/api/Config';
import {createGuild, updateGuild} from '@app/api/guild/tests/GuildTestUtils';
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 {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants';
import {GuildVerificationLevel} from '@fluxer/constants/src/GuildConstants';
import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
import {afterAll, afterEach, beforeAll, beforeEach, describe, expect, test} from 'vitest';
describe('Guild verification level without phone verification', () => {
let harness: ApiTestHarness;
let savedPhoneVerificationEnabled: boolean;
beforeAll(async () => {
harness = await createApiTestHarness();
});
afterAll(async () => {
await harness?.shutdown();
});
beforeEach(async () => {
await harness.reset();
savedPhoneVerificationEnabled = Config.instance.phoneVerificationEnabled;
});
afterEach(() => {
Config.instance.phoneVerificationEnabled = savedPhoneVerificationEnabled;
});
test('rejects very high when phone verification is unavailable', async () => {
Config.instance.phoneVerificationEnabled = false;
const account = await createTestAccount(harness);
const guild = await createGuild(harness, account.token, 'No Phone Guild');
await createBuilder(harness, account.token)
.patch(`/guilds/${guild.id}`)
.body({verification_level: GuildVerificationLevel.VERY_HIGH})
.expect(HTTP_STATUS.BAD_REQUEST, APIErrorCodes.INVALID_FORM_BODY)
.execute();
const updated = await updateGuild(harness, account.token, guild.id, {
verification_level: GuildVerificationLevel.HIGH,
});
expect(updated.verification_level).toBe(GuildVerificationLevel.HIGH);
});
test('accepts very high when phone verification is available', async () => {
Config.instance.phoneVerificationEnabled = true;
const account = await createTestAccount(harness);
const guild = await createGuild(harness, account.token, 'Phone Guild');
const updated = await updateGuild(harness, account.token, guild.id, {
verification_level: GuildVerificationLevel.VERY_HIGH,
});
expect(updated.verification_level).toBe(GuildVerificationLevel.VERY_HIGH);
});
test('accepts an unchanged stored very high when phone verification is unavailable', async () => {
Config.instance.phoneVerificationEnabled = true;
const account = await createTestAccount(harness);
const guild = await createGuild(harness, account.token, 'Stored Phone Guild');
await updateGuild(harness, account.token, guild.id, {verification_level: GuildVerificationLevel.VERY_HIGH});
Config.instance.phoneVerificationEnabled = false;
const updated = await updateGuild(harness, account.token, guild.id, {
name: 'Renamed Phone Guild',
verification_level: GuildVerificationLevel.VERY_HIGH,
});
expect(updated.name).toBe('Renamed Phone Guild');
expect(updated.verification_level).toBe(GuildVerificationLevel.VERY_HIGH);
});
test('clamps a template level to high when phone verification is unavailable', async () => {
Config.instance.phoneVerificationEnabled = false;
const account = await createTestAccount(harness);
const guild = await createBuilder<GuildResponse>(harness, account.token)
.post('/guilds')
.body({
name: 'Template Guild',
template: {
name: 'Template Source',
description: null,
verification_level: GuildVerificationLevel.VERY_HIGH,
default_message_notifications: 0,
explicit_content_filter: 0,
system_channel_id: 1001,
afk_timeout: 300,
system_channel_flags: 0,
roles: [{id: 0, name: '@everyone', permissions: '0'}],
channels: [{id: 1001, type: ChannelTypes.GUILD_TEXT, name: 'general', position: 0}],
},
})
.execute();
expect(guild.verification_level).toBe(GuildVerificationLevel.HIGH);
});
});