feat(federation): ⬆️ Upgrade to Versia 0.5

This commit is contained in:
Jesse Wierzbinski 2025-02-17 13:07:43 +01:00
parent e6c7e8a597
commit ed9ffe34f4
No known key found for this signature in database
10 changed files with 34 additions and 28 deletions

View file

@ -5,9 +5,9 @@ import { InboxJobType, inboxQueue } from "~/classes/queues/inbox";
const schemas = { const schemas = {
header: z.object({ header: z.object({
"x-signature": z.string().optional(), "versia-signature": z.string().optional(),
"x-nonce": z.string().optional(), "versia-signed-at": z.coerce.number().optional(),
"x-signed-by": z "versia-signed-by": z
.string() .string()
.url() .url()
.or(z.string().startsWith("instance ")) .or(z.string().startsWith("instance "))

View file

@ -9,9 +9,9 @@ const schemas = {
uuid: z.string().uuid(), uuid: z.string().uuid(),
}), }),
header: z.object({ header: z.object({
"x-signature": z.string().optional(), "versia-signature": z.string().optional(),
"x-nonce": z.string().optional(), "versia-signed-at": z.coerce.number().optional(),
"x-signed-by": z "versia-signed-by": z
.string() .string()
.url() .url()
.or(z.string().startsWith("instance ")) .or(z.string().startsWith("instance "))

View file

@ -41,7 +41,7 @@ export default apiRoute((app) =>
"pub.versia:custom_emojis", "pub.versia:custom_emojis",
"pub.versia:instance_messaging", "pub.versia:instance_messaging",
], ],
versions: ["0.4.0"], versions: ["0.5.0"],
}, },
host: config.http.base_url.host, host: config.http.base_url.host,
name: config.instance.name, name: config.instance.name,

View file

@ -17,7 +17,7 @@
"@oclif/core": "^4.2.6", "@oclif/core": "^4.2.6",
"@sentry/bun": "^9.1.0", "@sentry/bun": "^9.1.0",
"@versia/client": "^0.1.5", "@versia/client": "^0.1.5",
"@versia/federation": "0.1.4", "@versia/federation": "^0.2.0",
"@versia/kit": "workspace:*", "@versia/kit": "workspace:*",
"altcha-lib": "^1.2.0", "altcha-lib": "^1.2.0",
"blurhash": "^2.0.5", "blurhash": "^2.0.5",
@ -745,7 +745,7 @@
"@versia/client": ["@versia/client@0.1.5", "", { "dependencies": { "@badgateway/oauth2-client": "^2.4.2", "zod": "^3.24.1" } }, "sha512-POD2/IT98EZZ32kWEPc3XUY2zApX94tuBftNWIMyoT04Sp7CPuvv1TT2fxM2kmgrC6kgbh4I6yirPpzVY+FpSA=="], "@versia/client": ["@versia/client@0.1.5", "", { "dependencies": { "@badgateway/oauth2-client": "^2.4.2", "zod": "^3.24.1" } }, "sha512-POD2/IT98EZZ32kWEPc3XUY2zApX94tuBftNWIMyoT04Sp7CPuvv1TT2fxM2kmgrC6kgbh4I6yirPpzVY+FpSA=="],
"@versia/federation": ["@versia/federation@0.1.4", "", { "dependencies": { "magic-regexp": "^0.8.0", "mime-types": "^2.1.35", "zod": "^3.23.8", "zod-validation-error": "^3.4.0" } }, "sha512-89us9ltMNXNqohRxIxf7A4yYY2m3eiifsVWFGuKIrflX2Hv3VyqyZOrXh8i2bou+1qll9zAiCHYWCkAmv7RqkQ=="], "@versia/federation": ["@versia/federation@0.2.0", "", { "dependencies": { "magic-regexp": "^0.8.0", "mime-types": "^2.1.35", "zod": "^3.24.1", "zod-validation-error": "^3.4.0" } }, "sha512-Eb2l26aE+9218DT/YKhYJy6DsdCbM3VL2zuVXFvolMprF5sNLi/px5BF0/KgI3TN6FTo7ufXVPNqePvBt90aiQ=="],
"@versia/kit": ["@versia/kit@workspace:packages/plugin-kit"], "@versia/kit": ["@versia/kit@workspace:packages/plugin-kit"],

View file

@ -914,6 +914,10 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
remote: false, remote: false,
}, },
}, },
collections: {
replies: `/notes/${status.id}/replies`,
quotes: `/notes/${status.id}/quotes`,
},
attachments: (status.attachments ?? []).map((attachment) => attachments: (status.attachments ?? []).map((attachment) =>
new Media(attachment).toVersia(), new Media(attachment).toVersia(),
), ),

View file

@ -86,7 +86,7 @@ describe("InboxProcessor", () => {
let mockSenderInstance: Instance; let mockSenderInstance: Instance;
let mockHeaders: { let mockHeaders: {
signature: string; signature: string;
nonce: string; signedAt: Date;
authorization?: string; authorization?: string;
}; };
let processor: InboxProcessor; let processor: InboxProcessor;
@ -115,7 +115,7 @@ describe("InboxProcessor", () => {
// Setup basic mock headers // Setup basic mock headers
mockHeaders = { mockHeaders = {
signature: "test-signature", signature: "test-signature",
nonce: "test-nonce", signedAt: new Date(),
}; };
// Setup basic mock body // Setup basic mock body

View file

@ -63,7 +63,7 @@ export class InboxProcessor {
* *
* @param request Request object. * @param request Request object.
* @param body Entity JSON body. * @param body Entity JSON body.
* @param sender Sender of the request's instance and key (from X-Signed-By header). Null if request is from a bridge. * @param sender Sender of the request's instance and key (from Versia-Signed-By header). Null if request is from a bridge.
* @param headers Various request headers. * @param headers Various request headers.
* @param logger LogTape logger instance. * @param logger LogTape logger instance.
* @param requestIp Request IP address. Grabs it from the Hono context if not provided. * @param requestIp Request IP address. Grabs it from the Hono context if not provided.
@ -81,7 +81,7 @@ export class InboxProcessor {
} | null, } | null,
private headers: { private headers: {
signature?: string; signature?: string;
nonce?: string; signedAt?: Date;
authorization?: string; authorization?: string;
}, },
private logger: Logger = getLogger(["federation", "inbox"]), private logger: Logger = getLogger(["federation", "inbox"]),
@ -108,8 +108,8 @@ export class InboxProcessor {
this.sender.key, this.sender.key,
); );
if (!(this.headers.signature && this.headers.nonce)) { if (!(this.headers.signature && this.headers.signedAt)) {
throw new Error("Missing signature or nonce"); throw new Error("Missing signature or signature timestamp");
} }
// HACK: Making a fake Request object instead of passing the values directly is necessary because otherwise the validation breaks for some unknown reason // HACK: Making a fake Request object instead of passing the values directly is necessary because otherwise the validation breaks for some unknown reason
@ -117,8 +117,10 @@ export class InboxProcessor {
new Request(this.request.url, { new Request(this.request.url, {
method: this.request.method, method: this.request.method,
headers: { headers: {
"X-Signature": this.headers.signature, "Versia-Signature": this.headers.signature,
"X-Nonce": this.headers.nonce, "Versia-Signed-At": (
this.headers.signedAt.getTime() / 1000
).toString(),
}, },
body: this.request.body, body: this.request.body,
}), }),

View file

@ -10,9 +10,9 @@ export enum InboxJobType {
export type InboxJobData = { export type InboxJobData = {
data: Entity; data: Entity;
headers: { headers: {
"x-signature"?: string; "versia-signature"?: string;
"x-nonce"?: string; "versia-signed-at"?: number;
"x-signed-by"?: string; "versia-signed-by"?: string;
authorization?: string; authorization?: string;
}; };
request: { request: {

View file

@ -61,13 +61,13 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
} }
const { const {
"x-signature": signature, "versia-signature": signature,
"x-nonce": nonce, "versia-signed-at": signedAt,
"x-signed-by": signedBy, "versia-signed-by": signedBy,
} = headers as { } = headers as {
"x-signature": string; "versia-signature": string;
"x-nonce": string; "versia-signed-at": number;
"x-signed-by": string; "versia-signed-by": string;
}; };
const sender = await User.resolve(new URL(signedBy)); const sender = await User.resolve(new URL(signedBy));
@ -122,7 +122,7 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
}, },
{ {
signature, signature,
nonce, signedAt: new Date(signedAt * 1000),
authorization: undefined, authorization: undefined,
}, },
getLogger(["federation", "inbox"]), getLogger(["federation", "inbox"]),

View file

@ -113,7 +113,7 @@
"@oclif/core": "^4.2.6", "@oclif/core": "^4.2.6",
"@sentry/bun": "^9.1.0", "@sentry/bun": "^9.1.0",
"@versia/client": "^0.1.5", "@versia/client": "^0.1.5",
"@versia/federation": "0.1.4", "@versia/federation": "^0.2.0",
"@versia/kit": "workspace:*", "@versia/kit": "workspace:*",
"altcha-lib": "^1.2.0", "altcha-lib": "^1.2.0",
"blurhash": "^2.0.5", "blurhash": "^2.0.5",