mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
176 lines
5.3 KiB
TypeScript
176 lines
5.3 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
|
|
import {afterAll, beforeAll, beforeEach, describe, expect, it} from 'vitest';
|
|
import {setInjectedRegistrationRiskEvaluator} from '../../middleware/ServiceMiddleware';
|
|
import {
|
|
RecommendedAction,
|
|
RiskConfidence,
|
|
RiskDecisionMethod,
|
|
RiskLevel,
|
|
type RiskLevel as RiskLevelType,
|
|
} from '../../risk/RiskTypes';
|
|
import type {ApiTestHarness} from '../../test/ApiTestHarness';
|
|
import {createBuilder, createBuilderWithoutAuth} from '../../test/TestRequestBuilder';
|
|
import type {IRegistrationRiskEvaluator} from '../services/IRegistrationRiskEvaluator';
|
|
import {
|
|
createAuthHarness,
|
|
createTestAccount,
|
|
createUniqueEmail,
|
|
createUniqueUsername,
|
|
loginAccount,
|
|
registerUser,
|
|
} from './AuthTestUtils';
|
|
|
|
function createStaticRiskEvaluator(params: {
|
|
level: RiskLevelType;
|
|
riskScore: number;
|
|
recommendedAction: RecommendedAction;
|
|
}): IRegistrationRiskEvaluator {
|
|
return {
|
|
async evaluate() {
|
|
return {
|
|
level: params.level,
|
|
recommendedAction: params.recommendedAction,
|
|
assessment: {
|
|
suspicious: params.level !== RiskLevel.Low,
|
|
level: params.level,
|
|
confidence: RiskConfidence.High,
|
|
riskScore: params.riskScore,
|
|
reasoning: 'test risk verdict',
|
|
recommendedAction: params.recommendedAction,
|
|
method: RiskDecisionMethod.Noop,
|
|
modelUsed: 'test',
|
|
rounds: 0,
|
|
elapsedMs: 0,
|
|
signals: {},
|
|
},
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
async function createGuildInvite(harness: ApiTestHarness): Promise<{
|
|
guildId: string;
|
|
inviteCode: string;
|
|
ownerToken: string;
|
|
}> {
|
|
let owner = await createTestAccount(harness);
|
|
await createBuilderWithoutAuth(harness)
|
|
.post(`/test/users/${owner.userId}/acls`)
|
|
.body({
|
|
acls: ['*'],
|
|
})
|
|
.expect(200)
|
|
.execute();
|
|
owner = await loginAccount(harness, owner);
|
|
const guild = await createBuilder<GuildResponse>(harness, owner.token)
|
|
.post('/guilds')
|
|
.body({
|
|
name: `InviteGuild-${Date.now()}`,
|
|
})
|
|
.execute();
|
|
if (!guild.system_channel_id) {
|
|
throw new Error('Guild creation did not return a system_channel_id');
|
|
}
|
|
const invite = await createBuilder<{
|
|
code: string;
|
|
}>(harness, owner.token)
|
|
.post(`/channels/${guild.system_channel_id}/invites`)
|
|
.body({
|
|
max_uses: 0,
|
|
max_age: 0,
|
|
unique: false,
|
|
temporary: false,
|
|
})
|
|
.execute();
|
|
return {guildId: guild.id, inviteCode: invite.code, ownerToken: owner.token};
|
|
}
|
|
|
|
describe('Auth registration invite auto-join risk gating', () => {
|
|
let harness: ApiTestHarness;
|
|
beforeAll(async () => {
|
|
harness = await createAuthHarness();
|
|
});
|
|
beforeEach(async () => {
|
|
setInjectedRegistrationRiskEvaluator(undefined);
|
|
await harness.reset();
|
|
});
|
|
afterAll(async () => {
|
|
setInjectedRegistrationRiskEvaluator(undefined);
|
|
await harness?.shutdown();
|
|
});
|
|
it('auto-joins the invite on medium-risk registrations', async () => {
|
|
const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
|
|
setInjectedRegistrationRiskEvaluator(
|
|
createStaticRiskEvaluator({
|
|
level: RiskLevel.Medium,
|
|
riskScore: 40,
|
|
recommendedAction: RecommendedAction.RequireVerifiedEmail,
|
|
}),
|
|
);
|
|
const registration = await registerUser(harness, {
|
|
email: createUniqueEmail('invite-medium'),
|
|
username: createUniqueUsername('invite_medium'),
|
|
global_name: 'Invite Medium',
|
|
password: 'StrongPassword!123',
|
|
date_of_birth: '2000-01-01',
|
|
consent: true,
|
|
invite_code: inviteCode,
|
|
});
|
|
const memberLookup = await createBuilder(harness, ownerToken)
|
|
.get(`/guilds/${guildId}/members/${registration.user_id}`)
|
|
.expect(200)
|
|
.executeWithResponse();
|
|
expect(memberLookup.response.status).toBe(200);
|
|
});
|
|
it('auto-joins the invite on high-risk registrations', async () => {
|
|
const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
|
|
setInjectedRegistrationRiskEvaluator(
|
|
createStaticRiskEvaluator({
|
|
level: RiskLevel.High,
|
|
riskScore: 70,
|
|
recommendedAction: RecommendedAction.RequireOutboundPhone,
|
|
}),
|
|
);
|
|
const registration = await registerUser(harness, {
|
|
email: createUniqueEmail('invite-high'),
|
|
username: createUniqueUsername('invite_high'),
|
|
global_name: 'Invite High',
|
|
password: 'StrongPassword!123',
|
|
date_of_birth: '2000-01-01',
|
|
consent: true,
|
|
invite_code: inviteCode,
|
|
});
|
|
const memberLookup = await createBuilder(harness, ownerToken)
|
|
.get(`/guilds/${guildId}/members/${registration.user_id}`)
|
|
.expect(200)
|
|
.executeWithResponse();
|
|
expect(memberLookup.response.status).toBe(200);
|
|
});
|
|
it('does not auto-join the invite on very-high-risk registrations', async () => {
|
|
const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
|
|
setInjectedRegistrationRiskEvaluator(
|
|
createStaticRiskEvaluator({
|
|
level: RiskLevel.VeryHigh,
|
|
riskScore: 90,
|
|
recommendedAction: RecommendedAction.RequireInboundPhone,
|
|
}),
|
|
);
|
|
const registration = await registerUser(harness, {
|
|
email: createUniqueEmail('invite-veryhigh'),
|
|
username: createUniqueUsername('invite_veryhigh'),
|
|
global_name: 'Invite VeryHigh',
|
|
password: 'StrongPassword!123',
|
|
date_of_birth: '2000-01-01',
|
|
consent: true,
|
|
invite_code: inviteCode,
|
|
});
|
|
const memberLookup = await createBuilder(harness, ownerToken)
|
|
.get(`/guilds/${guildId}/members/${registration.user_id}`)
|
|
.expect(404)
|
|
.executeWithResponse();
|
|
expect(memberLookup.response.status).toBe(404);
|
|
});
|
|
});
|