Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # packages/frontend/src/components/MkChannelFollowButton.vue # packages/frontend/src/components/MkDrive.folder.vue # packages/frontend/src/components/MkDrive.navFolder.vue # packages/frontend/src/components/MkEmojiEditDialog.vue # packages/frontend/src/components/MkFollowButton.vue # packages/frontend/src/components/MkNote.vue # packages/frontend/src/components/MkPostForm.vue # packages/frontend/src/components/MkSignupDialog.form.vue # packages/frontend/src/pages/about.vue # packages/frontend/src/pages/admin/index.vue # packages/frontend/src/pages/admin/instance-block.vue # packages/frontend/src/pages/avatar-decorations.vue # packages/frontend/src/pages/custom-emojis-manager.vue # packages/frontend/src/pages/settings/mute-block.vue # packages/frontend/src/pages/settings/profile.vue # packages/frontend/src/pages/timeline.vue # packages/frontend/src/pages/user/home.vue
This commit is contained in:
commit
de3f4ce29c
216 changed files with 758 additions and 568 deletions
|
|
@ -16,6 +16,7 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj
|
|||
import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
|
||||
import type httpSignature from '@peertube/http-signature';
|
||||
import type * as Bull from 'bullmq';
|
||||
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
||||
|
||||
@Injectable()
|
||||
export class QueueService {
|
||||
|
|
@ -75,11 +76,15 @@ export class QueueService {
|
|||
if (content == null) return null;
|
||||
if (to == null) return null;
|
||||
|
||||
const contentBody = JSON.stringify(content);
|
||||
const digest = ApRequestCreator.createDigest(contentBody);
|
||||
|
||||
const data: DeliverJobData = {
|
||||
user: {
|
||||
id: user.id,
|
||||
},
|
||||
content,
|
||||
content: contentBody,
|
||||
digest,
|
||||
to,
|
||||
isSharedInbox,
|
||||
};
|
||||
|
|
@ -104,6 +109,8 @@ export class QueueService {
|
|||
@bindThis
|
||||
public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>) {
|
||||
if (content == null) return null;
|
||||
const contentBody = JSON.stringify(content);
|
||||
const digest = ApRequestCreator.createDigest(contentBody);
|
||||
|
||||
const opts = {
|
||||
attempts: this.config.deliverJobMaxAttempts ?? 12,
|
||||
|
|
@ -118,7 +125,8 @@ export class QueueService {
|
|||
name: d[0],
|
||||
data: {
|
||||
user,
|
||||
content,
|
||||
content: contentBody,
|
||||
digest,
|
||||
to: d[0],
|
||||
isSharedInbox: d[1],
|
||||
} as DeliverJobData,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ export class ApInboxService {
|
|||
} catch (err) {
|
||||
if (err instanceof Error || typeof err === 'string') {
|
||||
this.logger.error(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +258,7 @@ export class ApInboxService {
|
|||
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
this.announceNote(actor, activity, targetUri);
|
||||
await this.announceNote(actor, activity, targetUri);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -288,7 +290,7 @@ export class ApInboxService {
|
|||
} catch (err) {
|
||||
// 対象が4xxならスキップ
|
||||
if (err instanceof StatusError) {
|
||||
if (err.isClientError) {
|
||||
if (!err.isRetryable) {
|
||||
this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
|
||||
return;
|
||||
}
|
||||
|
|
@ -373,7 +375,7 @@ export class ApInboxService {
|
|||
});
|
||||
|
||||
if (isPost(object)) {
|
||||
this.createNote(resolver, actor, object, false, activity);
|
||||
await this.createNote(resolver, actor, object, false, activity);
|
||||
} else {
|
||||
this.logger.warn(`Unknown type: ${getApType(object)}`);
|
||||
}
|
||||
|
|
@ -404,7 +406,7 @@ export class ApInboxService {
|
|||
await this.apNoteService.createNote(note, resolver, silent);
|
||||
return 'ok';
|
||||
} catch (err) {
|
||||
if (err instanceof StatusError && err.isClientError) {
|
||||
if (err instanceof StatusError && !err.isRetryable) {
|
||||
return `skip ${err.statusCode}`;
|
||||
} else {
|
||||
throw err;
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ type PrivateKey = {
|
|||
};
|
||||
|
||||
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 digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`;
|
||||
const digestHeader = args.digest ?? this.createDigest(args.body);
|
||||
|
||||
const request: Request = {
|
||||
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 {
|
||||
const u = new URL(args.url);
|
||||
|
||||
|
|
@ -145,8 +149,8 @@ export class ApRequestService {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown): Promise<void> {
|
||||
const body = JSON.stringify(object);
|
||||
public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, digest?: string): Promise<void> {
|
||||
const body = typeof object === 'string' ? object : JSON.stringify(object);
|
||||
|
||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||
|
||||
|
|
@ -157,6 +161,7 @@ export class ApRequestService {
|
|||
},
|
||||
url,
|
||||
body,
|
||||
digest,
|
||||
additionalHeaders: {
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ export class ApNoteService {
|
|||
return { status: 'ok', res };
|
||||
} catch (e) {
|
||||
return {
|
||||
status: (e instanceof StatusError && e.isClientError) ? 'permerror' : 'temperror',
|
||||
status: (e instanceof StatusError && !e.isRetryable) ? 'permerror' : 'temperror',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export class StatusError extends Error {
|
|||
public statusCode: number;
|
||||
public statusMessage?: string;
|
||||
public isClientError: boolean;
|
||||
public isRetryable: boolean;
|
||||
|
||||
constructor(message: string, statusCode: number, statusMessage?: string) {
|
||||
super(message);
|
||||
|
|
@ -14,5 +15,6 @@ export class StatusError extends Error {
|
|||
this.statusCode = statusCode;
|
||||
this.statusMessage = statusMessage;
|
||||
this.isClientError = typeof this.statusCode === 'number' && this.statusCode >= 400 && this.statusCode < 500;
|
||||
this.isRetryable = !this.isClientError || this.statusCode === 429;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export class DeliverProcessorService {
|
|||
}
|
||||
|
||||
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
|
||||
this.federatedInstanceService.fetch(host).then(i => {
|
||||
|
|
@ -111,7 +111,7 @@ export class DeliverProcessorService {
|
|||
|
||||
if (res instanceof StatusError) {
|
||||
// 4xx
|
||||
if (res.isClientError) {
|
||||
if (!res.isRetryable) {
|
||||
// 相手が閉鎖していることを明示しているため、配送停止する
|
||||
if (job.data.isSharedInbox && res.statusCode === 410) {
|
||||
this.federatedInstanceService.fetch(host).then(i => {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export class InboxProcessorService {
|
|||
} catch (err) {
|
||||
// 対象が4xxならスキップ
|
||||
if (err instanceof StatusError) {
|
||||
if (err.isClientError) {
|
||||
if (!err.isRetryable) {
|
||||
throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`);
|
||||
}
|
||||
throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export class WebhookDeliverProcessorService {
|
|||
|
||||
if (res instanceof StatusError) {
|
||||
// 4xx
|
||||
if (res.isClientError) {
|
||||
if (!res.isRetryable) {
|
||||
throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ export type DeliverJobData = {
|
|||
/** Actor */
|
||||
user: ThinUser;
|
||||
/** Activity */
|
||||
content: unknown;
|
||||
content: string;
|
||||
/** Digest header */
|
||||
digest: string;
|
||||
/** inbox URL to deliver */
|
||||
to: string;
|
||||
/** whether it is sharedInbox */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue