enhance(backend): ActivityPub Deliver queueでBodyを事前処理するように (#12916)

* Pre-processing deliver body

* CHANGELOG

* ループ内で計算されると意味がないので

* 同じ処理を同じ形に

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
This commit is contained in:
MeiMei 2024-01-06 09:07:48 +09:00 committed by GitHub
parent 7768385be2
commit d415fd29a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 26 additions and 8 deletions

View file

@ -19,6 +19,9 @@
- Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正 - Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正
- Enhance: チャンネルノートのピン留めをノートのメニューからできるよ - Enhance: チャンネルノートのピン留めをノートのメニューからできるよ
### Server
- Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916)
## 2023.12.2 ## 2023.12.2
### General ### General

View file

@ -16,6 +16,7 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj
import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js'; import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type httpSignature from '@peertube/http-signature'; import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq'; import type * as Bull from 'bullmq';
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
@Injectable() @Injectable()
export class QueueService { export class QueueService {
@ -74,11 +75,15 @@ export class QueueService {
if (content == null) return null; if (content == null) return null;
if (to == null) return null; if (to == null) return null;
const contentBody = JSON.stringify(content);
const digest = ApRequestCreator.createDigest(contentBody);
const data: DeliverJobData = { const data: DeliverJobData = {
user: { user: {
id: user.id, id: user.id,
}, },
content, content: contentBody,
digest,
to, to,
isSharedInbox, isSharedInbox,
}; };
@ -103,6 +108,8 @@ export class QueueService {
@bindThis @bindThis
public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>) { public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>) {
if (content == null) return null; if (content == null) return null;
const contentBody = JSON.stringify(content);
const digest = ApRequestCreator.createDigest(contentBody);
const opts = { const opts = {
attempts: this.config.deliverJobMaxAttempts ?? 12, attempts: this.config.deliverJobMaxAttempts ?? 12,
@ -117,7 +124,8 @@ export class QueueService {
name: d[0], name: d[0],
data: { data: {
user, user,
content, content: contentBody,
digest,
to: d[0], to: d[0],
isSharedInbox: d[1], isSharedInbox: d[1],
} as DeliverJobData, } as DeliverJobData,

View file

@ -34,9 +34,9 @@ type PrivateKey = {
}; };
export class ApRequestCreator { export class ApRequestCreator {
static createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record<string, string> }): Signed { static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record<string, string> }): Signed {
const u = new URL(args.url); const u = new URL(args.url);
const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`; const digestHeader = args.digest ?? this.createDigest(args.body);
const request: Request = { const request: Request = {
url: u.href, url: u.href,
@ -59,6 +59,10 @@ export class ApRequestCreator {
}; };
} }
static createDigest(body: string) {
return `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}`;
}
static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed { static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
const u = new URL(args.url); const u = new URL(args.url);
@ -145,8 +149,8 @@ export class ApRequestService {
} }
@bindThis @bindThis
public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown): Promise<void> { public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, digest?: string): Promise<void> {
const body = JSON.stringify(object); const body = typeof object === 'string' ? object : JSON.stringify(object);
const keypair = await this.userKeypairService.getUserKeypair(user.id); const keypair = await this.userKeypairService.getUserKeypair(user.id);
@ -157,6 +161,7 @@ export class ApRequestService {
}, },
url, url,
body, body,
digest,
additionalHeaders: { additionalHeaders: {
}, },
}); });

View file

@ -72,7 +72,7 @@ export class DeliverProcessorService {
} }
try { try {
await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content); await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, job.data.digest);
// Update stats // Update stats
this.federatedInstanceService.fetch(host).then(i => { this.federatedInstanceService.fetch(host).then(i => {

View file

@ -15,7 +15,9 @@ export type DeliverJobData = {
/** Actor */ /** Actor */
user: ThinUser; user: ThinUser;
/** Activity */ /** Activity */
content: unknown; content: string;
/** Digest header */
digest: string;
/** inbox URL to deliver */ /** inbox URL to deliver */
to: string; to: string;
/** whether it is sharedInbox */ /** whether it is sharedInbox */