enhance: Judge instance block by endsWith (#9263)

* TypeScriptでendsWith

* fix

* SQL?

* バ〜カアホ

* Update packages/backend/src/core/UtilityService.ts

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* add comment

* add description

* Update packages/backend/src/core/UtilityService.ts

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* Update packages/backend/src/core/chart/charts/federation.ts

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* remove comment

* fix

* fix?

* add changelog

* ILIKE, ARRAY

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
tamaina 2023-01-13 18:21:07 +09:00 committed by GitHub
parent 161da24841
commit 303519a1bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 25 additions and 16 deletions

View file

@ -33,6 +33,7 @@ You should also include the user name that made the change.
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
- Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator
- You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic
- インスタンスブロックはサブドメインにも適用されるようになります
- ロールの導入に伴い、いくつかの機能がロールと統合されました
- モデレーターはロールに統合されました。今までのモデレーター情報は失われるため、予めモデレーター一覧を記録しておき、アップデート後にモデレーターロールを作りアサインし直してください。
- サイレンスはロールに統合されました。今までのユーザーは恩赦されるため、予めサイレンス一覧を記録しておくのをおすすめします。

View file

@ -193,7 +193,7 @@ clearQueueConfirmText: "未配達の投稿は配送されなくなります。
clearCachedFiles: "キャッシュをクリア"
clearCachedFilesConfirm: "キャッシュされたリモートファイルをすべて削除しますか?"
blockedInstances: "ブロックしたインスタンス"
blockedInstancesDescription: "ブロックしたいインスタンスのホストを改行で区切って設定します。ブロックされたインスタンスは、このインスタンスとやり取りできなくなります。"
blockedInstancesDescription: "ブロックしたいインスタンスのホストを改行で区切って設定します。ブロックされたインスタンスは、このインスタンスとやり取りできなくなります。サブドメインもブロックされます。"
muteAndBlock: "ミュートとブロック"
mutedUsers: "ミュートしたユーザー"
blockedUsers: "ブロックしたユーザー"

View file

@ -24,6 +24,12 @@ export class UtilityService {
return this.toPuny(this.config.host) === this.toPuny(host);
}
@bindThis
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
if (host == null) return false;
return blockedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
}
@bindThis
public extractDbHost(uri: string): string {
const url = new URL(uri);

View file

@ -291,7 +291,7 @@ export class ApInboxService {
// アナウンス先をブロックしてたら中断
const meta = await this.metaService.fetch();
if (meta.blockedHosts.includes(this.utilityService.extractDbHost(uri))) return;
if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) return;
const unlock = await this.appLockService.getApLock(uri);

View file

@ -96,7 +96,7 @@ export class Resolver {
}
const meta = await this.metaService.fetch();
if (meta.blockedHosts.includes(host)) {
if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) {
throw new Error('Instance is blocked');
}

View file

@ -324,7 +324,7 @@ export class ApNoteService {
// ブロックしてたら中断
const meta = await this.metaService.fetch();
if (meta.blockedHosts.includes(this.utilityService.extractDbHost(uri))) throw { statusCode: 451 };
if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) throw { statusCode: 451 };
const unlock = await this.appLockService.getApLock(uri);

View file

@ -61,21 +61,21 @@ export default class FederationChart extends Chart<typeof schema> {
this.followingsRepository.createQueryBuilder('following')
.select('COUNT(DISTINCT following.followeeHost)')
.where('following.followeeHost IS NOT NULL')
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
.andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
.getRawOne()
.then(x => parseInt(x.count, 10)),
this.followingsRepository.createQueryBuilder('following')
.select('COUNT(DISTINCT following.followerHost)')
.where('following.followerHost IS NOT NULL')
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followerHost NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followerHost NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
.andWhere(`following.followerHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
.getRawOne()
.then(x => parseInt(x.count, 10)),
this.followingsRepository.createQueryBuilder('following')
.select('COUNT(DISTINCT following.followeeHost)')
.where('following.followeeHost IS NOT NULL')
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
.andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
.andWhere(`following.followeeHost IN (${ pubsubSubQuery.getQuery() })`)
.setParameters(pubsubSubQuery.getParameters())
@ -84,7 +84,7 @@ export default class FederationChart extends Chart<typeof schema> {
this.instancesRepository.createQueryBuilder('instance')
.select('COUNT(instance.id)')
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
.andWhere('instance.isSuspended = false')
.andWhere('instance.isNotResponding = false')
.getRawOne()
@ -92,7 +92,7 @@ export default class FederationChart extends Chart<typeof schema> {
this.instancesRepository.createQueryBuilder('instance')
.select('COUNT(instance.id)')
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
.andWhere('instance.isSuspended = false')
.andWhere('instance.isNotResponding = false')
.getRawOne()

View file

@ -7,8 +7,8 @@ import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import type { Instance } from '@/models/entities/Instance.js';
import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '../UtilityService.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable()
export class InstanceEntityService {
@ -17,6 +17,8 @@ export class InstanceEntityService {
private instancesRepository: InstancesRepository,
private metaService: MetaService,
private utilityService: UtilityService,
) {
}
@ -35,7 +37,7 @@ export class InstanceEntityService {
followersCount: instance.followersCount,
isNotResponding: instance.isNotResponding,
isSuspended: instance.isSuspended,
isBlocked: meta.blockedHosts.includes(instance.host),
isBlocked: this.utilityService.isBlockedHost(meta.blockedHosts, instance.host),
softwareName: instance.softwareName,
softwareVersion: instance.softwareVersion,
openRegistrations: instance.openRegistrations,

View file

@ -56,7 +56,7 @@ export class DeliverProcessorService {
// ブロックしてたら中断
const meta = await this.metaService.fetch();
if (meta.blockedHosts.includes(this.utilityService.toPuny(host))) {
if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.toPuny(host))) {
return 'skip (blocked)';
}

View file

@ -76,7 +76,7 @@ export class InboxProcessorService {
// ブロックしてたら中断
const meta = await this.metaService.fetch();
if (meta.blockedHosts.includes(host)) {
if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) {
return `Blocked request: ${host}`;
}
@ -158,7 +158,7 @@ export class InboxProcessorService {
// ブロックしてたら中断
const ldHost = this.utilityService.extractDbHost(authUser.user.uri);
if (meta.blockedHosts.includes(ldHost)) {
if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) {
return `Blocked request: ${ldHost}`;
}
} else {

View file

@ -139,7 +139,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
if (Array.isArray(ps.blockedHosts)) {
set.blockedHosts = ps.blockedHosts.filter(Boolean);
set.blockedHosts = ps.blockedHosts.filter(Boolean).map(x => x.toLowerCase());
}
if (ps.themeColor !== undefined) {

View file

@ -117,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private async fetchAny(uri: string, me: CacheableLocalUser | null | undefined): Promise<SchemaType<typeof meta['res']> | null> {
// ブロックしてたら中断
const fetchedMeta = await this.metaService.fetch();
if (fetchedMeta.blockedHosts.includes(this.utilityService.extractDbHost(uri))) return null;
if (this.utilityService.isBlockedHost(fetchedMeta.blockedHosts, this.utilityService.extractDbHost(uri))) return null;
let local = await this.mergePack(me, ...await Promise.all([
this.apDbResolverService.getUserFromApId(uri),