diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts index 2f1310b8efe7..0d51866c232d 100644 --- a/packages/backend/src/core/UserBlockingService.ts +++ b/packages/backend/src/core/UserBlockingService.ts @@ -20,6 +20,7 @@ import { UserWebhookService } from '@/core/UserWebhookService.js'; import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; +import { RoleService } from '@/core/RoleService.js'; @Injectable() export class UserBlockingService implements OnModuleInit { @@ -49,6 +50,7 @@ export class UserBlockingService implements OnModuleInit { private webhookService: UserWebhookService, private apRendererService: ApRendererService, private loggerService: LoggerService, + private roleService: RoleService, ) { this.logger = this.loggerService.getLogger('user-block'); } @@ -58,7 +60,8 @@ export class UserBlockingService implements OnModuleInit { } @bindThis - public async block(blocker: MiUser, blockee: MiUser, silent = false) { + public async block(blocker: MiUser, blockee: MiUser, silent = false): null | 'BLOCKEE_IS_MODERATOR' { + if (await this.roleService.isModerator(blockee)) return 'BLOCKEE_IS_MODERATOR'; await Promise.all([ this.cancelRequest(blocker, blockee, silent), this.cancelRequest(blockee, blocker, silent), @@ -89,6 +92,8 @@ export class UserBlockingService implements OnModuleInit { const content = this.apRendererService.addContext(this.apRendererService.renderBlock(blocking)); this.queueService.deliver(blocker, content, blockee.inbox, false); } + + return null; } @bindThis diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index e2164fec1d93..d23f8f0fdd37 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -357,8 +357,11 @@ export class ApInboxService { return 'skip: ブロックしようとしているユーザーはローカルユーザーではありません'; } - await this.userBlockingService.block(await this.usersRepository.findOneByOrFail({ id: actor.id }), await this.usersRepository.findOneByOrFail({ id: blockee.id })); - return 'ok'; + const error = await this.userBlockingService.block(await this.usersRepository.findOneByOrFail({ id: actor.id }), await this.usersRepository.findOneByOrFail({ id: blockee.id })); + switch (error) { + case null: return 'ok'; + case 'BLOCKEE_IS_MODERATOR': return 'skip: Blocking Moderator is not allowed.'; + } } @bindThis diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index 408b02fb380c..9bf586b36598 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -61,8 +61,11 @@ export class RelationshipProcessorService { this.usersRepository.findOneByOrFail({ id: job.data.from.id }), this.usersRepository.findOneByOrFail({ id: job.data.to.id }), ]); - await this.userBlockingService.block(blockee, blocker, job.data.silent); - return 'ok'; + const error = await this.userBlockingService.block(blockee, blocker, job.data.silent); + switch (error) { + case null: return 'ok'; + case 'BLOCKEE_IS_MODERATOR': return 'skip: Blocking Moderator is not allowed.'; + } } @bindThis diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index 506621574969..32c2d41ab881 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -43,6 +43,12 @@ export const meta = { code: 'ALREADY_BLOCKING', id: '787fed64-acb9-464a-82eb-afbd745b9614', }, + + blockeeIsModerator: { + message: 'Blocking Moderator is not allowed.', + code: 'BLOCKEE_IS_MODERATOR', + id: '3dca06d1-5ee8-4f14-aff1-917e9ba35e05', + }, }, res: { @@ -99,11 +105,18 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.alreadyBlocking); } - await this.userBlockingService.block(blocker, blockee); - - return await this.userEntityService.pack(blockee.id, blocker, { - schema: 'UserDetailedNotMe', - }); + const error = await this.userBlockingService.block(blocker, blockee); + + switch (error) { + case null: { + return await this.userEntityService.pack(blockee.id, blocker, { + schema: 'UserDetailedNotMe', + }); + } + case 'BLOCKEE_IS_MODERATOR': throw new ApiError(meta.errors.blockeeIsModerator); + // 網羅性チェック + default: error satisfies never; + } }); } }