mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
perf(message): reuse the resolved channel for dm send checks (#2197)
This commit is contained in:
1 parent
d5fb495e19
commit
b5496097d2
4 files changed
+50
-16
No files matched your search
@@ -37,6 +37,18 @@ export interface ChannelAuthOptions {
|
||||
validateNsfw: boolean;
|
||||
}
|
||||
|
||||
interface DMSendPermissionsByChannelParams {
|
||||
channel: Channel;
|
||||
userId: UserID;
|
||||
}
|
||||
|
||||
interface DMSendPermissionsByChannelIdParams {
|
||||
channelId: ChannelID;
|
||||
userId: UserID;
|
||||
}
|
||||
|
||||
type DMSendPermissionsParams = DMSendPermissionsByChannelParams | DMSendPermissionsByChannelIdParams;
|
||||
|
||||
export abstract class BaseChannelAuthService {
|
||||
protected abstract readonly options: ChannelAuthOptions;
|
||||
protected dmPermissionValidator: DMPermissionValidator;
|
||||
@@ -136,8 +148,10 @@ export abstract class BaseChannelAuthService {
|
||||
};
|
||||
}
|
||||
|
||||
async validateDMSendPermissions({channelId, userId}: {channelId: ChannelID; userId: UserID}): Promise<void> {
|
||||
const channel = await this.channelRepository.channelData.findUnique(channelId);
|
||||
async validateDMSendPermissions(params: DMSendPermissionsParams): Promise<void> {
|
||||
const {userId} = params;
|
||||
const channel =
|
||||
'channel' in params ? params.channel : await this.channelRepository.channelData.findUnique(params.channelId);
|
||||
if (!channel) throw new UnknownChannelError();
|
||||
if (channel.type === ChannelTypes.GROUP_DM || channel.type === ChannelTypes.DM_PERSONAL_NOTES) {
|
||||
return;
|
||||
|
||||
@@ -47,12 +47,7 @@ export class MessageInteractionService {
|
||||
guildRepository,
|
||||
gatewayService,
|
||||
);
|
||||
this.pinAuthService = new MessagePinAuthService(
|
||||
channelRepository,
|
||||
userRepository,
|
||||
guildRepository,
|
||||
gatewayService,
|
||||
);
|
||||
this.pinAuthService = new MessagePinAuthService(channelRepository, userRepository, guildRepository, gatewayService);
|
||||
this.readStateService = new MessageReadStateService(gatewayService);
|
||||
this.pinService = new MessagePinService(
|
||||
gatewayService,
|
||||
@@ -110,7 +105,7 @@ export class MessageInteractionService {
|
||||
}): Promise<void> {
|
||||
const authChannel = await this.authService.getChannelAuthenticated({userId, channelId});
|
||||
if (!authChannel.guild && authChannel.channel.type !== ChannelTypes.DM_PERSONAL_NOTES) {
|
||||
await this.authService.validateDMSendPermissions({channelId, userId});
|
||||
await this.authService.validateDMSendPermissions({channel: authChannel.channel, userId});
|
||||
}
|
||||
await this.pinService.pinMessage({authChannel, messageId, userId, requestCache});
|
||||
}
|
||||
@@ -128,7 +123,7 @@ export class MessageInteractionService {
|
||||
}): Promise<void> {
|
||||
const authChannel = await this.authService.getChannelAuthenticated({userId, channelId});
|
||||
if (!authChannel.guild && authChannel.channel.type !== ChannelTypes.DM_PERSONAL_NOTES) {
|
||||
await this.authService.validateDMSendPermissions({channelId, userId});
|
||||
await this.authService.validateDMSendPermissions({channel: authChannel.channel, userId});
|
||||
}
|
||||
await this.pinService.unpinMessage({authChannel, messageId, userId, requestCache});
|
||||
}
|
||||
|
||||
@@ -238,7 +238,6 @@ export class MessageSendService {
|
||||
user,
|
||||
checkPermission,
|
||||
hasPermission,
|
||||
channelId,
|
||||
}: {
|
||||
guild: GuildResponse | null;
|
||||
member: GuildMemberResponse | null;
|
||||
@@ -247,7 +246,6 @@ export class MessageSendService {
|
||||
user: User;
|
||||
checkPermission: (permission: bigint) => Promise<void>;
|
||||
hasPermission: (permission: bigint) => Promise<boolean>;
|
||||
channelId: ChannelID;
|
||||
}): Promise<{
|
||||
canEmbedLinks: boolean;
|
||||
canMentionEveryone: boolean;
|
||||
@@ -286,7 +284,7 @@ export class MessageSendService {
|
||||
}
|
||||
await this.deps.channelAuthService.checkGuildVerification({user, guild, member});
|
||||
} else if (channel.type === ChannelTypes.DM || channel.type === ChannelTypes.GROUP_DM) {
|
||||
await this.deps.channelAuthService.validateDMSendPermissions({channelId, userId: user.id});
|
||||
await this.deps.channelAuthService.validateDMSendPermissions({channel, userId: user.id});
|
||||
}
|
||||
return {canEmbedLinks, canMentionEveryone, canAttachFiles};
|
||||
}
|
||||
@@ -320,7 +318,6 @@ export class MessageSendService {
|
||||
user,
|
||||
checkPermission,
|
||||
hasPermission,
|
||||
channelId,
|
||||
});
|
||||
this.deps.validationService.ensureTextChannel(channel);
|
||||
const isForwardMessage = this.ensureMessageRequestIsValid({user, data, guildFeatures: guild?.features ?? null});
|
||||
@@ -809,7 +806,6 @@ export class MessageSendService {
|
||||
user,
|
||||
checkPermission,
|
||||
hasPermission,
|
||||
channelId,
|
||||
});
|
||||
const needsSlowmodeCheck = guild && channel.rateLimitPerUser && channel.rateLimitPerUser > 0 && !user.isBot;
|
||||
const slowmodeBypass = needsSlowmodeCheck ? await hasPermission(Permissions.BYPASS_SLOWMODE) : false;
|
||||
|
||||
@@ -4,13 +4,20 @@ import {Permissions} from '@fluxer/constants/src/ChannelConstants';
|
||||
import {MAX_MESSAGE_LENGTH_PREMIUM} from '@fluxer/constants/src/LimitConstants';
|
||||
import type {MessageResponse} from '@fluxer/schema/src/domains/message/MessageResponseSchemas';
|
||||
import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from 'vitest';
|
||||
import {createTestAccount} from '../../auth/tests/AuthTestUtils';
|
||||
import {authorizeBot, createTestBotAccount} from '../../bot/tests/BotTestUtils';
|
||||
import {ensureSessionStarted} from '../../message/tests/MessageTestUtils';
|
||||
import {getGatewayService} from '../../middleware/ServiceRegistry';
|
||||
import {type ApiTestHarness, createApiTestHarness} from '../../test/ApiTestHarness';
|
||||
import {HTTP_STATUS} from '../../test/TestConstants';
|
||||
import {createBuilder} from '../../test/TestRequestBuilder';
|
||||
import {createPermissionOverwrite, setupTestGuildWithMembers} from './ChannelTestUtils';
|
||||
import {ChannelDataRepository} from '../repositories/ChannelDataRepository';
|
||||
import {
|
||||
createDmChannel,
|
||||
createFriendship,
|
||||
createPermissionOverwrite,
|
||||
setupTestGuildWithMembers,
|
||||
} from './ChannelTestUtils';
|
||||
|
||||
describe('Message send permissions', () => {
|
||||
let harness: ApiTestHarness;
|
||||
@@ -140,6 +147,28 @@ describe('Message send permissions', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('resolves the DM channel once for routing and once for authentication when sending', async () => {
|
||||
const sender = await createTestAccount(harness);
|
||||
const recipient = await createTestAccount(harness);
|
||||
await ensureSessionStarted(harness, sender.token);
|
||||
await createFriendship(harness, sender, recipient);
|
||||
const channel = await createDmChannel(harness, sender.token, recipient.userId);
|
||||
const findUnique = vi.spyOn(ChannelDataRepository.prototype, 'findUnique');
|
||||
|
||||
try {
|
||||
await createBuilder<MessageResponse>(harness, sender.token)
|
||||
.post(`/channels/${channel.id}/messages`)
|
||||
.body({content: 'no redundant reads'})
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.execute();
|
||||
const channelReads = findUnique.mock.calls.filter((call) => call[0].toString() === channel.id).length;
|
||||
|
||||
expect(channelReads).toBe(2);
|
||||
} finally {
|
||||
findUnique.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it('allows bot message content up to 4000 characters', async () => {
|
||||
const {owner, guild, systemChannel} = await setupTestGuildWithMembers(harness, 0);
|
||||
const botAccount = await createTestBotAccount(harness);
|
||||
|
||||
Reference in new issue
Block a user