Compare commits

...

3 commits

Author SHA1 Message Date
d99d116c02 fix: filter plugins should have access to idService in order to calculate account age 2024-02-19 00:23:36 +01:00
4b9179a4c4 feat: Add a simple customizable plugin system for spam filtering
A new field `noteFilterPlugin` is added to `config.yml` which should
point to a JavaScript ES Module file containing a default export of the
following:

```
export default async function (context) {
    return { verdict: false };
}
```

where the function is expected to take a `context` object (see
`NoteCreateService.ts` for what this object contains) and return a
result of two fields: `verdict` and `reason`. If `verdict` is set to
true, the note contained within the `context` object will be blocked
from the local instance.
2024-02-18 16:57:20 +01:00
dadba96935 Revert "perf(backend): use RSA 2048bit"
This reverts commit af2368bd2b.
2024-02-18 15:54:08 +01:00
5 changed files with 57 additions and 4 deletions

View file

@ -641,7 +641,6 @@
- nsfwjs のモデルロードを排他することで、重複ロードによってメモリ使用量が増加しないように
- 連合の配送ジョブのパフォーマンスを向上ロック機構の見直し、Redisキャッシュの活用
- featuredートのsignedGet回数を減らしました
- ActivityPubの署名用鍵長を2048bitに変更しパフォーマンスを向上(新規アカウントのみ)
- リモートサーバーのセンシティブなファイルのキャッシュだけを無効化できるオプションを追加
- MeilisearchにIndexするートの範囲を設定できるように
- Export notes with file detail

View file

@ -93,6 +93,10 @@ type Source = {
perUserNotificationsMaxCount?: number;
deactivateAntennaThreshold?: number;
pidFile: string;
// BEGIN comfy.social
noteFilterPlugin?: string;
// END comfy.social
};
export type Config = {
@ -170,6 +174,10 @@ export type Config = {
perUserNotificationsMaxCount: number;
deactivateAntennaThreshold: number;
pidFile: string;
// BEGIN comfy.social
noteFilterPlugin?: string;
// END comfy.social
};
const _filename = fileURLToPath(import.meta.url);
@ -265,6 +273,9 @@ export function loadConfig(): Config {
perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500,
deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7),
pidFile: config.pidFile,
// BEGIN comfy.social
noteFilterPlugin: config.noteFilterPlugin,
// END comfy.social
};
}

View file

@ -38,7 +38,7 @@ export class CreateSystemUserService {
// Generate secret
const secret = generateNativeUserToken();
const keyPair = await genRsaKeyPair();
const keyPair = await genRsaKeyPair(4096);
let account!: MiUser;

View file

@ -147,11 +147,29 @@ type Option = {
app?: MiApp | null;
};
// BEGIN comfy.social
type NoteFilterResult = {
verdict: boolean; // true = block
reason?: string;
};
type NoteFilterPluginContext = {
data: Option;
user: MiUser;
mentionedUsers: MiUser[];
remoteUserResolveService: RemoteUserResolveService;
idService: IdService;
}
// END comfy.social
@Injectable()
export class NoteCreateService implements OnApplicationShutdown {
#shutdownController = new AbortController();
public static ContainsProhibitedWordsError = class extends Error {};
// BEGIN comfy.social
private noteFilterPluginFn?: (context: NoteFilterPluginContext) => Promise<NoteFilterResult> = null;
// END comfy.social
constructor(
@Inject(DI.config)
@ -219,7 +237,15 @@ export class NoteCreateService implements OnApplicationShutdown {
private instanceChart: InstanceChart,
private utilityService: UtilityService,
private userBlockingService: UserBlockingService,
) { }
) {
// BEGIN comfy.social
if (this.config.noteFilterPlugin != null) {
import(this.config.noteFilterPlugin).then((m) => {
this.noteFilterPluginFn = m.default;
});
}
// END comfy.social
}
@bindThis
public async create(user: {
@ -379,6 +405,23 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
// BEGIN comfy.social
// Invoke customizable filter policy
if (this.noteFilterPluginFn != null) {
const filterResult = await this.noteFilterPluginFn({
data: data,
user: user,
mentionedUsers: mentionedUsers,
remoteUserResolveService: this.remoteUserResolveService,
idService: this.idService,
});
if (filterResult.verdict) {
throw new Error(`Blocked by custom filter policy, reason: ${filterResult.reason}`);
}
}
// END comfy.social
const note = await this.insertNote(user, data, tags, emojis, mentionedUsers);
setImmediate('post created', { signal: this.#shutdownController.signal }).then(

View file

@ -95,7 +95,7 @@ export class SignupService {
const keyPair = await new Promise<string[]>((res, rej) =>
generateKeyPair('rsa', {
modulusLength: 2048,
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem',