diff --git a/CHANGELOG.md b/CHANGELOG.md index f948d696e4..e1efd9f1e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Fix: ローカルに存在しないリモートアカウントに対するアカウント削除リクエストを受信した際に、そのユーザーを新規作成して削除する挙動を修正 - Fix: Inboxでの特定のエラーによる失敗はDelayedにしない - Fix: ID生成アルゴリズムにULIDを使用している場合にMisskeyが正しく動作しない問題を修正 +- Fix: リレー経由で届いたノートがリノートとして表示される問題を修正 - Fix: robots.txtの内容を調整 ## 2026.3.2 diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index 9120de1f9f..d96d6c70d0 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -91,13 +91,27 @@ export class RelayService { return JSON.stringify(result); } + @bindThis + private getAcceptedRelays(): Promise { + return this.relaysCache.fetch(() => this.relaysRepository.findBy({ + status: 'accepted', + })); + } + + @bindThis + public async isRelayActor(actor: { inbox: string | null; sharedInbox: string | null }): Promise { + const relays = await this.getAcceptedRelays(); + return relays.some(relay => + (actor.inbox != null && relay.inbox === actor.inbox) + || (actor.sharedInbox != null && relay.inbox === actor.sharedInbox), + ); + } + @bindThis public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any): Promise { if (activity == null) return; - const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({ - status: 'accepted', - })); + const relays = await this.getAcceptedRelays(); if (relays.length === 0) return; const copy = deepClone(activity); diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index ff47ca930d..4f926b99d4 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -302,12 +302,14 @@ export class ApInboxService { @bindThis private async announceNote(actor: MiRemoteUser, activity: IAnnounce, target: IPost, resolver?: Resolver): Promise { - const uri = getApId(activity); - if (actor.isSuspended) { return; } + // リレーからのAnnounceかチェック + const fromRelay = await this.relayService.isRelayActor(actor); + const uri = getApId(fromRelay ? target : activity); + // アナウンス先が許可されているかチェック if (!this.utilityService.isFederationAllowedUri(uri)) return; @@ -336,6 +338,14 @@ export class ApInboxService { throw err; } + // リレーからのAnnounceはリノートを作成せず、ノートを直接公開する + if (fromRelay) { + this.logger.info(`Publishing relay-delivered note: ${uri}`); + const noteObj = await this.noteEntityService.pack(renote, null, { skipHide: true, withReactionAndUserPairCache: true }); + this.globalEventService.publishNotesStream(noteObj); + return; + } + if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) { return 'skip: invalid actor for this activity'; }