diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index b73d0de4d0..afea871575 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -84,7 +84,7 @@ export class QueueService { digest: await genRFC3230DigestHeader(contentBody, 'SHA-256'), to, isSharedInbox, - privateKey, + privateKey: privateKey && { keyId: privateKey.keyId, privateKey: privateKey.privateKey }, }; return this.deliverQueue.add(to, data, { @@ -126,7 +126,7 @@ export class QueueService { content: contentBody, to: d[0], isSharedInbox: d[1], - privateKey, + privateKey: privateKey && { keyId: privateKey.keyId, privateKey: privateKey.privateKey }, } as DeliverJobData, opts, }))); diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index c5099a5425..f106ae1669 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -16,7 +16,8 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { DI } from '@/di-symbols.js'; import { deepClone } from '@/misc/clone.js'; import { bindThis } from '@/decorators.js'; -import { PrivateKey } from './activitypub/type.js'; +import { UserKeypairService } from './UserKeypairService.js'; +import type { PrivateKey } from './activitypub/type.js'; const ACTOR_USERNAME = 'relay.actor' as const; @@ -35,6 +36,7 @@ export class RelayService { private queueService: QueueService, private createSystemUserService: CreateSystemUserService, private apRendererService: ApRendererService, + private userKeypairService: UserKeypairService, ) { this.relaysCache = new MemorySingleCache(1000 * 60 * 10); } @@ -122,11 +124,9 @@ export class RelayService { const copy = deepClone(activity); if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public']; + privateKey = privateKey ?? await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id); + const signed = await this.apRendererService.attachLdSignature(copy, user, privateKey); - const signed = await this.apRendererService.attachLdSignature(copy, user); - - for (const relay of relays) { - this.queueService.deliver(user, signed, relay.inbox, false, privateKey); - } + this.queueService.deliverMany(user, signed, new Map(relays.map(({ inbox }) => [inbox, false])), privateKey); } } diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index af42e4405b..042e13a540 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -32,8 +32,8 @@ export class UserSuspendService { const manager = this.apDeliverManagerService.createDeliverManager(user, content); manager.addAllKnowingSharedInboxRecipe(); // process delivre時にはキーペアが消去されているはずなので、ここで挿入する - const keypairs = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); - manager.execute({ privateKey: { keyId: keypairs.keyId, privateKeyPem: keypairs.privateKey } }); + const privateKey = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); + manager.execute({ privateKey }); } } @@ -46,8 +46,8 @@ export class UserSuspendService { const manager = this.apDeliverManagerService.createDeliverManager(user, content); manager.addAllKnowingSharedInboxRecipe(); // process delivre時にはキーペアが消去されているはずなので、ここで挿入する - const keypairs = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); - manager.execute({ privateKey: { keyId: keypairs.keyId, privateKeyPem: keypairs.privateKey } }); + const privateKey = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); + manager.execute({ privateKey }); } } } diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 1c533ef7c3..4b0dd1403d 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -140,7 +140,7 @@ class DeliverManager { this.logger.info(`ed25519 key pair created for user ${this.actor.id} and publishing to followers`); // リモートに配信 const keyPair = await this.userKeypairService.getLocalUserKeypairWithKeyId(created, 'main'); - await this.accountUpdateService.publishToFollowers(this.actor.id, { keyId: keyPair.keyId, privateKeyPem: keyPair.privateKey }); + await this.accountUpdateService.publishToFollowers(this.actor.id, keyPair); } } //#endregion diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index d929fa4ee1..e4b3074abd 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -30,7 +30,7 @@ import { isNotNull } from '@/misc/is-not-null.js'; import { IdService } from '@/core/IdService.js'; import { LdSignatureService } from './LdSignatureService.js'; import { ApMfmService } from './ApMfmService.js'; -import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; +import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate, PrivateKey } from './type.js'; @Injectable() export class ApRendererService { @@ -657,12 +657,10 @@ export class ApRendererService { } @bindThis - public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise { - const keypair = await this.userKeypairService.getUserKeypair(user.id); - + public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }, key: PrivateKey): Promise { const ldSignature = this.ldSignatureService.use(); ldSignature.debug = false; - activity = await ldSignature.signRsaSignature2017(activity, keypair.privateKey, `${this.config.url}/users/${user.id}#main-key`); + activity = await ldSignature.signRsaSignature2017(activity, key.privateKey, key.keyId); return activity; } diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index 6c0df36d7e..c9bcbd961a 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -34,7 +34,11 @@ export async function createSignedPost(args: { level: string; key: PrivateKey; u const digestHeader = args.digest ?? await genRFC3230DigestHeader(args.body, 'SHA-256'); request.headers['Digest'] = digestHeader; - const result = await signAsDraftToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']); + const result = await signAsDraftToRequest( + request, + { keyId: args.key.keyId, privateKeyPem: args.key.privateKey }, + ['(request-target)', 'date', 'host', 'digest'], + ); return { request, @@ -56,7 +60,11 @@ export async function createSignedGet(args: { level: string; key: PrivateKey; ur }; // TODO: httpMessageSignaturesImplementationLevelによって新規格で通信をするようにする - const result = await signAsDraftToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']); + const result = await signAsDraftToRequest( + request, + { keyId: args.key.keyId, privateKeyPem: args.key.privateKey }, + ['(request-target)', 'date', 'host', 'accept'], + ); return { request, @@ -80,25 +88,10 @@ export class ApRequestService { this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる } - /** - * Get private key by user id and implementation level - * @param userId User id - * @param level Implementation level - */ - @bindThis - private async getPrivateKey(userId: MiUser['id'], level: string): Promise { - const keypair = await this.userKeypairService.getLocalUserKeypairWithKeyId(userId, level); - - return { - keyId: keypair.keyId, - privateKeyPem: keypair.privateKey, - }; - } - @bindThis public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, level: string, digest?: string, key?: PrivateKey): Promise { const body = typeof object === 'string' ? object : JSON.stringify(object); - key = key ?? await this.getPrivateKey(user.id, level); + key = key ?? await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, level); const req = await createSignedPost({ level, key, @@ -131,7 +124,7 @@ export class ApRequestService { */ @bindThis public async signedGet(url: string, user: { id: MiUser['id'] }, level: string): Promise { - const key = await this.getPrivateKey(user.id, level); + const key = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, level); const req = await createSignedGet({ level, key, diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 54d1c52dc0..6fd5ada9fe 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -328,6 +328,6 @@ export const isFlag = (object: IObject): object is IFlag => getApType(object) == export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move'; export type PrivateKey = { - privateKeyPem: string; + privateKey: string; keyId: string; }; diff --git a/packages/backend/test/unit/ap-request.ts b/packages/backend/test/unit/ap-request.ts index 797ef73e62..1c0159ed95 100644 --- a/packages/backend/test/unit/ap-request.ts +++ b/packages/backend/test/unit/ap-request.ts @@ -35,7 +35,7 @@ describe('ap-request', () => { describe.each(['00', '01'])('createSignedPost with verify', (level) => { test('pass', async () => { const keypair = await getKeyPair(level); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; + const key = { keyId: 'x', 'privateKey': keypair.privateKey }; const url = 'https://example.com/inbox'; const activity = { a: 1 }; const body = JSON.stringify(activity); @@ -56,7 +56,7 @@ describe('ap-request', () => { describe.each(['00', '01'])('createSignedGet with verify', (level) => { test('pass', async () => { const keypair = await getKeyPair(level); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; + const key = { keyId: 'x', 'privateKey': keypair.privateKey }; const url = 'https://example.com/outbox'; const headers = { 'User-Agent': 'UA',