From 9f1d7907e42e8ce52ee024f5c7139259ac10c17c Mon Sep 17 00:00:00 2001 From: eternal-flame-AD Date: Tue, 19 Nov 2024 21:07:02 -0600 Subject: [PATCH] fix(backend): Atomically mark remote account deletions Signed-off-by: eternal-flame-AD --- .../migration/1732071810971-IndexUserDeleted.js | 16 ++++++++++++++++ .../src/core/activitypub/ApInboxService.ts | 9 +-------- .../core/activitypub/models/ApPersonService.ts | 4 ++-- 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 packages/backend/migration/1732071810971-IndexUserDeleted.js diff --git a/packages/backend/migration/1732071810971-IndexUserDeleted.js b/packages/backend/migration/1732071810971-IndexUserDeleted.js new file mode 100644 index 0000000000..b4c3d714ad --- /dev/null +++ b/packages/backend/migration/1732071810971-IndexUserDeleted.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project and yumechi + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class IndexUserDeleted1732071810971 { + name = 'IndexUserDeleted1732071810971' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_199b79e682bdc5ba946f491686" ON "user" ("isDeleted")`); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX IF EXISTS "IDX_199b79e682bdc5ba946f491686"`); + } +} diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index f3aa46292e..fccf86cb91 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -509,19 +509,12 @@ export class ApInboxService { return `skip: delete actor ${actor.uri} !== ${uri}`; } - const user = await this.usersRepository.findOneBy({ id: actor.id }); - if (user == null) { - return 'skip: actor not found'; - } else if (user.isDeleted) { + if (!(await this.usersRepository.update({ id: actor.id, isDeleted: false }, { isDeleted: true })).affected) { return 'skip: already deleted'; } const job = await this.queueService.createDeleteAccountJob(actor); - await this.usersRepository.update(actor.id, { - isDeleted: true, - }); - this.globalEventService.publishInternalEvent('remoteUserUpdated', { id: actor.id }); return `ok: queued ${job.name} ${job.id}`; diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 8c4e40c561..7de850c511 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -557,7 +557,7 @@ export class ApPersonService implements OnModuleInit { if (moving) updates.movedAt = new Date(); // Update user - await this.usersRepository.update(exist.id, updates); + await this.usersRepository.update({ id: exist.id, isDeleted: false }, updates); if (person.publicKey) { await this.userPublickeysRepository.update({ userId: exist.id }, { @@ -662,7 +662,7 @@ export class ApPersonService implements OnModuleInit { @bindThis public async updateFeatured(userId: MiUser['id'], resolver?: Resolver): Promise { - const user = await this.usersRepository.findOneByOrFail({ id: userId }); + const user = await this.usersRepository.findOneByOrFail({ id: userId, isDeleted: false }); if (!this.userEntityService.isRemoteUser(user)) return; if (!user.featured) return;