mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
148 lines
5.8 KiB
TypeScript
148 lines
5.8 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import {createTestAccount} from '@app/api/auth/tests/AuthTestUtils';
|
|
import {
|
|
createOAuth2Application,
|
|
createUniqueApplicationName,
|
|
deleteOAuth2Application,
|
|
getOAuth2Application,
|
|
listOAuth2Applications,
|
|
} from '@app/api/oauth/tests/OAuth2TestUtils';
|
|
import {type ApiTestHarness, createApiTestHarness} from '@app/api/test/ApiTestHarness';
|
|
import {HTTP_STATUS} from '@app/api/test/TestConstants';
|
|
import {createBuilder, createBuilderWithoutAuth} from '@app/api/test/TestRequestBuilder';
|
|
import type {MessageResponse} from '@fluxer/schema/src/domains/message/MessageResponseSchemas';
|
|
import {beforeEach, describe, expect, test} from 'vitest';
|
|
|
|
describe('OAuth2 Application Delete', () => {
|
|
let harness: ApiTestHarness;
|
|
beforeEach(async () => {
|
|
harness = await createApiTestHarness();
|
|
});
|
|
test('deletes application and invalidates bot token', async () => {
|
|
const account = await createTestAccount(harness);
|
|
const appName = createUniqueApplicationName();
|
|
const createResult = await createOAuth2Application(harness, account.token, {
|
|
name: appName,
|
|
redirect_uris: ['https://example.com/callback'],
|
|
});
|
|
await createBuilder(harness, `Bot ${createResult.botToken}`).get('/users/@me').expect(HTTP_STATUS.OK).execute();
|
|
await deleteOAuth2Application(harness, account.token, createResult.application.id, account.password);
|
|
await createBuilder(harness, account.token)
|
|
.get(`/oauth2/applications/${createResult.application.id}`)
|
|
.expect(HTTP_STATUS.NOT_FOUND)
|
|
.execute();
|
|
const applications = await listOAuth2Applications(harness, account.token);
|
|
const found = applications.find((app) => app.id === createResult.application.id);
|
|
expect(found).toBeUndefined();
|
|
await createBuilder(harness, `Bot ${createResult.botToken}`)
|
|
.get('/users/@me')
|
|
.expect(HTTP_STATUS.UNAUTHORIZED)
|
|
.execute();
|
|
const botUser = await createBuilder<{
|
|
id: string;
|
|
username: string;
|
|
discriminator: string;
|
|
avatar: string | null;
|
|
}>(harness, account.token)
|
|
.get(`/users/${createResult.botUserId}`)
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
expect(botUser.username).toBe('DeletedUser');
|
|
expect(botUser.discriminator).toBe('0000');
|
|
expect(botUser.avatar).toBeNull();
|
|
});
|
|
test('keeps bot-authored messages readable after deleting the application', async () => {
|
|
const account = await createTestAccount(harness);
|
|
const createResult = await createOAuth2Application(harness, account.token, {
|
|
name: createUniqueApplicationName(),
|
|
});
|
|
const guild = await createBuilder<{
|
|
id: string;
|
|
system_channel_id?: string;
|
|
}>(harness, account.token)
|
|
.post('/guilds')
|
|
.body({name: `Bot Message Retention ${Date.now()}`})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const channelId = guild.system_channel_id;
|
|
if (!channelId) {
|
|
throw new Error('Guild response missing system channel');
|
|
}
|
|
const seeded = await createBuilder<{
|
|
messages: Array<{
|
|
message_id: string;
|
|
}>;
|
|
}>(harness, '')
|
|
.post('/test/messages/seed')
|
|
.body({
|
|
channel_id: channelId,
|
|
author_id: createResult.botUserId,
|
|
clear_existing: true,
|
|
messages: [{content: 'bot message before deletion'}],
|
|
})
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const botMessageId = seeded.messages[0]?.message_id;
|
|
if (!botMessageId) {
|
|
throw new Error('Seeded message response missing message id');
|
|
}
|
|
await deleteOAuth2Application(harness, account.token, createResult.application.id, account.password);
|
|
const messages = await createBuilder<Array<MessageResponse>>(harness, account.token)
|
|
.get(`/channels/${channelId}/messages`)
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
const foundMessage = messages.find((message) => message.id === botMessageId);
|
|
expect(foundMessage).toBeDefined();
|
|
expect(foundMessage?.author.id).toBe(createResult.botUserId);
|
|
expect(foundMessage?.author.bot).toBe(true);
|
|
expect(foundMessage?.author.username).toBe('DeletedUser');
|
|
expect(foundMessage?.author.discriminator).toBe('0000');
|
|
const authorCount = await createBuilderWithoutAuth<{
|
|
count: number;
|
|
}>(harness)
|
|
.get(`/test/users/${createResult.botUserId}/messages/count`)
|
|
.expect(HTTP_STATUS.OK)
|
|
.execute();
|
|
expect(authorCount.count).toBe(1);
|
|
});
|
|
test('enforces access control', async () => {
|
|
const owner = await createTestAccount(harness);
|
|
const otherUser = await createTestAccount(harness);
|
|
const createResult = await createOAuth2Application(harness, owner.token, {
|
|
name: createUniqueApplicationName(),
|
|
});
|
|
await createBuilder(harness, otherUser.token)
|
|
.delete(`/oauth2/applications/${createResult.application.id}`)
|
|
.body({password: otherUser.password})
|
|
.expect(HTTP_STATUS.FORBIDDEN)
|
|
.execute();
|
|
const application = await getOAuth2Application(harness, owner.token, createResult.application.id);
|
|
expect(application.id).toBe(createResult.application.id);
|
|
});
|
|
test('requires sudo verification', async () => {
|
|
const account = await createTestAccount(harness);
|
|
const createResult = await createOAuth2Application(harness, account.token, {
|
|
name: createUniqueApplicationName(),
|
|
});
|
|
await createBuilder(harness, account.token)
|
|
.delete(`/oauth2/applications/${createResult.application.id}`)
|
|
.body({})
|
|
.expect(HTTP_STATUS.FORBIDDEN, 'SUDO_MODE_REQUIRED')
|
|
.execute();
|
|
const application = await getOAuth2Application(harness, account.token, createResult.application.id);
|
|
expect(application.id).toBe(createResult.application.id);
|
|
});
|
|
test('rejects wrong password', async () => {
|
|
const account = await createTestAccount(harness);
|
|
const createResult = await createOAuth2Application(harness, account.token, {
|
|
name: createUniqueApplicationName(),
|
|
});
|
|
await createBuilder(harness, account.token)
|
|
.delete(`/oauth2/applications/${createResult.application.id}`)
|
|
.body({password: 'wrong-password'})
|
|
.expect(HTTP_STATUS.BAD_REQUEST, 'INVALID_FORM_BODY')
|
|
.execute();
|
|
});
|
|
});
|