summaryrefslogtreecommitdiff
path: root/packages/backend
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-05-24 18:28:21 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-05-28 21:31:39 -0400
commit45e5749cca8ddf11ba01ab3d669cff9517045a3f (patch)
tree6c9f15aac52a1e5e270079075a2d909833e45927 /packages/backend
parentadd IDX_instance_host_key (diff)
downloadsharkey-45e5749cca8ddf11ba01ab3d669cff9517045a3f.tar.gz
sharkey-45e5749cca8ddf11ba01ab3d669cff9517045a3f.tar.bz2
sharkey-45e5749cca8ddf11ba01ab3d669cff9517045a3f.zip
add instance properties for persisted block data
Diffstat (limited to 'packages/backend')
-rw-r--r--packages/backend/migration/1748105111513-add_instance_block_columns.js89
-rw-r--r--packages/backend/src/models/Instance.ts50
2 files changed, 139 insertions, 0 deletions
diff --git a/packages/backend/migration/1748105111513-add_instance_block_columns.js b/packages/backend/migration/1748105111513-add_instance_block_columns.js
new file mode 100644
index 0000000000..c9087604e5
--- /dev/null
+++ b/packages/backend/migration/1748105111513-add_instance_block_columns.js
@@ -0,0 +1,89 @@
+/*
+ * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/**
+ * @typedef {import('typeorm').MigrationInterface} MigrationInterface
+ * @typedef {{ blockedHosts: string[], silencedHosts: string[], mediaSilencedHosts: string[], federationHosts: string[], bubbleInstances: string[] }} Meta
+ */
+
+/**
+ * @class
+ * @implements {MigrationInterface}
+ */
+export class AddInstanceBlockColumns1748105111513 {
+ name = 'AddInstanceBlockColumns1748105111513'
+
+ async up(queryRunner) {
+ // Schema migration
+ await queryRunner.query(`ALTER TABLE "instance" ADD "isBlocked" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "instance"."isBlocked" IS 'True if this instance is blocked from federation.'`);
+ await queryRunner.query(`ALTER TABLE "instance" ADD "isAllowListed" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "instance"."isAllowListed" IS 'True if this instance is allow-listed.'`);
+ await queryRunner.query(`ALTER TABLE "instance" ADD "isBubbled" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "instance"."isBubbled" IS 'True if this instance is part of the local bubble.'`);
+ await queryRunner.query(`ALTER TABLE "instance" ADD "isSilenced" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "instance"."isSilenced" IS 'True if this instance is silenced.'`);
+ await queryRunner.query(`ALTER TABLE "instance" ADD "isMediaSilenced" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "instance"."isMediaSilenced" IS 'True if this instance is media-silenced.'`);
+
+ // Data migration
+ /** @type {Meta[]} */
+ const metas = await queryRunner.query(`SELECT "blockedHosts", "silencedHosts", "mediaSilencedHosts", "federationHosts", "bubbleInstances" FROM "meta"`);
+ if (metas.length > 0) {
+ /** @type {Meta} */
+ const meta = metas[0];
+
+ // Blocked hosts
+ if (meta.blockedHosts.length > 0) {
+ const pattern = buildPatterns(meta.blockedHosts);
+ await queryRunner.query(`UPDATE "instance" SET "isBlocked" = true WHERE ((lower(reverse("host")) || '.')::text) LIKE ANY ${pattern}`);
+ }
+
+ // Silenced hosts
+ if (meta.silencedHosts.length > 0) {
+ const pattern = buildPatterns(meta.silencedHosts);
+ await queryRunner.query(`UPDATE "instance" SET "isSilenced" = true WHERE ((lower(reverse("host")) || '.')::text) LIKE ANY ${pattern}`);
+ }
+
+ // Media silenced hosts
+ if (meta.mediaSilencedHosts.length > 0) {
+ const pattern = buildPatterns(meta.mediaSilencedHosts);
+ await queryRunner.query(`UPDATE "instance" SET "isMediaSilenced" = true WHERE ((lower(reverse("host")) || '.')::text) LIKE ANY ${pattern}`);
+ }
+
+ // Allow-listed hosts
+ if (meta.federationHosts.length > 0) {
+ const pattern = buildPatterns(meta.federationHosts);
+ await queryRunner.query(`UPDATE "instance" SET "isAllowListed" = true WHERE ((lower(reverse("host")) || '.')::text) LIKE ANY ${pattern}`);
+ }
+
+ // Bubbled hosts
+ if (meta.bubbleInstances.length > 0) {
+ const pattern = buildPatterns(meta.bubbleInstances);
+ await queryRunner.query(`UPDATE "instance" SET "isBubbled" = true WHERE ((lower(reverse("host")) || '.')::text) LIKE ANY ${pattern}`);
+ }
+ }
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isMediaSilenced"`);
+ await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isSilenced"`);
+ await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isBubbled"`);
+ await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isAllowListed"`);
+ await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isBlocked"`);
+ }
+}
+
+/**
+ * @param {string[]} input
+ * @returns {string}
+ */
+function buildPatterns(input) {
+ const strings = input
+ .map(i => i.toLowerCase().split('').reverse().join('') + '.%')
+ .map(i => `'${i}'`)
+ .join(', ');
+ return `(array[${strings}]::text[])`;
+}
diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts
index 5d8108d423..0022e58933 100644
--- a/packages/backend/src/models/Instance.ts
+++ b/packages/backend/src/models/Instance.ts
@@ -99,6 +99,56 @@ export class MiInstance {
})
public suspensionState: 'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding';
+ /**
+ * True if this instance is blocked from federation.
+ */
+ @Column('boolean', {
+ nullable: false,
+ default: false,
+ comment: 'True if this instance is blocked from federation.',
+ })
+ public isBlocked: boolean;
+
+ /**
+ * True if this instance is allow-listed.
+ */
+ @Column('boolean', {
+ nullable: false,
+ default: false,
+ comment: 'True if this instance is allow-listed.',
+ })
+ public isAllowListed: boolean;
+
+ /**
+ * True if this instance is part of the local bubble.
+ */
+ @Column('boolean', {
+ nullable: false,
+ default: false,
+ comment: 'True if this instance is part of the local bubble.',
+ })
+ public isBubbled: boolean;
+
+ /**
+ * True if this instance is silenced.
+ */
+ @Column('boolean', {
+ nullable: false,
+ default: false,
+ comment: 'True if this instance is silenced.',
+ })
+ public isSilenced: boolean;
+
+ /**
+ * True if this instance is media-silenced.
+ */
+ @Column('boolean', {
+ nullable: false,
+ default: false,
+ comment: 'True if this instance is media-silenced.',
+ })
+ public isMediaSilenced: boolean;
+
@Column('varchar', {
length: 64, nullable: true,
comment: 'The software of the Instance.',