From ba734a9f3c2070fbfbd35995e15b83d20a603d6c Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sun, 30 Apr 2023 07:27:55 -0400 Subject: [PATCH 01/14] instance silence --- .../1682844825247-InstanceSilence.js | 63 +++++++++++++++++++ .../backend/src/misc/should-block-instance.ts | 17 +++++ packages/backend/src/models/entities/meta.ts | 5 ++ .../src/models/repositories/instance.ts | 5 +- .../src/models/schema/federation-instance.ts | 5 ++ .../src/server/api/endpoints/admin/meta.ts | 11 ++++ .../server/api/endpoints/admin/update-meta.ts | 16 +++++ .../api/endpoints/federation/instances.ts | 17 +++++ .../backend/src/services/following/create.ts | 7 ++- packages/backend/src/services/note/create.ts | 21 ++++++- packages/calckey-js/src/api.types.ts | 1 + .../client/src/pages/admin/instance-block.vue | 30 ++++++++- 12 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 packages/backend/migration/1682844825247-InstanceSilence.js diff --git a/packages/backend/migration/1682844825247-InstanceSilence.js b/packages/backend/migration/1682844825247-InstanceSilence.js new file mode 100644 index 0000000000..5689c4f160 --- /dev/null +++ b/packages/backend/migration/1682844825247-InstanceSilence.js @@ -0,0 +1,63 @@ +export class InstanceSilence1682844825247 { + name = 'InstanceSilence1682844825247' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "fk_7f4e851a35d81b64dda28eee0"`); + await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_createdAt"`); + await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muteeId"`); + await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muterId"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useStarForReactionFallback"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableGuestTimeline"`); + await queryRunner.query(`ALTER TABLE "meta" ADD "silencedHosts" character varying(256) array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the notification was read.'`); + await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "secureMode" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "privateMode" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "allowedHosts" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-calckey}'`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey'`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey/issues/new'`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS 'The mutee user ID.'`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muterId" IS 'The muter user ID.'`); + await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "isPublic" DROP DEFAULT`); + await queryRunner.query(`CREATE INDEX "IDX_d1259a2c2b7bb413ff449e8711" ON "renote_muting" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_7eac97594bcac5ffcf2068089b" ON "renote_muting" ("muteeId") `); + await queryRunner.query(`CREATE INDEX "IDX_7aa72a5fe76019bfe8e5e0e8b7" ON "renote_muting" ("muterId") `); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0d801c609cec4e9eb4b6b4490c" ON "renote_muting" ("muterId", "muteeId") `); + await queryRunner.query(`CREATE INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5" ON "abuse_user_report" ("targetUserId") `); + await queryRunner.query(`ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d" FOREIGN KEY ("muterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`); + await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d"`); + await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6"`); + await queryRunner.query(`DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_0d801c609cec4e9eb4b6b4490c"`); + await queryRunner.query(`DROP INDEX "public"."IDX_7aa72a5fe76019bfe8e5e0e8b7"`); + await queryRunner.query(`DROP INDEX "public"."IDX_7eac97594bcac5ffcf2068089b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`); + await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "isPublic" SET DEFAULT true`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muterId" IS NULL`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS NULL`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey/issues/new'`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey'`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-misskey}'`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "allowedHosts" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "privateMode" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "secureMode" DROP NOT NULL`); + await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS 'The fallback reaction for emoji reacts'`); + await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the Notification is read.'`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "silencedHosts"`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableGuestTimeline" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "useStarForReactionFallback" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`CREATE INDEX "IDX_renote_muting_muterId" ON "muting" ("muterId") `); + await queryRunner.query(`CREATE INDEX "IDX_renote_muting_muteeId" ON "muting" ("muteeId") `); + await queryRunner.query(`CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `); + await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "fk_7f4e851a35d81b64dda28eee0" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } +} diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts index 6e46232428..66b5832c70 100644 --- a/packages/backend/src/misc/should-block-instance.ts +++ b/packages/backend/src/misc/should-block-instance.ts @@ -18,3 +18,20 @@ export async function shouldBlockInstance( (blockedHost) => host === blockedHost || host.endsWith(`.${blockedHost}`), ); } + +/** + * Returns whether a specific host (punycoded) should be limited. + * + * @param host punycoded instance host + * @param meta a resolved Meta table + * @returns whether the given host should be limited + */ +export async function shouldSilenceInstance( + host: Instance["host"], + meta?: Meta, +): Promise { + const { silencedHosts } = meta ?? (await fetchMeta()); + return silencedHosts.some( + (limitedHost) => host === limitedHost || host.endsWith(`.${limitedHost}`), + ); +} diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 2f77796c4b..84f9af4793 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -97,6 +97,11 @@ export class Meta { }) public blockedHosts: string[]; + @Column('varchar', { + length: 256, array: true, default: '{}', + }) + public silencedHosts: string[]; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts index fb4498911a..bae32b5718 100644 --- a/packages/backend/src/models/repositories/instance.ts +++ b/packages/backend/src/models/repositories/instance.ts @@ -1,12 +1,10 @@ import { db } from "@/db/postgre.js"; import { Instance } from "@/models/entities/instance.js"; import type { Packed } from "@/misc/schema.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { shouldBlockInstance } from "@/misc/should-block-instance.js"; +import { shouldBlockInstance, shouldSilenceInstance } from "@/misc/should-block-instance.js"; export const InstanceRepository = db.getRepository(Instance).extend({ async pack(instance: Instance): Promise> { - const meta = await fetchMeta(); return { id: instance.id, caughtAt: instance.caughtAt.toISOString(), @@ -22,6 +20,7 @@ export const InstanceRepository = db.getRepository(Instance).extend({ isNotResponding: instance.isNotResponding, isSuspended: instance.isSuspended, isBlocked: await shouldBlockInstance(instance.host), + isSilenced: await shouldSilenceInstance(instance.host), softwareName: instance.softwareName, softwareVersion: instance.softwareVersion, openRegistrations: instance.openRegistrations, diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts index ed3369bf11..f793d40f62 100644 --- a/packages/backend/src/models/schema/federation-instance.ts +++ b/packages/backend/src/models/schema/federation-instance.ts @@ -68,6 +68,11 @@ export const packedFederationInstanceSchema = { optional: false, nullable: false, }, + isSilenced: { + type: "boolean", + optional: false, + nullable: false, + }, softwareName: { type: "string", optional: false, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index f0ac57892d..89928af11c 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -259,6 +259,16 @@ export const meta = { nullable: false, }, }, + silencedHosts: { + type: "array", + optional: true, + nullable: false, + items: { + type: "string", + optional: false, + nullable: false, + }, + }, allowedHosts: { type: "array", optional: true, @@ -524,6 +534,7 @@ export default define(meta, paramDef, async (ps, me) => { customSplashIcons: instance.customSplashIcons, hiddenTags: instance.hiddenTags, blockedHosts: instance.blockedHosts, + silencedHosts: instance.silencedHosts, allowedHosts: instance.allowedHosts, privateMode: instance.privateMode, secureMode: instance.secureMode, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index a230007323..7f92e5e29e 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -61,6 +61,13 @@ export const paramDef = { type: "string", }, }, + silencedHosts: { + type: "array", + nullable: true, + items: { + type: "string", + }, + }, allowedHosts: { type: "array", nullable: true, @@ -219,6 +226,15 @@ export default define(meta, paramDef, async (ps, me) => { }); } + if (Array.isArray(ps.silencedHosts)) { + let lastValue = ""; + set.silencedHosts = ps.silencedHosts.sort().filter((h) => { + const lv = lastValue; + lastValue = h; + return h !== "" && h !== lv; + }); + } + if (ps.themeColor !== undefined) { set.themeColor = ps.themeColor; } diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 8f6184b196..646f38282b 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -34,6 +34,7 @@ export const paramDef = { notResponding: { type: "boolean", nullable: true }, suspended: { type: "boolean", nullable: true }, federating: { type: "boolean", nullable: true }, + silenced: { type: "boolean", nullable: true }, subscribing: { type: "boolean", nullable: true }, publishing: { type: "boolean", nullable: true }, limit: { type: "integer", minimum: 1, maximum: 100, default: 30 }, @@ -115,6 +116,22 @@ export default define(meta, paramDef, async (ps, me) => { } } + if (typeof ps.silenced === "boolean") { + const meta = await fetchMeta(true); + if (ps.silenced) { + if (meta.silencedHosts.length === 0) { + return []; + } + query.andWhere("instance.host IN (:...silences)", { + silences: meta.silencedHosts, + }); + } else if (meta.silencedHosts.length > 0) { + query.andWhere("instance.host NOT IN (:...silences)", { + silences: meta.silencedHosts, + }); + } + } + if (typeof ps.notResponding === "boolean") { if (ps.notResponding) { query.andWhere("instance.isNotResponding = TRUE"); diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index 61a8c6b268..cb5a888beb 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -27,6 +27,7 @@ import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js import type { Packed } from "@/misc/schema.js"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { webhookDeliver } from "@/queue/index.js"; +import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; const logger = new Logger("following/create"); @@ -227,12 +228,14 @@ export default async function ( // フォロー対象が鍵アカウントである or // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or - // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである + // フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである or + // The follower is remote, the followee is local, and the follower is in a silenced instance. // 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく if ( followee.isLocked || (followeeProfile.carefulBot && follower.isBot) || - (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) + (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) || + (Users.isRemoteUser(follower) && Users.isLocalUser(followee) && await shouldSilenceInstance(follower.host)) ) { let autoAccept = false; diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 5dd324d89a..3bccf33f7f 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -39,7 +39,7 @@ import { } from "@/models/index.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import type { App } from "@/models/entities/app.js"; -import { Not, In } from "typeorm"; +import { Not, In, IsNull } from "typeorm"; import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; import { genId } from "@/misc/gen-id.js"; import { @@ -66,6 +66,7 @@ import { Cache } from "@/misc/cache.js"; import type { UserProfile } from "@/models/entities/user-profile.js"; import { db } from "@/db/postgre.js"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; +import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; const mutedWordsCache = new Cache< { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] @@ -166,7 +167,8 @@ export default async ( data: Option, silent = false, ) => - new Promise(async (res, rej) => { +// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME +new Promise(async (res, rej) => { // If you reply outside the channel, match the scope of the target. // TODO (I think it's a process that could be done on the client side, but it's server side for now.) if ( @@ -203,6 +205,13 @@ export default async ( data.visibility = "home"; } + const inSilencedInstance = Users.isRemoteUser(user) && await shouldSilenceInstance(user.host); + + // If the + if (data.visibility === "public" && inSilencedInstance) { + data.visibility = "home"; + } + // Reject if the target of the renote is a public range other than "Home or Entire". if ( data.renote && @@ -307,6 +316,14 @@ export default async ( } } + // Remove from mention the local users who aren't following the remote user in the silenced instance. + if (inSilencedInstance) { + const relations = await Followings.findBy([ + { followeeId: user.id, followerHost: IsNull() }, // a local user following the silenced user + ]).then(rels => rels.map(rel => rel.followerId)); + mentionedUsers = mentionedUsers.filter(mentioned => relations.includes(mentioned.id)); + } + const note = await insertNote(user, data, tags, emojis, mentionedUsers); res(note); diff --git a/packages/calckey-js/src/api.types.ts b/packages/calckey-js/src/api.types.ts index bef00da4ea..478b86721c 100644 --- a/packages/calckey-js/src/api.types.ts +++ b/packages/calckey-js/src/api.types.ts @@ -55,6 +55,7 @@ export type Endpoints = { "admin/get-table-stats": { req: TODO; res: TODO }; "admin/invite": { req: TODO; res: TODO }; "admin/logs": { req: TODO; res: TODO }; + "admin/meta": { req: TODO; res: TODO }; "admin/reset-password": { req: TODO; res: TODO }; "admin/resolve-abuse-user-report": { req: TODO; res: TODO }; "admin/resync-chart": { req: TODO; res: TODO }; diff --git a/packages/client/src/pages/admin/instance-block.vue b/packages/client/src/pages/admin/instance-block.vue index 80231b11e2..688578ff45 100644 --- a/packages/client/src/pages/admin/instance-block.vue +++ b/packages/client/src/pages/admin/instance-block.vue @@ -2,18 +2,25 @@ - + {{ i18n.ts.blockedInstances }} + + {{ i18n.ts.silencedInstances }} + + @@ -35,15 +42,21 @@ import { i18n } from "@/i18n"; import { definePageMetadata } from "@/scripts/page-metadata"; let blockedHosts: string = $ref(""); +let silencedHosts: string = $ref(""); +let tab = $ref("block"); async function init() { const meta = await os.api("admin/meta"); - blockedHosts = meta.blockedHosts.join("\n"); + if (meta) { + blockedHosts = meta.blockedHosts.join("\n"); + silencedHosts = meta.silencedHosts.join("\n"); + } } function save() { os.apiWithDialog("admin/update-meta", { blockedHosts: blockedHosts.split("\n").map((h) => h.trim()) || [], + silencedHosts: silencedHosts.split("\n").map((h) => h.trim()) || [], }).then(() => { fetchInstance(); }); @@ -51,7 +64,18 @@ function save() { const headerActions = $computed(() => []); -const headerTabs = $computed(() => []); +const headerTabs = $computed(() => [ + { + key: "block", + title: i18n.ts.block, + icon: "ph-prohibit ph-bold ph-lg", + }, + { + key: "silence", + title: i18n.ts.silence, + icon: "ph-eye-slash ph-bold ph-lg", + }, +]); definePageMetadata({ title: i18n.ts.instanceBlocking, From 151b30c53d77d37db25d70eb025d3b7139be7d6d Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sun, 30 Apr 2023 07:58:03 -0400 Subject: [PATCH 02/14] rename and comment --- packages/backend/src/misc/should-block-instance.ts | 2 +- packages/backend/src/services/note/create.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts index 66b5832c70..47f9200d49 100644 --- a/packages/backend/src/misc/should-block-instance.ts +++ b/packages/backend/src/misc/should-block-instance.ts @@ -32,6 +32,6 @@ export async function shouldSilenceInstance( ): Promise { const { silencedHosts } = meta ?? (await fetchMeta()); return silencedHosts.some( - (limitedHost) => host === limitedHost || host.endsWith(`.${limitedHost}`), + (silencedHost) => host === silencedHost || host.endsWith(`.${silencedHost}`), ); } diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 3bccf33f7f..bd3a0224a1 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -207,7 +207,7 @@ new Promise(async (res, rej) => { const inSilencedInstance = Users.isRemoteUser(user) && await shouldSilenceInstance(user.host); - // If the + // Enforce home visibility if the user is in a silenced instance. if (data.visibility === "public" && inSilencedInstance) { data.visibility = "home"; } From 9bc872dc00fbd026f3e1c88e5bfc697ac9be7c76 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sun, 30 Apr 2023 08:08:45 -0400 Subject: [PATCH 03/14] format --- .../1682844825247-InstanceSilence.js | 220 +++++++++++++----- .../backend/src/misc/should-block-instance.ts | 3 +- .../src/models/repositories/instance.ts | 5 +- .../backend/src/services/following/create.ts | 4 +- packages/backend/src/services/note/create.ts | 13 +- .../client/src/pages/admin/instance-block.vue | 12 +- 6 files changed, 188 insertions(+), 69 deletions(-) diff --git a/packages/backend/migration/1682844825247-InstanceSilence.js b/packages/backend/migration/1682844825247-InstanceSilence.js index 5689c4f160..4c05b349d7 100644 --- a/packages/backend/migration/1682844825247-InstanceSilence.js +++ b/packages/backend/migration/1682844825247-InstanceSilence.js @@ -1,63 +1,165 @@ export class InstanceSilence1682844825247 { - name = 'InstanceSilence1682844825247' + name = "InstanceSilence1682844825247"; - async up(queryRunner) { - await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "fk_7f4e851a35d81b64dda28eee0"`); - await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_createdAt"`); - await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muteeId"`); - await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muterId"`); - await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useStarForReactionFallback"`); - await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableGuestTimeline"`); - await queryRunner.query(`ALTER TABLE "meta" ADD "silencedHosts" character varying(256) array NOT NULL DEFAULT '{}'`); - await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the notification was read.'`); - await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "secureMode" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "privateMode" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "allowedHosts" SET NOT NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-calckey}'`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey'`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey/issues/new'`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS 'The mutee user ID.'`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muterId" IS 'The muter user ID.'`); - await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "isPublic" DROP DEFAULT`); - await queryRunner.query(`CREATE INDEX "IDX_d1259a2c2b7bb413ff449e8711" ON "renote_muting" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_7eac97594bcac5ffcf2068089b" ON "renote_muting" ("muteeId") `); - await queryRunner.query(`CREATE INDEX "IDX_7aa72a5fe76019bfe8e5e0e8b7" ON "renote_muting" ("muterId") `); - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0d801c609cec4e9eb4b6b4490c" ON "renote_muting" ("muterId", "muteeId") `); - await queryRunner.query(`CREATE INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5" ON "abuse_user_report" ("targetUserId") `); - await queryRunner.query(`ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d" FOREIGN KEY ("muterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } + async up(queryRunner) { + await queryRunner.query( + `ALTER TABLE "abuse_user_report" DROP CONSTRAINT "fk_7f4e851a35d81b64dda28eee0"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_renote_muting_createdAt"`, + ); + await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muteeId"`); + await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muterId"`); + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "useStarForReactionFallback"`, + ); + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "enableGuestTimeline"`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ADD "silencedHosts" character varying(256) array NOT NULL DEFAULT '{}'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "notification"."isRead" IS 'Whether the notification was read.'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "meta"."defaultReaction" IS NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "secureMode" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "privateMode" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "allowedHosts" SET NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-calckey}'`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey'`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://codeberg.org/calckey/calckey/issues/new'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."muteeId" IS 'The mutee user ID.'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."muterId" IS 'The muter user ID.'`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER COLUMN "isPublic" DROP DEFAULT`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_d1259a2c2b7bb413ff449e8711" ON "renote_muting" ("createdAt") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_7eac97594bcac5ffcf2068089b" ON "renote_muting" ("muteeId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_7aa72a5fe76019bfe8e5e0e8b7" ON "renote_muting" ("muterId") `, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_0d801c609cec4e9eb4b6b4490c" ON "renote_muting" ("muterId", "muteeId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5" ON "abuse_user_report" ("targetUserId") `, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d" FOREIGN KEY ("muterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } - async down(queryRunner) { - await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`); - await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d"`); - await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6"`); - await queryRunner.query(`DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`); - await queryRunner.query(`DROP INDEX "public"."IDX_0d801c609cec4e9eb4b6b4490c"`); - await queryRunner.query(`DROP INDEX "public"."IDX_7aa72a5fe76019bfe8e5e0e8b7"`); - await queryRunner.query(`DROP INDEX "public"."IDX_7eac97594bcac5ffcf2068089b"`); - await queryRunner.query(`DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`); - await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "isPublic" SET DEFAULT true`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muterId" IS NULL`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS NULL`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey/issues/new'`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey'`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-misskey}'`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "allowedHosts" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "privateMode" DROP NOT NULL`); - await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "secureMode" DROP NOT NULL`); - await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS 'The fallback reaction for emoji reacts'`); - await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the Notification is read.'`); - await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "silencedHosts"`); - await queryRunner.query(`ALTER TABLE "meta" ADD "enableGuestTimeline" boolean NOT NULL DEFAULT false`); - await queryRunner.query(`ALTER TABLE "meta" ADD "useStarForReactionFallback" boolean NOT NULL DEFAULT false`); - await queryRunner.query(`CREATE INDEX "IDX_renote_muting_muterId" ON "muting" ("muterId") `); - await queryRunner.query(`CREATE INDEX "IDX_renote_muting_muteeId" ON "muting" ("muteeId") `); - await queryRunner.query(`CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `); - await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "fk_7f4e851a35d81b64dda28eee0" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - } + async down(queryRunner) { + await queryRunner.query( + `ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d"`, + ); + await queryRunner.query( + `ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_0d801c609cec4e9eb4b6b4490c"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_7aa72a5fe76019bfe8e5e0e8b7"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_7eac97594bcac5ffcf2068089b"`, + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`, + ); + await queryRunner.query( + `ALTER TABLE "page" ALTER COLUMN "isPublic" SET DEFAULT true`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."muterId" IS NULL`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."muteeId" IS NULL`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "renote_muting"."createdAt" IS NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey/issues/new'`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey'`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-misskey}'`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "allowedHosts" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "privateMode" DROP NOT NULL`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "secureMode" DROP NOT NULL`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "meta"."defaultReaction" IS 'The fallback reaction for emoji reacts'`, + ); + await queryRunner.query( + `COMMENT ON COLUMN "notification"."isRead" IS 'Whether the Notification is read.'`, + ); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "silencedHosts"`); + await queryRunner.query( + `ALTER TABLE "meta" ADD "enableGuestTimeline" boolean NOT NULL DEFAULT false`, + ); + await queryRunner.query( + `ALTER TABLE "meta" ADD "useStarForReactionFallback" boolean NOT NULL DEFAULT false`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_renote_muting_muterId" ON "muting" ("muterId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_renote_muting_muteeId" ON "muting" ("muteeId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `, + ); + await queryRunner.query( + `ALTER TABLE "abuse_user_report" ADD CONSTRAINT "fk_7f4e851a35d81b64dda28eee0" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } } diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts index 47f9200d49..35ed307931 100644 --- a/packages/backend/src/misc/should-block-instance.ts +++ b/packages/backend/src/misc/should-block-instance.ts @@ -32,6 +32,7 @@ export async function shouldSilenceInstance( ): Promise { const { silencedHosts } = meta ?? (await fetchMeta()); return silencedHosts.some( - (silencedHost) => host === silencedHost || host.endsWith(`.${silencedHost}`), + (silencedHost) => + host === silencedHost || host.endsWith(`.${silencedHost}`), ); } diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts index bae32b5718..667ec948de 100644 --- a/packages/backend/src/models/repositories/instance.ts +++ b/packages/backend/src/models/repositories/instance.ts @@ -1,7 +1,10 @@ import { db } from "@/db/postgre.js"; import { Instance } from "@/models/entities/instance.js"; import type { Packed } from "@/misc/schema.js"; -import { shouldBlockInstance, shouldSilenceInstance } from "@/misc/should-block-instance.js"; +import { + shouldBlockInstance, + shouldSilenceInstance, +} from "@/misc/should-block-instance.js"; export const InstanceRepository = db.getRepository(Instance).extend({ async pack(instance: Instance): Promise> { diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index cb5a888beb..c987a01e59 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -235,7 +235,9 @@ export default async function ( followee.isLocked || (followeeProfile.carefulBot && follower.isBot) || (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) || - (Users.isRemoteUser(follower) && Users.isLocalUser(followee) && await shouldSilenceInstance(follower.host)) + (Users.isRemoteUser(follower) && + Users.isLocalUser(followee) && + (await shouldSilenceInstance(follower.host))) ) { let autoAccept = false; diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index bd3a0224a1..ad50bd97a4 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -167,8 +167,8 @@ export default async ( data: Option, silent = false, ) => -// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME -new Promise(async (res, rej) => { + // rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME + new Promise(async (res, rej) => { // If you reply outside the channel, match the scope of the target. // TODO (I think it's a process that could be done on the client side, but it's server side for now.) if ( @@ -205,7 +205,8 @@ new Promise(async (res, rej) => { data.visibility = "home"; } - const inSilencedInstance = Users.isRemoteUser(user) && await shouldSilenceInstance(user.host); + const inSilencedInstance = + Users.isRemoteUser(user) && (await shouldSilenceInstance(user.host)); // Enforce home visibility if the user is in a silenced instance. if (data.visibility === "public" && inSilencedInstance) { @@ -320,8 +321,10 @@ new Promise(async (res, rej) => { if (inSilencedInstance) { const relations = await Followings.findBy([ { followeeId: user.id, followerHost: IsNull() }, // a local user following the silenced user - ]).then(rels => rels.map(rel => rel.followerId)); - mentionedUsers = mentionedUsers.filter(mentioned => relations.includes(mentioned.id)); + ]).then((rels) => rels.map((rel) => rel.followerId)); + mentionedUsers = mentionedUsers.filter((mentioned) => + relations.includes(mentioned.id), + ); } const note = await insertNote(user, data, tags, emojis, mentionedUsers); diff --git a/packages/client/src/pages/admin/instance-block.vue b/packages/client/src/pages/admin/instance-block.vue index 688578ff45..3a9a17fa08 100644 --- a/packages/client/src/pages/admin/instance-block.vue +++ b/packages/client/src/pages/admin/instance-block.vue @@ -9,13 +9,21 @@ /> - + {{ i18n.ts.blockedInstances }} - + {{ i18n.ts.silencedInstances }}