refactor: simplify account standing and verification levels (#3130)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-02 18:17:41 +02:00
1 parent 1abde06824
commit 1ec8f31253
488 files changed
+10390 -47117

No files matched your search

@@ -1,13 +1,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createUserID} from '@app/api/BrandedTypes';
import {Config} from '@app/api/Config';
import {User} from '@app/api/models/User';
import {checkGuildVerificationWithResponse} from '@app/api/utils/GuildVerificationUtils';
import {GuildFeatures, GuildVerificationLevel} from '@fluxer/constants/src/GuildConstants';
import {ProfileFieldPrivacyFlags} from '@fluxer/constants/src/UserConstants';
import {GuildEmailVerificationRequiredError} from '@fluxer/errors/src/domains/auth/EmailVerificationRequiredError';
import {GuildPhoneVerificationRequiredError} from '@fluxer/errors/src/domains/auth/GuildPhoneVerificationRequiredError';
import {GuildVerificationRequiredError} from '@fluxer/errors/src/domains/guild/GuildVerificationRequiredError';
import type {GuildMemberResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas';
import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
@@ -17,7 +15,7 @@ const TEST_USER_ID = createUserID(175928847299117063n);
const TEST_OWNER_ID = createUserID(275928847299117063n);
const TEST_JOINED_AT = new Date('2025-01-01T00:00:00.000Z').toISOString();
function createUser(params?: {emailVerified?: boolean; hasVerifiedPhone?: boolean}): User {
function createUser(params?: {emailVerified?: boolean}): User {
return new User({
user_id: TEST_USER_ID,
username: 'member',
@@ -27,7 +25,6 @@ function createUser(params?: {emailVerified?: boolean; hasVerifiedPhone?: boolea
system: false,
email: '[email protected]',
email_verified: params?.emailVerified ?? false,
has_verified_phone: params?.hasVerifiedPhone ?? false,
email_bounced: false,
password_hash: 'hashed',
password_last_changed_at: null,
@@ -56,7 +53,6 @@ function createUser(params?: {emailVerified?: boolean; hasVerifiedPhone?: boolea
stripe_subscription_id: null,
stripe_customer_id: null,
has_ever_purchased: false,
suspicious_activity_flags: 0,
terms_agreed_at: null,
privacy_agreed_at: null,
last_active_at: null,
@@ -158,50 +154,22 @@ describe('GuildVerificationUtils', () => {
}),
).not.toThrow();
});
it('allows very high verification with only a verified phone', () => {
it('treats a stored level above high as high', () => {
const guild = createGuildResponse([]);
guild.verification_level = GuildVerificationLevel.VERY_HIGH;
Object.assign(guild, {verification_level: 4});
expect(() =>
checkGuildVerificationWithResponse({
user: createUser({emailVerified: false, hasVerifiedPhone: true}),
guild,
member: createMemberResponse(new Date().toISOString()),
}),
).not.toThrow();
});
it('rejects very high verification without a verified phone', () => {
const guild = createGuildResponse([]);
guild.verification_level = GuildVerificationLevel.VERY_HIGH;
expect(() =>
checkGuildVerificationWithResponse({
user: createUser({emailVerified: true, hasVerifiedPhone: false}),
user: createUser({emailVerified: true}),
guild,
member,
}),
).toThrow(GuildPhoneVerificationRequiredError);
});
it('treats very high as high when phone verification is unavailable', () => {
const saved = Config.instance.phoneVerificationEnabled;
Config.instance.phoneVerificationEnabled = false;
try {
const guild = createGuildResponse([]);
guild.verification_level = GuildVerificationLevel.VERY_HIGH;
expect(() =>
checkGuildVerificationWithResponse({
user: createUser({emailVerified: true, hasVerifiedPhone: false}),
guild,
member,
}),
).not.toThrow();
expect(() =>
checkGuildVerificationWithResponse({
user: createUser({emailVerified: true, hasVerifiedPhone: false}),
guild,
member: createMemberResponse(new Date().toISOString()),
}),
).toThrow(GuildVerificationRequiredError);
} finally {
Config.instance.phoneVerificationEnabled = saved;
}
).not.toThrow();
expect(() =>
checkGuildVerificationWithResponse({
user: createUser({emailVerified: true}),
guild,
member: createMemberResponse(new Date().toISOString()),
}),
).toThrow(GuildVerificationRequiredError);
});
});
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createRoleIDSet, createUserID, type RoleID, type UserID} from '@app/api/BrandedTypes';
import {Config} from '@app/api/Config';
import type {Guild} from '@app/api/models/Guild';
import type {GuildMember} from '@app/api/models/GuildMember';
import type {User} from '@app/api/models/User';
@@ -11,7 +10,6 @@ import {
getEffectiveGuildVerificationLevel,
} from '@fluxer/constants/src/GuildConstants';
import {GuildEmailVerificationRequiredError} from '@fluxer/errors/src/domains/auth/EmailVerificationRequiredError';
import {GuildPhoneVerificationRequiredError} from '@fluxer/errors/src/domains/auth/GuildPhoneVerificationRequiredError';
import {AccountTooNewForGuildError} from '@fluxer/errors/src/domains/guild/AccountTooNewForGuildError';
import {GuildVerificationRequiredError} from '@fluxer/errors/src/domains/guild/GuildVerificationRequiredError';
import type {GuildMemberResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas';
@@ -41,12 +39,6 @@ function checkGuildVerification(params: VerificationParams): void {
if (memberRoles && memberRoles.size > 0) {
return;
}
if (verificationLevel === GuildVerificationLevel.VERY_HIGH) {
if (!user.hasVerifiedPhone) {
throw new GuildPhoneVerificationRequiredError();
}
return;
}
if (!user.email) {
throw new GuildVerificationRequiredError('You need to claim your account to send messages in this guild.');
}
@@ -91,7 +83,6 @@ export function checkGuildVerificationWithGuildModel({
verificationLevel: getEffectiveGuildVerificationLevel(
guild.verificationLevel ?? GuildVerificationLevel.NONE,
guild.features.has(GuildFeatures.DISCOVERABLE),
Config.instance.phoneVerificationEnabled,
),
memberJoinedAt: member.joinedAt,
memberRoles: member.roleIds,
@@ -117,7 +108,6 @@ export function checkGuildVerificationWithResponse({
verificationLevel: getEffectiveGuildVerificationLevel(
guild.verification_level ?? GuildVerificationLevel.NONE,
(guild.features ?? []).includes(GuildFeatures.DISCOVERABLE),
Config.instance.phoneVerificationEnabled,
),
memberJoinedAt: member.joined_at,
memberRoles: createRoleIDSet(new Set(member.roles.map((roleId) => BigInt(roleId)))),