From bb3d7109271a678487208df1cff3a11e28ceedbc Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sun, 16 Mar 2025 10:49:16 -0400 Subject: [PATCH] allow unsigned fetch for all system users --- .../migration/1740162088574-add_unsignedFetch.js | 4 ++-- packages/backend/src/core/CreateSystemUserService.ts | 10 ++++++++-- packages/backend/src/core/InstanceActorService.ts | 10 +--------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/backend/migration/1740162088574-add_unsignedFetch.js b/packages/backend/migration/1740162088574-add_unsignedFetch.js index 855a3796aa..0744e68dfa 100644 --- a/packages/backend/migration/1740162088574-add_unsignedFetch.js +++ b/packages/backend/migration/1740162088574-add_unsignedFetch.js @@ -12,8 +12,8 @@ export class AddUnsignedFetch1740162088574 { await queryRunner.query(`CREATE TYPE "public"."user_allowunsignedfetch_enum" AS ENUM('never', 'always', 'essential', 'staff')`); await queryRunner.query(`ALTER TABLE "user" ADD "allowUnsignedFetch" "public"."user_allowunsignedfetch_enum" NOT NULL DEFAULT 'staff'`); - // Special one-time migration: allow unauthorized fetch for instance actor - await queryRunner.query(`UPDATE "user" SET "allowUnsignedFetch" = 'always' WHERE "username" = 'instance.actor' AND "host" IS null`); + // Special one-time migration: allow unauthorized fetch for system accounts + await queryRunner.query(`UPDATE "user" SET "allowUnsignedFetch" = 'always' WHERE "username" LIKE '%.%' AND "host" IS null`); // Special one-time migration: convert legacy config "" to meta setting "" const config = await loadConfig(); diff --git a/packages/backend/src/core/CreateSystemUserService.ts b/packages/backend/src/core/CreateSystemUserService.ts index d198707a42..a0aa6bad06 100644 --- a/packages/backend/src/core/CreateSystemUserService.ts +++ b/packages/backend/src/core/CreateSystemUserService.ts @@ -29,7 +29,7 @@ export class CreateSystemUserService { } @bindThis - public async createSystemUser(username: string, data?: Partial): Promise { + public async createSystemUser(username: string): Promise { const password = randomUUID(); // Generate hash of password @@ -63,7 +63,13 @@ export class CreateSystemUserService { isExplorable: false, approved: true, isBot: true, - ...(data ?? {}), + /* we always allow requests about our instance actor, because when + a remote instance needs to check our signature on a request we + sent, it will need to fetch information about the user that + signed it (which is our instance actor), and if we try to check + their signature on *that* request, we'll fetch *their* instance + actor... leading to an infinite recursion */ + allowUnsignedFetch: 'always', }).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0])); await transactionalEntityManager.insert(MiUserKeypair, { diff --git a/packages/backend/src/core/InstanceActorService.ts b/packages/backend/src/core/InstanceActorService.ts index 6c0e360588..22c47297a3 100644 --- a/packages/backend/src/core/InstanceActorService.ts +++ b/packages/backend/src/core/InstanceActorService.ts @@ -49,15 +49,7 @@ export class InstanceActorService { this.cache.set(user); return user; } else { - const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME, { - /* we always allow requests about our instance actor, because when - a remote instance needs to check our signature on a request we - sent, it will need to fetch information about the user that - signed it (which is our instance actor), and if we try to check - their signature on *that* request, we'll fetch *their* instance - actor... leading to an infinite recursion */ - allowUnsignedFetch: 'always', - }) as MiLocalUser; + const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as MiLocalUser; this.cache.set(created); return created; }