This commit is contained in:
Namekuji 2023-04-30 08:08:45 -04:00
parent ada759a9e5
commit c35f03832d
6 changed files with 188 additions and 69 deletions

View file

@ -1,63 +1,165 @@
export class InstanceSilence1682844825247 { export class InstanceSilence1682844825247 {
name = 'InstanceSilence1682844825247' name = "InstanceSilence1682844825247";
async up(queryRunner) { async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "fk_7f4e851a35d81b64dda28eee0"`); await queryRunner.query(
await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_createdAt"`); `ALTER TABLE "abuse_user_report" DROP CONSTRAINT "fk_7f4e851a35d81b64dda28eee0"`,
await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muteeId"`); );
await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muterId"`); await queryRunner.query(
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useStarForReactionFallback"`); `DROP INDEX "public"."IDX_renote_muting_createdAt"`,
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(`DROP INDEX "public"."IDX_renote_muting_muteeId"`);
await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the notification was read.'`); await queryRunner.query(`DROP INDEX "public"."IDX_renote_muting_muterId"`);
await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS NULL`); await queryRunner.query(
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "secureMode" SET NOT NULL`); `ALTER TABLE "meta" DROP COLUMN "useStarForReactionFallback"`,
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(
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "pinnedPages" SET DEFAULT '{/featured,/channels,/explore,/pages,/about-calckey}'`); `ALTER TABLE "meta" DROP COLUMN "enableGuestTimeline"`,
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(
await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`); `ALTER TABLE "meta" ADD "silencedHosts" character varying(256) array NOT NULL DEFAULT '{}'`,
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(
await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "isPublic" DROP DEFAULT`); `COMMENT ON COLUMN "notification"."isRead" IS 'Whether the notification was read.'`,
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(
await queryRunner.query(`CREATE INDEX "IDX_7aa72a5fe76019bfe8e5e0e8b7" ON "renote_muting" ("muterId") `); `COMMENT ON COLUMN "meta"."defaultReaction" IS NULL`,
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(
await queryRunner.query(`ALTER TABLE "renote_muting" ADD CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); `ALTER TABLE "meta" ALTER COLUMN "secureMode" SET NOT NULL`,
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`); 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) { async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`); await queryRunner.query(
await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d"`); `ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`,
await queryRunner.query(`ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6"`); );
await queryRunner.query(`DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`); await queryRunner.query(
await queryRunner.query(`DROP INDEX "public"."IDX_0d801c609cec4e9eb4b6b4490c"`); `ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7aa72a5fe76019bfe8e5e0e8b7d"`,
await queryRunner.query(`DROP INDEX "public"."IDX_7aa72a5fe76019bfe8e5e0e8b7"`); );
await queryRunner.query(`DROP INDEX "public"."IDX_7eac97594bcac5ffcf2068089b"`); await queryRunner.query(
await queryRunner.query(`DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`); `ALTER TABLE "renote_muting" DROP CONSTRAINT "FK_7eac97594bcac5ffcf2068089b6"`,
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(
await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS NULL`); `DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`,
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(
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://github.com/misskey-dev/misskey'`); `DROP INDEX "public"."IDX_0d801c609cec4e9eb4b6b4490c"`,
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(
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "privateMode" DROP NOT NULL`); `DROP INDEX "public"."IDX_7aa72a5fe76019bfe8e5e0e8b7"`,
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(
await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the Notification is read.'`); `DROP INDEX "public"."IDX_7eac97594bcac5ffcf2068089b"`,
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(
await queryRunner.query(`ALTER TABLE "meta" ADD "useStarForReactionFallback" boolean NOT NULL DEFAULT false`); `DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`,
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(
await queryRunner.query(`CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `); `ALTER TABLE "page" ALTER COLUMN "isPublic" SET DEFAULT true`,
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`); );
} 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`,
);
}
} }

View file

@ -32,6 +32,7 @@ export async function shouldSilenceInstance(
): Promise<boolean> { ): Promise<boolean> {
const { silencedHosts } = meta ?? (await fetchMeta()); const { silencedHosts } = meta ?? (await fetchMeta());
return silencedHosts.some( return silencedHosts.some(
(silencedHost) => host === silencedHost || host.endsWith(`.${silencedHost}`), (silencedHost) =>
host === silencedHost || host.endsWith(`.${silencedHost}`),
); );
} }

View file

@ -1,7 +1,10 @@
import { db } from "@/db/postgre.js"; import { db } from "@/db/postgre.js";
import { Instance } from "@/models/entities/instance.js"; import { Instance } from "@/models/entities/instance.js";
import type { Packed } from "@/misc/schema.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({ export const InstanceRepository = db.getRepository(Instance).extend({
async pack(instance: Instance): Promise<Packed<"FederationInstance">> { async pack(instance: Instance): Promise<Packed<"FederationInstance">> {

View file

@ -235,7 +235,9 @@ export default async function (
followee.isLocked || followee.isLocked ||
(followeeProfile.carefulBot && follower.isBot) || (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)) (Users.isRemoteUser(follower) &&
Users.isLocalUser(followee) &&
(await shouldSilenceInstance(follower.host)))
) { ) {
let autoAccept = false; let autoAccept = false;

View file

@ -167,8 +167,8 @@ export default async (
data: Option, data: Option,
silent = false, silent = false,
) => ) =>
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME // rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
new Promise<Note>(async (res, rej) => { new Promise<Note>(async (res, rej) => {
// If you reply outside the channel, match the scope of the target. // 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.) // TODO (I think it's a process that could be done on the client side, but it's server side for now.)
if ( if (
@ -205,7 +205,8 @@ new Promise<Note>(async (res, rej) => {
data.visibility = "home"; 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. // Enforce home visibility if the user is in a silenced instance.
if (data.visibility === "public" && inSilencedInstance) { if (data.visibility === "public" && inSilencedInstance) {
@ -320,8 +321,10 @@ new Promise<Note>(async (res, rej) => {
if (inSilencedInstance) { if (inSilencedInstance) {
const relations = await Followings.findBy([ const relations = await Followings.findBy([
{ followeeId: user.id, followerHost: IsNull() }, // a local user following the silenced user { followeeId: user.id, followerHost: IsNull() }, // a local user following the silenced user
]).then(rels => rels.map(rel => rel.followerId)); ]).then((rels) => rels.map((rel) => rel.followerId));
mentionedUsers = mentionedUsers.filter(mentioned => relations.includes(mentioned.id)); mentionedUsers = mentionedUsers.filter((mentioned) =>
relations.includes(mentioned.id),
);
} }
const note = await insertNote(user, data, tags, emojis, mentionedUsers); const note = await insertNote(user, data, tags, emojis, mentionedUsers);

View file

@ -9,13 +9,21 @@
/></template> /></template>
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> <MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init"> <FormSuspense :p="init">
<FormTextarea v-if="tab === 'block'" v-model="blockedHosts" class="_formBlock"> <FormTextarea
v-if="tab === 'block'"
v-model="blockedHosts"
class="_formBlock"
>
<span>{{ i18n.ts.blockedInstances }}</span> <span>{{ i18n.ts.blockedInstances }}</span>
<template #caption>{{ <template #caption>{{
i18n.ts.blockedInstancesDescription i18n.ts.blockedInstancesDescription
}}</template> }}</template>
</FormTextarea> </FormTextarea>
<FormTextarea v-else-if="tab === 'silence'" v-model="silencedHosts" class="_formBlock"> <FormTextarea
v-else-if="tab === 'silence'"
v-model="silencedHosts"
class="_formBlock"
>
<span>{{ i18n.ts.silencedInstances }}</span> <span>{{ i18n.ts.silencedInstances }}</span>
<template #caption>{{ <template #caption>{{
i18n.ts.silencedInstancesDescription i18n.ts.silencedInstancesDescription