Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: サーバーサイレンス機能を追加 #12031

Merged
merged 23 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a92ef26
feat : サーバーサイレンスを追加
mattyatea Oct 14, 2023
3ca464e
Update CHANGELOG.md
mattyatea Oct 14, 2023
80fd42a
Update CHANGELOG.md
mattyatea Oct 14, 2023
728704f
Update locale
mattyatea Oct 14, 2023
7cc50a2
Update instance-info.vue
mattyatea Oct 14, 2023
3d79428
update misskey-js.api.md
mattyatea Oct 14, 2023
9818d1a
lint fix
mattyatea Oct 14, 2023
ba661d9
migration fix
mattyatea Oct 14, 2023
0e7ab75
既存のものを使うように
mattyatea Oct 15, 2023
4530bc9
Merge branch 'develop' into instance-silence
mattyatea Oct 15, 2023
e93c54d
Merge branch 'develop' into instance-silence
mattyatea Oct 16, 2023
b390c08
fix
mattyatea Oct 16, 2023
6b7c2f6
色々直した
mattyatea Oct 16, 2023
3e22d89
Update packages/frontend/src/pages/admin/instance-block.vue
syuilo Oct 16, 2023
c1124e2
Update packages/frontend/src/pages/admin/instance-block.vue
syuilo Oct 16, 2023
f59fb7d
Update packages/frontend/src/components/MkInstanceCardMini.vue
syuilo Oct 16, 2023
6edab88
Update packages/backend/src/core/entities/InstanceEntityService.ts
syuilo Oct 16, 2023
1f95db4
Update packages/backend/src/core/entities/InstanceEntityService.ts
syuilo Oct 16, 2023
e027d0c
Update packages/backend/src/core/entities/InstanceEntityService.ts
syuilo Oct 16, 2023
197fbcf
Update packages/backend/src/core/UserFollowingService.ts
syuilo Oct 16, 2023
5c306e6
Update packages/backend/src/core/UserFollowingService.ts
syuilo Oct 16, 2023
cb65e98
fix: サイレンスされてるサーバーからの投稿は全部ホームにする
mattyatea Oct 16, 2023
a3d5a56
fix: undefinedでfalseを返すようにした
mattyatea Oct 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
- Enhance: トレンドハッシュタグ取得時のパフォーマンスを大幅に向上
- Enhance: WebSocket接続が多い場合のパフォーマンスを向上
- Enhance: 不要なPostgreSQLのインデックスを削除しパフォーマンスを向上
- Feat: サーバーサイレンス機能が追加されました
- Fix: 連合なしアンケートに投票をするとUpdateがリモートに配信されてしまうのを修正
- Fix: nodeinfoにおいてCORS用のヘッダーが設定されていないのを修正
- Fix: 同じ種類のTLのストリーミングを複数接続できない問題を修正
Expand Down
10 changes: 9 additions & 1 deletion locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ perHour: "Per Hour"
perDay: "Per Day"
stopActivityDelivery: "Stop sending activities"
blockThisInstance: "Block this instance"
silenceThisInstance: "Silence this instance"
operations: "Operations"
software: "Software"
version: "Version"
Expand All @@ -213,6 +214,13 @@ clearQueueConfirmText: "Any undelivered notes remaining in the queue will not be
clearCachedFiles: "Clear cache"
clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?"
blockedInstances: "Blocked Instances"
silencedInstances: "Silenced Instances"
silencedInstancesDescription: "List the hostnames of the instances that you want to\
\ silence. Accounts in the listed instances are treated as \"Silenced\", can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked instances."
hiddenTags: "Hidden Hashtags"
hiddenTagsDescription: "List the hashtags (without the #) of the hashtags you wish\
\ to hide from trending and explore. Hidden hashtags are still discoverable via\
\ other means. Blocked instances are not affected even if listed here."
blockedInstancesDescription: "List the hostnames of the instances that you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance."
muteAndBlock: "Mutes and Blocks"
mutedUsers: "Muted users"
Expand Down Expand Up @@ -794,7 +802,7 @@ active: "Active"
offline: "Offline"
notRecommended: "Not recommended"
botProtection: "Bot Protection"
instanceBlocking: "Blocked Instances"
instanceBlocking: "Blocked/Silenced Instances"
selectAccount: "Select account"
switchAccount: "Switch account"
enabled: "Enabled"
Expand Down
3 changes: 3 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export interface Locale {
"perDay": string;
"stopActivityDelivery": string;
"blockThisInstance": string;
"silenceThisInstance": string;
"operations": string;
"software": string;
"version": string;
Expand All @@ -217,6 +218,8 @@ export interface Locale {
"clearCachedFilesConfirm": string;
"blockedInstances": string;
"blockedInstancesDescription": string;
"silencedInstances": string;
"silencedInstancesDescription": string;
"muteAndBlock": string;
"mutedUsers": string;
"blockedUsers": string;
Expand Down
7 changes: 5 additions & 2 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ perHour: "1時間ごと"
perDay: "1日ごと"
stopActivityDelivery: "アクティビティの配送を停止"
blockThisInstance: "このサーバーをブロック"
silenceThisInstance: "サーバーをサイレンス"
operations: "操作"
software: "ソフトウェア"
version: "バージョン"
Expand All @@ -213,7 +214,9 @@ clearQueueConfirmText: "未配達の投稿は配送されなくなります。
clearCachedFiles: "キャッシュをクリア"
clearCachedFilesConfirm: "キャッシュされたリモートファイルをすべて削除しますか?"
blockedInstances: "ブロックしたサーバー"
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このサーバーとやり取りできなくなります。サブドメインもブロックされます。"
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
silencedInstances: "サイレンスしたサーバー"
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
muteAndBlock: "ミュートとブロック"
mutedUsers: "ミュートしたユーザー"
blockedUsers: "ブロックしたユーザー"
Expand Down Expand Up @@ -794,7 +797,7 @@ active: "アクティブ"
offline: "オフライン"
notRecommended: "非推奨"
botProtection: "Botプロテクション"
instanceBlocking: "サーバーブロック"
instanceBlocking: "サーバーブロック・サイレンス"
selectAccount: "アカウントを選択"
switchAccount: "アカウントを切り替え"
enabled: "有効"
Expand Down
16 changes: 16 additions & 0 deletions packages/backend/migration/1697247230117-InstanceSilence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

export class InstanceSilence1697247230117 {
name = 'InstanceSilence1697247230117'

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "silencedHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "visibility" DROP NOT NULL`);
kakkokari-gtyih marked this conversation as resolved.
Show resolved Hide resolved
}
}
14 changes: 10 additions & 4 deletions packages/backend/src/core/UserFollowingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { IsNull } from 'typeorm';
import { DataSource, IsNull } from 'typeorm';
syuilo marked this conversation as resolved.
Show resolved Hide resolved
import type { MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { QueueService } from '@/core/QueueService.js';
Expand All @@ -28,6 +28,7 @@ import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js';
import type { Config } from '@/config.js';
import { AccountMoveService } from '@/core/AccountMoveService.js';
import { shouldSilenceInstance } from '@/misc/should-block-instance.js';
import Logger from '../logger.js';

const logger = new Logger('following/create');
Expand All @@ -52,6 +53,9 @@ export class UserFollowingService implements OnModuleInit {
constructor(
private moduleRef: ModuleRef,

@Inject(DI.db)
private db: DataSource,
mattyatea marked this conversation as resolved.
Show resolved Hide resolved

@Inject(DI.config)
private config: Config,

Expand Down Expand Up @@ -121,12 +125,14 @@ export class UserFollowingService implements OnModuleInit {

// フォロー対象が鍵アカウントである or
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである or
// フォロワーがローカルユーザーであり、フォロー対象がサイレンスされているサーバーである
// 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく
if (
followee.isLocked ||
(followeeProfile.carefulBot && follower.isBot) ||
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true')
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true') ||
( this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && await shouldSilenceInstance(follower.host, this.db))
) {
let autoAccept = false;

Expand Down
10 changes: 8 additions & 2 deletions packages/backend/src/core/entities/InstanceEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
syuilo marked this conversation as resolved.
Show resolved Hide resolved
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/Blocking.js';
import type { MiInstance } from '@/models/Instance.js';
import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js';
import { shouldSilenceInstance } from '@/misc/should-block-instance.js';
import { DI } from '@/di-symbols.js';
syuilo marked this conversation as resolved.
Show resolved Hide resolved
import { UtilityService } from '../UtilityService.js';

@Injectable()
export class InstanceEntityService {
constructor(
@Inject(DI.db)
private db: DataSource,
mattyatea marked this conversation as resolved.
Show resolved Hide resolved

syuilo marked this conversation as resolved.
Show resolved Hide resolved
private metaService: MetaService,

private utilityService: UtilityService,
Expand Down Expand Up @@ -43,6 +48,7 @@ export class InstanceEntityService {
description: instance.description,
maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail,
isSilenced: await shouldSilenceInstance(instance.host, this.db),
iconUrl: instance.iconUrl,
faviconUrl: instance.faviconUrl,
themeColor: instance.themeColor,
Expand Down
40 changes: 40 additions & 0 deletions packages/backend/src/misc/fetch-meta.ts
mattyatea marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DataSource } from 'typeorm';
import { MiMeta } from '@/models/Meta.js';

let cache: MiMeta;

export async function fetchMeta(noCache = false, db: DataSource): Promise<MiMeta> {
if (!noCache && cache) return cache;

return await db.transaction(async (transactionalEntityManager) => {
// New IDs are prioritized because multiple records may have been created due to past bugs.
const metas = await transactionalEntityManager.find(MiMeta, {
order: {
id: 'DESC',
},
});

const meta = metas[0];

if (meta) {
cache = meta;
return meta;
} else {
// If fetchMeta is called at the same time when meta is empty, this part may be called at the same time, so use fail-safe upsert.
const saved = await transactionalEntityManager
.upsert(
MiMeta,
{
id: 'x',
},
['id'],
)
.then((x) =>
transactionalEntityManager.findOneByOrFail(MiMeta, x.identifiers[0]),
);

cache = saved;
return saved;
}
});
}
15 changes: 15 additions & 0 deletions packages/backend/src/misc/should-block-instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DataSource } from 'typeorm';
import { fetchMeta } from '@/misc/fetch-meta.js';
import type { MiInstance } from '@/models/Instance.js';
import type { MiMeta } from '@/models/Meta.js';

export async function shouldSilenceInstance(
host: MiInstance['host'],
db : DataSource,
meta?: MiMeta,
): Promise<boolean> {
const { silencedHosts } = meta ?? (await fetchMeta(true, db));
return silencedHosts.some(
(limitedHost: string) => host === limitedHost || host.endsWith(`.${limitedHost}`),
);
}
5 changes: 5 additions & 0 deletions packages/backend/src/models/Meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export class MiMeta {
})
public sensitiveWords: string[];

@Column('varchar', {
length: 1024, array: true, default: '{}',
})
public silencedHosts: string[];

@Column('varchar', {
length: 1024,
nullable: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ export const packedFederationInstanceSchema = {
type: 'string',
optional: false, nullable: true,
},
isSilenced: {
type: "boolean",
optional: false,
nullable: false,
},
infoUpdatedAt: {
type: 'string',
optional: false, nullable: true,
Expand Down
11 changes: 11 additions & 0 deletions packages/backend/src/server/api/endpoints/admin/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
silencedHosts: {
type: "array",
optional: true,
nullable: false,
items: {
type: "string",
optional: false,
nullable: false,
},
},
pinnedUsers: {
type: 'array',
optional: false, nullable: false,
Expand Down Expand Up @@ -367,6 +377,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
pinnedUsers: instance.pinnedUsers,
hiddenTags: instance.hiddenTags,
blockedHosts: instance.blockedHosts,
silencedHosts: instance.silencedHosts,
sensitiveWords: instance.sensitiveWords,
preservedUsernames: instance.preservedUsernames,
hcaptchaSecretKey: instance.hcaptchaSecretKey,
Expand Down
56 changes: 40 additions & 16 deletions packages/backend/src/server/api/endpoints/admin/update-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@ export const paramDef = {
type: 'object',
properties: {
disableRegistration: { type: 'boolean', nullable: true },
pinnedUsers: { type: 'array', nullable: true, items: {
type: 'string',
} },
hiddenTags: { type: 'array', nullable: true, items: {
type: 'string',
} },
blockedHosts: { type: 'array', nullable: true, items: {
type: 'string',
} },
sensitiveWords: { type: 'array', nullable: true, items: {
type: 'string',
} },
pinnedUsers: {
type: 'array', nullable: true, items: {
type: 'string',
},
},
hiddenTags: {
type: 'array', nullable: true, items: {
type: 'string',
},
},
blockedHosts: {
type: 'array', nullable: true, items: {
type: 'string',
},
},
sensitiveWords: {
type: 'array', nullable: true, items: {
type: 'string',
},
},
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
mascotImageUrl: { type: 'string', nullable: true },
bannerUrl: { type: 'string', nullable: true },
Expand Down Expand Up @@ -67,9 +75,11 @@ export const paramDef = {
proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
maintainerName: { type: 'string', nullable: true },
maintainerEmail: { type: 'string', nullable: true },
langs: { type: 'array', items: {
type: 'string',
} },
langs: {
type: 'array', items: {
type: 'string',
},
},
summalyProxy: { type: 'string', nullable: true },
deeplAuthKey: { type: 'string', nullable: true },
deeplIsPro: { type: 'boolean' },
Expand Down Expand Up @@ -115,6 +125,13 @@ export const paramDef = {
perUserHomeTimelineCacheMax: { type: 'integer' },
perUserListTimelineCacheMax: { type: 'integer' },
notesPerOneAd: { type: 'integer' },
silencedHosts: {
type: 'array',
nullable: true,
items: {
type: 'string',
},
},
},
required: [],
} as const;
Expand Down Expand Up @@ -147,7 +164,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (Array.isArray(ps.sensitiveWords)) {
set.sensitiveWords = ps.sensitiveWords.filter(Boolean);
}

if (Array.isArray(ps.silencedHosts)) {
let lastValue = '';
set.silencedHosts = ps.silencedHosts.sort().filter((h) => {
const lv = lastValue;
lastValue = h;
return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
});
}
if (ps.themeColor !== undefined) {
set.themeColor = ps.themeColor;
}
Expand Down
Loading
Loading