mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
feat(api): drop NSFW classification for emojis and stickers (#2462)
This commit is contained in:
@@ -6,7 +6,6 @@ import {ATTACHMENT_MAX_SIZE_NON_PREMIUM} from '@fluxer/constants/src/LimitConsta
|
||||
import {UserFlags} from '@fluxer/constants/src/UserConstants';
|
||||
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
|
||||
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
|
||||
import {NsfwEmojiStickerBlockedError} from '@fluxer/errors/src/domains/moderation/NsfwEmojiStickerBlockedError';
|
||||
import type {GuildMemberResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas';
|
||||
import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
|
||||
import type {RichEmbedRequest} from '@fluxer/schema/src/domains/message/MessageRequestSchemas';
|
||||
@@ -15,8 +14,8 @@ import {snowflakeToDate} from '@fluxer/snowflake/src/Snowflake';
|
||||
import * as BucketUtils from '@fluxer/snowflake/src/SnowflakeBuckets';
|
||||
import type {IVirusScanService} from '@pkgs/virus_scan/src/IVirusScanService';
|
||||
import {AttachmentDecayService} from '../../../attachment/AttachmentDecayService';
|
||||
import type {ChannelID, EmojiID, GuildID, MessageID, RoleID, StickerID, UserID, WebhookID} from '../../../BrandedTypes';
|
||||
import {createAttachmentID, createEmojiID, createGuildID} from '../../../BrandedTypes';
|
||||
import type {ChannelID, GuildID, MessageID, RoleID, StickerID, UserID, WebhookID} from '../../../BrandedTypes';
|
||||
import {createAttachmentID, createGuildID} from '../../../BrandedTypes';
|
||||
import {Config} from '../../../Config';
|
||||
import {getContentMessage} from '../../../content_i18n/ContentI18n';
|
||||
import type {
|
||||
@@ -121,7 +120,7 @@ export class MessagePersistenceService {
|
||||
constructor(
|
||||
private channelRepository: IChannelRepositoryAggregate,
|
||||
private userRepository: IUserRepository,
|
||||
private guildRepository: IGuildRepositoryAggregate,
|
||||
guildRepository: IGuildRepositoryAggregate,
|
||||
private embedService: EmbedService,
|
||||
private readonly storageService: IStorageService,
|
||||
attachmentUploadTraceRepository: AttachmentUploadTraceRepository,
|
||||
@@ -168,18 +167,10 @@ export class MessagePersistenceService {
|
||||
isBot,
|
||||
dmNsfwContext: params.dmNsfwContext,
|
||||
});
|
||||
let nsfwEmojiIds = new Set<EmojiID>();
|
||||
if (params.content) {
|
||||
if (!isNSFWAllowed) {
|
||||
await this.enforceNsfwEmojiRestrictions(params.content);
|
||||
} else {
|
||||
nsfwEmojiIds = await this.collectNsfwEmojiIds(params.content);
|
||||
}
|
||||
}
|
||||
const [sanitizedContent, attachmentResult, processedStickers] = await Promise.all([
|
||||
this.sanitizeContentIfNeeded(params, authorId),
|
||||
this.processAttachments(params, isNSFWAllowed ? 'allow' : 'block'),
|
||||
this.processStickers(params, authorId, isNSFWAllowed),
|
||||
this.processStickers(params, authorId),
|
||||
]);
|
||||
let messageContent = sanitizedContent;
|
||||
let processedAttachments: Array<MessageAttachment> = params.processedAttachments
|
||||
@@ -242,7 +233,6 @@ export class MessagePersistenceService {
|
||||
? params.messageSnapshots.map((snapshot) => snapshot.toMessageSnapshot())
|
||||
: null,
|
||||
call: null,
|
||||
nsfw_emojis: nsfwEmojiIds.size > 0 ? nsfwEmojiIds : null,
|
||||
has_reaction: false,
|
||||
version: 1,
|
||||
};
|
||||
@@ -305,7 +295,6 @@ export class MessagePersistenceService {
|
||||
private async processStickers(
|
||||
params: CreateMessageParams,
|
||||
authorId: UserID | null,
|
||||
isNSFWAllowed?: boolean,
|
||||
): Promise<Array<MessageStickerItem>> {
|
||||
if (!params.stickerIds || params.stickerIds.length === 0) {
|
||||
return [];
|
||||
@@ -315,37 +304,9 @@ export class MessagePersistenceService {
|
||||
userId: authorId,
|
||||
guildId: params.guildId,
|
||||
hasPermission: params.hasPermission,
|
||||
isNSFWAllowed: isNSFWAllowed ?? true,
|
||||
});
|
||||
}
|
||||
|
||||
private async enforceNsfwEmojiRestrictions(content: string): Promise<void> {
|
||||
const nsfwIds = await this.collectNsfwEmojiIds(content);
|
||||
if (nsfwIds.size > 0) {
|
||||
throw new NsfwEmojiStickerBlockedError();
|
||||
}
|
||||
}
|
||||
|
||||
private async collectNsfwEmojiIds(content: string): Promise<Set<EmojiID>> {
|
||||
const CUSTOM_EMOJI_REGEX = /<a?:[^:]+:(\d+)>/g;
|
||||
const emojiIds = new Set<EmojiID>();
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = CUSTOM_EMOJI_REGEX.exec(content)) !== null) {
|
||||
emojiIds.add(createEmojiID(BigInt(match[1])));
|
||||
}
|
||||
if (emojiIds.size === 0) {
|
||||
return new Set();
|
||||
}
|
||||
const lookups = await Promise.all([...emojiIds].map((id) => this.guildRepository.getEmojiById(id)));
|
||||
const nsfwEmojiIds = new Set<EmojiID>();
|
||||
for (const emoji of lookups) {
|
||||
if (emoji?.isNsfw) {
|
||||
nsfwEmojiIds.add(emoji.id);
|
||||
}
|
||||
}
|
||||
return nsfwEmojiIds;
|
||||
}
|
||||
|
||||
private async runPostPersistenceOperations(context: {
|
||||
message: Message;
|
||||
params: CreateMessageParams;
|
||||
@@ -431,9 +392,6 @@ export class MessagePersistenceService {
|
||||
if (data.content !== undefined && data.content !== message.content) {
|
||||
let sanitizedContent = data.content && hasVisibleContent(data.content) ? data.content : '';
|
||||
if (sanitizedContent) {
|
||||
if (!isNSFWAllowed) {
|
||||
await this.enforceNsfwEmojiRestrictions(sanitizedContent);
|
||||
}
|
||||
sanitizedContent = await this.contentService.sanitizeCustomEmojis({
|
||||
content: sanitizedContent,
|
||||
userId: message.authorId ?? null,
|
||||
|
||||
@@ -96,7 +96,6 @@ function makeMessage(messageId: bigint = 2n, content: string = '', channelId: bi
|
||||
message_reference: null,
|
||||
message_snapshots: null,
|
||||
call: null,
|
||||
nsfw_emojis: null,
|
||||
has_reaction: null,
|
||||
version: 1,
|
||||
});
|
||||
|
||||
@@ -48,7 +48,6 @@ function makeMessage(channelId: ChannelID, messageId: MessageID): Message {
|
||||
message_reference: null,
|
||||
message_snapshots: null,
|
||||
call: null,
|
||||
nsfw_emojis: null,
|
||||
has_reaction: null,
|
||||
version: 1,
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ import {FeatureTemporarilyDisabledError} from '@fluxer/errors/src/domains/core/F
|
||||
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
|
||||
import {MissingPermissionsError} from '@fluxer/errors/src/domains/core/MissingPermissionsError';
|
||||
import {SlowmodeRateLimitError} from '@fluxer/errors/src/domains/core/SlowmodeRateLimitError';
|
||||
import {NsfwEmojiStickerBlockedError} from '@fluxer/errors/src/domains/moderation/NsfwEmojiStickerBlockedError';
|
||||
import {NsfwContentRequiresAgeVerificationError} from '@fluxer/errors/src/domains/moderation/NsfwContentRequiresAgeVerificationError';
|
||||
import type {GuildMemberResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas';
|
||||
import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
|
||||
import {snowflakeToDate} from '@fluxer/snowflake/src/Snowflake';
|
||||
@@ -845,7 +845,7 @@ export class MessageSendService {
|
||||
const guildNsfw = guild != null && guild.nsfw_level === GuildNSFWLevel.AGE_RESTRICTED;
|
||||
const destAllowsNsfw = channel.isNsfw || guildNsfw;
|
||||
if (!destAllowsNsfw) {
|
||||
throw new NsfwEmojiStickerBlockedError();
|
||||
throw new NsfwContentRequiresAgeVerificationError();
|
||||
}
|
||||
}
|
||||
if (data.message_reference && guild && !isForwardMessage) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import {Permissions} from '@fluxer/constants/src/ChannelConstants';
|
||||
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
|
||||
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
|
||||
import {MissingPermissionsError} from '@fluxer/errors/src/domains/core/MissingPermissionsError';
|
||||
import {NsfwEmojiStickerBlockedError} from '@fluxer/errors/src/domains/moderation/NsfwEmojiStickerBlockedError';
|
||||
import type {GuildID, StickerID, UserID} from '../../../BrandedTypes';
|
||||
import type {MessageStickerItem} from '../../../database/types/MessageTypes';
|
||||
import type {IGuildRepositoryAggregate} from '../../../guild/repositories/IGuildRepositoryAggregate';
|
||||
@@ -25,9 +24,8 @@ export class MessageStickerService {
|
||||
userId: UserID | null;
|
||||
guildId: GuildID | null;
|
||||
hasPermission?: (permission: bigint) => Promise<boolean>;
|
||||
isNSFWAllowed?: boolean;
|
||||
}): Promise<Array<MessageStickerItem>> {
|
||||
const {stickerIds, userId, guildId, hasPermission, isNSFWAllowed = true} = params;
|
||||
const {stickerIds, userId, guildId, hasPermission} = params;
|
||||
let hasGlobalExpressions = 0;
|
||||
if (userId) {
|
||||
const user = await this.userRepository.findUnique(userId);
|
||||
@@ -49,26 +47,18 @@ export class MessageStickerService {
|
||||
if (!stickerFromAnyGuild) {
|
||||
throw InputValidationError.fromCode('sticker', ValidationErrorCodes.CUSTOM_STICKER_NOT_FOUND);
|
||||
}
|
||||
if (!isNSFWAllowed && stickerFromAnyGuild.isNsfw) {
|
||||
throw new NsfwEmojiStickerBlockedError();
|
||||
}
|
||||
return {
|
||||
sticker_id: stickerFromAnyGuild.id,
|
||||
name: stickerFromAnyGuild.name,
|
||||
animated: stickerFromAnyGuild.animated,
|
||||
...(stickerFromAnyGuild.isNsfw ? {nsfw: true} : {}),
|
||||
};
|
||||
}
|
||||
const guildSticker = await this.guildRepository.getSticker(stickerId, guildId);
|
||||
if (guildSticker) {
|
||||
if (!isNSFWAllowed && guildSticker.isNsfw) {
|
||||
throw new NsfwEmojiStickerBlockedError();
|
||||
}
|
||||
return {
|
||||
sticker_id: guildSticker.id,
|
||||
name: guildSticker.name,
|
||||
animated: guildSticker.animated,
|
||||
...(guildSticker.isNsfw ? {nsfw: true} : {}),
|
||||
};
|
||||
}
|
||||
const stickerFromOtherGuild = await this.guildRepository.getStickerById(stickerId);
|
||||
@@ -87,14 +77,10 @@ export class MessageStickerService {
|
||||
throw new MissingPermissionsError();
|
||||
}
|
||||
}
|
||||
if (!isNSFWAllowed && stickerFromOtherGuild.isNsfw) {
|
||||
throw new NsfwEmojiStickerBlockedError();
|
||||
}
|
||||
return {
|
||||
sticker_id: stickerFromOtherGuild.id,
|
||||
name: stickerFromOtherGuild.name,
|
||||
animated: stickerFromOtherGuild.animated,
|
||||
...(stickerFromOtherGuild.isNsfw ? {nsfw: true} : {}),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user