diff --git a/packages/backend/src/core/AccountUpdateService.ts b/packages/backend/src/core/AccountUpdateService.ts index 69a57b4854..4c89f3a048 100644 --- a/packages/backend/src/core/AccountUpdateService.ts +++ b/packages/backend/src/core/AccountUpdateService.ts @@ -27,15 +27,22 @@ export class AccountUpdateService { } @bindThis - public async publishToFollowers(userId: MiUser['id']) { + /** + * ユーザーのアップデートをフォロワーに配信する + * @param userId ユーザーID + * @param isKeyUpdation Ed25519キーの作成など公開鍵のアップデートによる呼び出しか? trueにするとメインキーを使うようになる + */ + public async publishToFollowers(userId: MiUser['id'], isKeyUpdation: boolean = false) { const user = await this.usersRepository.findOneBy({ id: userId }); if (user == null) throw new Error('user not found'); // フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信 if (this.userEntityService.isLocalUser(user)) { const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user)); - this.apDeliverManagerService.deliverToFollowers(user, content); - this.relayService.deliverToRelays(user, content); + await Promise.allSettled([ + this.apDeliverManagerService.deliverToFollowers(user, content, isKeyUpdation), + this.relayService.deliverToRelays(user, content, isKeyUpdation), + ]); } } } diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 6177aba32e..cb5dca2d39 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -70,7 +70,7 @@ export class QueueService { } @bindThis - public async deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean) { + public async deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean, forceMainKey?: boolean) { if (content == null) return null; if (to == null) return null; @@ -84,6 +84,7 @@ export class QueueService { digest: await genRFC3230DigestHeader(contentBody, 'SHA-256'), to, isSharedInbox, + forceMainKey, }; return this.deliverQueue.add(to, data, { @@ -101,10 +102,11 @@ export class QueueService { * @param user `{ id: string; }` この関数ではThinUserに変換しないので前もって変換してください * @param content IActivity | null * @param inboxes `Map` / key: to (inbox url), value: isSharedInbox (whether it is sharedInbox) + * @param forceMainKey boolean | undefined, force to use main (rsa) key * @returns void */ @bindThis - public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map) { + public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map, forceMainKey?: boolean) { if (content == null) return null; const contentBody = JSON.stringify(content); @@ -124,6 +126,7 @@ export class QueueService { content: contentBody, to: d[0], isSharedInbox: d[1], + forceMainKey, } as DeliverJobData, opts, }))); diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index e9dc9b57af..52bf5d8e6a 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -111,7 +111,7 @@ export class RelayService { } @bindThis - public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any): Promise { + public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any, forceMainKey?: boolean): Promise { if (activity == null) return; const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({ @@ -125,7 +125,7 @@ export class RelayService { const signed = await this.apRendererService.attachLdSignature(copy, user); for (const relay of relays) { - this.queueService.deliver(user, signed, relay.inbox, false); + this.queueService.deliver(user, signed, relay.inbox, false, forceMainKey); } } } diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index cd3b6a8795..cf3dce465e 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -13,6 +13,7 @@ import { bindThis } from '@/decorators.js'; import type { IActivity } from '@/core/activitypub/type.js'; import { ThinUser } from '@/queue/types.js'; import { UserKeypairService } from '../UserKeypairService.js'; +import { AccountUpdateService } from '@/core/AccountUpdateService.js'; interface IRecipe { type: string; @@ -50,6 +51,7 @@ class DeliverManager { private userKeypairService: UserKeypairService, private followingsRepository: FollowingsRepository, private queueService: QueueService, + private accountUpdateService: AccountUpdateService, actor: { id: MiUser['id']; host: null; }, activity: IActivity | null, @@ -104,12 +106,16 @@ class DeliverManager { * Execute delivers */ @bindThis - public async execute(): Promise { + public async execute(opts?: { forceMainKey?: boolean }): Promise { //#region MIGRATION - /** - * ed25519の署名がなければ追加する - */ - await this.userKeypairService.refreshAndprepareEd25519KeyPair(this.actor.id); + if (opts?.forceMainKey !== true) { + /** + * ed25519の署名がなければ追加する + */ + await this.userKeypairService.refreshAndprepareEd25519KeyPair(this.actor.id); + // リモートに配信 + await this.accountUpdateService.publishToFollowers(this.actor.id, true); + } //#endregion // The value flags whether it is shared or not. @@ -163,6 +169,7 @@ export class ApDeliverManagerService { private userKeypairService: UserKeypairService, private queueService: QueueService, + private accountUpdateService: AccountUpdateService, ) { } @@ -170,18 +177,20 @@ export class ApDeliverManagerService { * Deliver activity to followers * @param actor * @param activity Activity + * @param forceMainKey Force to use main (rsa) key */ @bindThis - public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity): Promise { + public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, forceMainKey?: boolean): Promise { const manager = new DeliverManager( this.userKeypairService, this.followingsRepository, this.queueService, + this.accountUpdateService, actor, activity, ); manager.addFollowersRecipe(); - await manager.execute(); + await manager.execute({ forceMainKey }); } /** @@ -196,6 +205,7 @@ export class ApDeliverManagerService { this.userKeypairService, this.followingsRepository, this.queueService, + this.accountUpdateService, actor, activity, ); @@ -209,7 +219,7 @@ export class ApDeliverManagerService { this.userKeypairService, this.followingsRepository, this.queueService, - + this.accountUpdateService, actor, activity, ); diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index 6c58bee211..132593679e 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -91,11 +91,16 @@ 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.getUserKeypair(userId); - return (level !== '00' && keypair.ed25519PrivateKey) ? { + return (level !== '00' && level !== '10' && keypair.ed25519PrivateKey) ? { privateKeyPem: keypair.ed25519PrivateKey, keyId: `${this.config.url}/users/${userId}#ed25519-key`, } : { diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index 8f3782a048..2a4dd5f997 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -76,7 +76,16 @@ export class DeliverProcessorService { await this.fetchInstanceMetadataService.fetchInstanceMetadata(_server).then(() => {}); const server = await this.federatedInstanceService.fetch(host); - await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, server.httpMessageSignaturesImplementationLevel, job.data.digest); + /** + * RSAキーを強制するかでレベルを変える + */ + const level = job.data.forceMainKey ? + server.httpMessageSignaturesImplementationLevel === '11' ? + '10' : + '00' + : server.httpMessageSignaturesImplementationLevel; + + await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, level, job.data.digest); // Update stats if (server.isNotResponding) { diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index 135bccb60c..74e0c0a66e 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -38,6 +38,8 @@ export type DeliverJobData = { to: string; /** whether it is sharedInbox */ isSharedInbox: boolean; + /** force to use main (rsa) key */ + forceMainKey?: boolean; }; export type InboxJobData = {