mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
fix(api): trust recorded upload types and bound edit sizes (#2345)
This commit is contained in:
1 parent
c79c0ee138
commit
693aec2b4d
2 files changed
+34
-4
No files matched your search
@@ -209,7 +209,7 @@ export class AttachmentProcessingService {
|
|||||||
}
|
}
|
||||||
const attachmentId = createAttachmentID(await this.snowflakeService.generate());
|
const attachmentId = createAttachmentID(await this.snowflakeService.generate());
|
||||||
const cdnKey = makeAttachmentCdnKey(message.channelId, attachmentId, attachment.filename);
|
const cdnKey = makeAttachmentCdnKey(message.channelId, attachmentId, attachment.filename);
|
||||||
let contentType = attachment.content_type ?? getContentType(attachment.filename);
|
let contentType = pendingUpload.content_type ?? getContentType(attachment.filename);
|
||||||
let size = BigInt(uploadedFile.contentLength);
|
let size = BigInt(uploadedFile.contentLength);
|
||||||
const clientFlags =
|
const clientFlags =
|
||||||
(attachment.flags ?? 0) & (MessageAttachmentFlags.IS_SPOILER | MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA);
|
(attachment.flags ?? 0) & (MessageAttachmentFlags.IS_SPOILER | MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import {MessageFlags, Permissions, SENDABLE_MESSAGE_FLAGS} from '@fluxer/constants/src/ChannelConstants';
|
import {MessageFlags, Permissions, SENDABLE_MESSAGE_FLAGS} from '@fluxer/constants/src/ChannelConstants';
|
||||||
|
import {ATTACHMENT_MAX_SIZE_NON_PREMIUM} from '@fluxer/constants/src/LimitConstants';
|
||||||
import {UserFlags} from '@fluxer/constants/src/UserConstants';
|
import {UserFlags} from '@fluxer/constants/src/UserConstants';
|
||||||
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
|
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
|
||||||
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
|
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
|
||||||
@@ -16,6 +17,7 @@ import type {IVirusScanService} from '@pkgs/virus_scan/src/IVirusScanService';
|
|||||||
import {AttachmentDecayService} from '../../../attachment/AttachmentDecayService';
|
import {AttachmentDecayService} from '../../../attachment/AttachmentDecayService';
|
||||||
import type {ChannelID, EmojiID, GuildID, MessageID, RoleID, StickerID, UserID, WebhookID} from '../../../BrandedTypes';
|
import type {ChannelID, EmojiID, GuildID, MessageID, RoleID, StickerID, UserID, WebhookID} from '../../../BrandedTypes';
|
||||||
import {createAttachmentID, createEmojiID, createGuildID} from '../../../BrandedTypes';
|
import {createAttachmentID, createEmojiID, createGuildID} from '../../../BrandedTypes';
|
||||||
|
import {Config} from '../../../Config';
|
||||||
import {getContentMessage} from '../../../content_i18n/ContentI18n';
|
import {getContentMessage} from '../../../content_i18n/ContentI18n';
|
||||||
import type {
|
import type {
|
||||||
MessageAttachment,
|
MessageAttachment,
|
||||||
@@ -29,6 +31,8 @@ import type {IMediaService, MediaProxyNsfwMode} from '../../../infrastructure/IM
|
|||||||
import type {ISnowflakeService} from '../../../infrastructure/ISnowflakeService';
|
import type {ISnowflakeService} from '../../../infrastructure/ISnowflakeService';
|
||||||
import type {IStorageService} from '../../../infrastructure/IStorageService';
|
import type {IStorageService} from '../../../infrastructure/IStorageService';
|
||||||
import type {LimitConfigService} from '../../../limits/LimitConfigService';
|
import type {LimitConfigService} from '../../../limits/LimitConfigService';
|
||||||
|
import {resolveLimitSafe} from '../../../limits/LimitConfigUtils';
|
||||||
|
import {createLimitMatchContext} from '../../../limits/LimitMatchContextBuilder';
|
||||||
import type {Channel} from '../../../models/Channel';
|
import type {Channel} from '../../../models/Channel';
|
||||||
import type {Message} from '../../../models/Message';
|
import type {Message} from '../../../models/Message';
|
||||||
import type {MessageSnapshot} from '../../../models/MessageSnapshot';
|
import type {MessageSnapshot} from '../../../models/MessageSnapshot';
|
||||||
@@ -43,7 +47,7 @@ import type {AttachmentUploadTraceRepository} from '../../repositories/message/A
|
|||||||
import {AttachmentProcessingService} from './AttachmentProcessingService';
|
import {AttachmentProcessingService} from './AttachmentProcessingService';
|
||||||
import {type DmNsfwContext, MessageContentService} from './MessageContentService';
|
import {type DmNsfwContext, MessageContentService} from './MessageContentService';
|
||||||
import {MessageEmbedAttachmentResolver} from './MessageEmbedAttachmentResolver';
|
import {MessageEmbedAttachmentResolver} from './MessageEmbedAttachmentResolver';
|
||||||
import {collectMessageAttachments} from './MessageHelpers';
|
import {assertAttachmentFileSizesWithinLimit, collectMessageAttachments} from './MessageHelpers';
|
||||||
import {MessageStickerService} from './MessageStickerService';
|
import {MessageStickerService} from './MessageStickerService';
|
||||||
|
|
||||||
function mapAttachmentForEmbedResolution(att: MessageAttachment) {
|
function mapAttachmentForEmbedResolution(att: MessageAttachment) {
|
||||||
@@ -119,13 +123,13 @@ export class MessagePersistenceService {
|
|||||||
private userRepository: IUserRepository,
|
private userRepository: IUserRepository,
|
||||||
private guildRepository: IGuildRepositoryAggregate,
|
private guildRepository: IGuildRepositoryAggregate,
|
||||||
private embedService: EmbedService,
|
private embedService: EmbedService,
|
||||||
storageService: IStorageService,
|
private readonly storageService: IStorageService,
|
||||||
attachmentUploadTraceRepository: AttachmentUploadTraceRepository,
|
attachmentUploadTraceRepository: AttachmentUploadTraceRepository,
|
||||||
mediaService: IMediaService,
|
mediaService: IMediaService,
|
||||||
virusScanService: IVirusScanService,
|
virusScanService: IVirusScanService,
|
||||||
snowflakeService: ISnowflakeService,
|
snowflakeService: ISnowflakeService,
|
||||||
private readStateService: ReadStateService,
|
private readStateService: ReadStateService,
|
||||||
limitConfigService: LimitConfigService,
|
private readonly limitConfigService: LimitConfigService,
|
||||||
) {
|
) {
|
||||||
this.attachmentService = new AttachmentProcessingService(
|
this.attachmentService = new AttachmentProcessingService(
|
||||||
storageService,
|
storageService,
|
||||||
@@ -492,6 +496,32 @@ export class MessagePersistenceService {
|
|||||||
uploadUserId !== undefined,
|
uploadUserId !== undefined,
|
||||||
'Attachment upload actor must be resolved before processing new attachments',
|
'Attachment upload actor must be resolved before processing new attachments',
|
||||||
);
|
);
|
||||||
|
const uploader = await this.userRepository.findUnique(uploadUserId);
|
||||||
|
const guildFeatures = guild?.features ?? null;
|
||||||
|
const maxFileSize = Math.floor(
|
||||||
|
resolveLimitSafe(
|
||||||
|
this.limitConfigService.getConfigSnapshot(),
|
||||||
|
createLimitMatchContext({user: uploader, guildFeatures}),
|
||||||
|
'max_attachment_file_size',
|
||||||
|
ATTACHMENT_MAX_SIZE_NON_PREMIUM,
|
||||||
|
guildFeatures ? 'guild' : 'user',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const uploadedSizes: Array<number> = [];
|
||||||
|
for (const [index, attachment] of newAttachments.entries()) {
|
||||||
|
const uploadedFile = await this.storageService.getObjectMetadata(
|
||||||
|
Config.s3.buckets.uploads,
|
||||||
|
attachment.upload_filename,
|
||||||
|
);
|
||||||
|
if (!uploadedFile) {
|
||||||
|
throw InputValidationError.fromCode(
|
||||||
|
`attachments.${index}.upload_filename`,
|
||||||
|
ValidationErrorCodes.FILE_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
uploadedSizes.push(uploadedFile.contentLength);
|
||||||
|
}
|
||||||
|
assertAttachmentFileSizesWithinLimit(uploadedSizes, maxFileSize);
|
||||||
const attachmentResult = await this.attachmentService.computeAttachments({
|
const attachmentResult = await this.attachmentService.computeAttachments({
|
||||||
message,
|
message,
|
||||||
attachments: newAttachments,
|
attachments: newAttachments,
|
||||||
|
|||||||
Reference in new issue
Block a user