Skip to content
This repository has been archived by the owner on Mar 29, 2024. It is now read-only.

Commit

Permalink
enhance: 禁止ワードチェック強化 (#27)
Browse files Browse the repository at this point in the history
* enhance: 禁止ワードチェック強化
* リモートの禁止ワードチェックを添付ファイルとユーザーを登録する前に行うなど
  Resolve misskey-dev/misskey#13374
* 禁止ワートの対象の見直し

* performActivityで特定のエラーが出た際にDelayedに追加しないように

* use IdentifiableError

* NoteCreateService.checkProhibitedWords

* https://github.com/misskey-dev/misskey-private/pull/27/files#r1507416135

* remove comment
  • Loading branch information
tamaina authored and 16439s committed Mar 8, 2024
1 parent dad89b8 commit 5c5a08c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 23 deletions.
25 changes: 24 additions & 1 deletion packages/backend/src/core/NoteCreateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,13 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}

if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
const hasProhibitedWords = await this.checkProhibitedWordsContain({
cw: data.cw,
text: data.text,
pollChoices: data.poll?.choices,
}, meta.prohibitedWords);

if (hasProhibitedWords) {
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
}

Expand Down Expand Up @@ -1029,6 +1035,23 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}

public async checkProhibitedWordsContain(content: Parameters<UtilityService['concatNoteContentsForKeyWordCheck']>[0], prohibitedWords?: string[]) {
if (prohibitedWords == null) {
prohibitedWords = (await this.metaService.fetch()).prohibitedWords;
}

if (
this.utilityService.isKeyWordIncluded(
this.utilityService.concatNoteContentsForKeyWordCheck(content),
prohibitedWords,
)
) {
return true;
}

return false;
}

@bindThis
public dispose(): void {
this.#shutdownController.abort();
Expand Down
14 changes: 14 additions & 0 deletions packages/backend/src/core/UtilityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ export class UtilityService {
return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
}

@bindThis
public concatNoteContentsForKeyWordCheck(content: {
cw?: string | null;
text?: string | null;
pollChoices?: string[] | null;
others?: string[] | null;
}): string {
/**
* ノートの内容を結合してキーワードチェック用の文字列を生成する
* cwとtextは内容が繋がっているかもしれないので間に何も入れずにチェックする
*/
return `${content.cw ?? ''}${content.text ?? ''}\n${(content.pollChoices ?? []).join('\n')}\n${(content.others ?? []).join('\n')}`;
}

@bindThis
public isKeyWordIncluded(text: string, keyWords: string[]): boolean {
if (keyWords.length === 0) return false;
Expand Down
1 change: 0 additions & 1 deletion packages/backend/src/core/activitypub/ApInboxService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import { ApResolverService } from './ApResolverService.js';
import { ApAudienceService } from './ApAudienceService.js';
import { ApPersonService } from './models/ApPersonService.js';
import { ApQuestionService } from './models/ApQuestionService.js';
import { CacheService } from '@/core/CacheService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Resolver } from './ApResolverService.js';
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IRead, IReject, IRemove, IUndo, IUpdate, IMove } from './type.js';
Expand Down
62 changes: 42 additions & 20 deletions packages/backend/src/core/activitypub/models/ApNoteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import { MessagingService } from '@/core/MessagingService.js';
import { bindThis } from '@/decorators.js';
import { checkHttps } from '@/misc/check-https.js';
import { NoteUpdateService } from '@/core/NoteUpdateService.js';
import { getApId, getApType, getOneApHrefNullable, getOneApId, isEmoji, validPost } from '../type.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { isNotNull } from '@/misc/is-not-null.js';
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
import { ApLoggerService } from '../ApLoggerService.js';
import { ApMfmService } from '../ApMfmService.js';
import { ApDbResolverService } from '../ApDbResolverService.js';
Expand Down Expand Up @@ -163,11 +165,47 @@ export class ApNoteService {
throw new Error('invalid note.attributedTo: ' + note.attributedTo);
}

const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as MiRemoteUser;
const uri = getOneApId(note.attributedTo);

// 投稿者が凍結されていたらスキップ
// ローカルで投稿者を検索し、もし凍結されていたらスキップ
const cachedActor = await this.apPersonService.fetchPerson(uri) as MiRemoteUser;
if (cachedActor && cachedActor.isSuspended) {
throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended');
}

const apMentions = await this.apMentionService.extractApMentions(note.tag, resolver);
const apHashtags = extractApHashtags(note.tag);

const cw = note.summary === '' ? null : note.summary;

// テキストのパース
let text: string | null = null;
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
text = note.source.content;
} else if (typeof note._misskey_content !== 'undefined') {
text = note._misskey_content;
} else if (typeof note.content === 'string') {
text = this.apMfmService.htmlToMfm(note.content, note.tag);
}

const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined);

//#region Contents Check
// 添付ファイルとユーザーをこのサーバーで登録する前に内容をチェックする
/**
* 禁止ワードチェック
*/
const hasProhibitedWords = await this.noteCreateService.checkProhibitedWordsContain({ cw, text, pollChoices: poll?.choices });
if (hasProhibitedWords) {
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
}
//#endregion

const actor = cachedActor ?? await this.apPersonService.resolvePerson(uri, resolver) as MiRemoteUser;

// 解決した投稿者が凍結されていたらスキップ
if (actor.isSuspended) {
throw new Error('actor has been suspended');
throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended');
}

const noteAudience = await this.apAudienceService.parseAudience(actor, note.to, note.cc, resolver);
Expand All @@ -184,9 +222,6 @@ export class ApNoteService {

let isMessaging = note._misskey_talk && visibility === 'specified';

const apMentions = await this.apMentionService.extractApMentions(note.tag, resolver);
const apHashtags = extractApHashtags(note.tag);

// 添付ファイル
// TODO: attachmentは必ずしもImageではない
// TODO: attachmentは必ずしも配列ではない
Expand Down Expand Up @@ -257,18 +292,6 @@ export class ApNoteService {
}
}

const cw = note.summary === '' ? null : note.summary;

// テキストのパース
let text: string | null = null;
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
text = note.source.content;
} else if (typeof note._misskey_content !== 'undefined') {
text = note._misskey_content;
} else if (typeof note.content === 'string') {
text = this.apMfmService.htmlToMfm(note.content, note.tag);
}

// vote
if (reply && reply.hasPoll) {
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
Expand Down Expand Up @@ -298,7 +321,6 @@ export class ApNoteService {

const apEmojis = emojis.map(emoji => emoji.name);

const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined);
const event = await this.apEventService.extractEventFromNote(note, resolver).catch(() => undefined);

if (isMessaging) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ export class InboxProcessorService {
await this.apInboxService.performActivity(authUser.user, activity);
} catch (e) {
if (e instanceof IdentifiableError) {
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') return 'blocked notes with prohibited words';
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
return 'blocked notes with prohibited words';
}
if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') return 'actor has been suspended';
}
throw e;
}
Expand Down

0 comments on commit 5c5a08c

Please sign in to comment.