diff --git a/classes/functions/emoji.ts b/classes/functions/emoji.ts deleted file mode 100644 index a2ee0d28..00000000 --- a/classes/functions/emoji.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { emojiValidatorWithColons } from "@/api"; -import { type InferSelectModel, inArray } from "drizzle-orm"; -import { Emojis, type Instances } from "~/drizzle/schema"; -import { Emoji } from "~/packages/database-interface/emoji"; - -export type EmojiWithInstance = InferSelectModel & { - instance: InferSelectModel | null; -}; - -/** - * Used for parsing emojis from local text - * @param text The text to parse - * @returns An array of emojis - */ -export const parseEmojis = async (text: string): Promise => { - const matches = text.match(emojiValidatorWithColons); - if (!matches || matches.length === 0) { - return []; - } - - return Emoji.manyFromSql( - inArray( - Emojis.shortcode, - matches.map((match) => match.replace(/:/g, "")), - ), - ); -}; diff --git a/classes/functions/federation.ts b/classes/functions/federation.ts index 1b300a7d..2596e8fb 100644 --- a/classes/functions/federation.ts +++ b/classes/functions/federation.ts @@ -1,65 +1,10 @@ -import { debugRequest } from "@/api"; -import { getLogger } from "@logtape/logtape"; -import { SignatureConstructor } from "@lysand-org/federation"; -import type { Entity, Undo } from "@lysand-org/federation/types"; +import type { Undo } from "@lysand-org/federation/types"; import { config } from "config-manager"; import type { User } from "~/packages/database-interface/user"; export const localObjectUri = (id: string) => new URL(`/objects/${id}`, config.http.base_url).toString(); -export const objectToInboxRequest = async ( - object: Entity, - author: User, - userToSendTo: User, -): Promise => { - if (userToSendTo.isLocal() || !userToSendTo.data.endpoints?.inbox) { - throw new Error("UserToSendTo has no inbox or is a local user"); - } - - if (author.isRemote()) { - throw new Error("Author is a remote user"); - } - - const privateKey = await crypto.subtle.importKey( - "pkcs8", - Buffer.from(author.data.privateKey ?? "", "base64"), - "Ed25519", - false, - ["sign"], - ); - - const ctor = new SignatureConstructor(privateKey, author.getUri()); - - const userInbox = new URL(userToSendTo.data.endpoints?.inbox ?? ""); - - const request = new Request(userInbox, { - method: "POST", - headers: { - "Content-Type": "application/json", - Origin: new URL(config.http.base_url).host, - }, - body: JSON.stringify(object), - }); - - const { request: signed, signedString } = await ctor.sign(request); - - if (config.debug.federation) { - // Debug request - await debugRequest(signed); - - const logger = getLogger("federation"); - - // Log public key - logger.debug`Sender public key: ${author.data.publicKey}`; - - // Log signed string - logger.debug`Signed string:\n${signedString}`; - } - - return signed; -}; - export const undoFederationRequest = (undoer: User, uri: string): Undo => { const id = crypto.randomUUID(); return { diff --git a/classes/functions/status.ts b/classes/functions/status.ts index e5f60da4..242218cb 100644 --- a/classes/functions/status.ts +++ b/classes/functions/status.ts @@ -1,11 +1,6 @@ import { mentionValidator } from "@/api"; import { sanitizeHtml, sanitizeHtmlInline } from "@/sanitization"; import markdownItTaskLists from "@hackmd/markdown-it-task-lists"; -import { getLogger } from "@logtape/logtape"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import type { ContentFormat } from "@lysand-org/federation/types"; import { config } from "config-manager"; import { @@ -37,11 +32,9 @@ import { type Notes, Users, } from "~/drizzle/schema"; -import type { Note } from "~/packages/database-interface/note"; +import type { EmojiWithInstance } from "~/packages/database-interface/emoji"; import { User } from "~/packages/database-interface/user"; import type { Application } from "./application"; -import type { EmojiWithInstance } from "./emoji"; -import { objectToInboxRequest } from "./federation"; import { type UserWithInstance, type UserWithRelations, @@ -316,11 +309,7 @@ export const parseTextMentions = async ( // Attempt to resolve mentions that were not found for (const person of notFoundRemoteUsers) { - const signatureConstructor = await SignatureConstructor.fromStringKey( - author.data.privateKey ?? "", - author.getUri(), - ); - const manager = new FederationRequester(signatureConstructor); + const manager = await author.getFederationRequester(); const uri = await User.webFinger( manager, @@ -451,26 +440,3 @@ export const getMarkdownRenderer = () => { return renderer; }; - -export const federateNote = async (note: Note) => { - for (const user of await note.getUsersToFederateTo()) { - // TODO: Add queue system - const request = await objectToInboxRequest( - note.toLysand(), - note.author, - user, - ); - - // Send request - const response = await fetch(request, { - proxy: config.http.proxy.address, - }); - - if (!response.ok) { - const logger = getLogger("federation"); - - logger.debug`${await response.text()}`; - logger.error`Failed to federate status ${note.data.id} to ${user.getUri()}`; - } - } -}; diff --git a/classes/functions/user.ts b/classes/functions/user.ts index c9fcda64..206d27d0 100644 --- a/classes/functions/user.ts +++ b/classes/functions/user.ts @@ -1,7 +1,3 @@ -/** - * Old code that needs to be rewritten - */ -import { getLogger } from "@logtape/logtape"; import type { Follow, FollowAccept, @@ -19,10 +15,9 @@ import { Tokens, type Users, } from "~/drizzle/schema"; +import type { EmojiWithInstance } from "~/packages/database-interface/emoji"; import { User } from "~/packages/database-interface/user"; import type { Application } from "./application"; -import type { EmojiWithInstance } from "./emoji"; -import { objectToInboxRequest } from "./federation"; import { type Relationship, checkForBidirectionalRelationships, @@ -168,25 +163,12 @@ export const followRequestUser = async ( } if (isRemote) { - // Federate - // TODO: Make database job - const request = await objectToInboxRequest( + const { ok } = await follower.federateToUser( followRequestToLysand(follower, followee), - follower, followee, ); - // Send request - const response = await fetch(request, { - proxy: config.http.proxy.address, - }); - - if (!response.ok) { - const logger = getLogger("federation"); - - logger.debug`${await response.text()}`; - logger.error`Failed to federate follow request from ${follower.id} to ${followee.getUri()}`; - + if (!ok) { await db .update(Relationships) .set({ @@ -217,45 +199,17 @@ export const followRequestUser = async ( }; export const sendFollowAccept = async (follower: User, followee: User) => { - // TODO: Make database job - const request = await objectToInboxRequest( + await follower.federateToUser( followAcceptToLysand(follower, followee), followee, - follower, ); - - // Send request - const response = await fetch(request, { - proxy: config.http.proxy.address, - }); - - if (!response.ok) { - const logger = getLogger("federation"); - - logger.debug`${await response.text()}`; - logger.error`Failed to federate follow accept from ${followee.id} to ${follower.getUri()}`; - } }; export const sendFollowReject = async (follower: User, followee: User) => { - // TODO: Make database job - const request = await objectToInboxRequest( + await follower.federateToUser( followRejectToLysand(follower, followee), followee, - follower, ); - - // Send request - const response = await fetch(request, { - proxy: config.http.proxy.address, - }); - - if (!response.ok) { - const logger = getLogger("federation"); - - logger.debug`${await response.text()}`; - logger.error`Failed to federate follow reject from ${followee.id} to ${follower.getUri()}`; - } }; export const transformOutputToUserWithRelations = ( diff --git a/cli/commands/federation/user/fetch.ts b/cli/commands/federation/user/fetch.ts index c254ac0a..89037db1 100644 --- a/cli/commands/federation/user/fetch.ts +++ b/cli/commands/federation/user/fetch.ts @@ -1,8 +1,4 @@ import { parseUserAddress, userAddressValidator } from "@/api"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import { Args } from "@oclif/core"; import chalk from "chalk"; import ora from "ora"; @@ -47,11 +43,7 @@ export default class FederationUserFetch extends BaseCommand< const requester = await User.getServerActor(); - const signatureConstructor = await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - const manager = new FederationRequester(signatureConstructor); + const manager = await requester.getFederationRequester(); const uri = await User.webFinger(manager, username, host); diff --git a/cli/commands/federation/user/finger.ts b/cli/commands/federation/user/finger.ts index 51cffc0f..0595a89a 100644 --- a/cli/commands/federation/user/finger.ts +++ b/cli/commands/federation/user/finger.ts @@ -1,8 +1,4 @@ import { parseUserAddress, userAddressValidator } from "@/api"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import { Args } from "@oclif/core"; import chalk from "chalk"; import ora from "ora"; @@ -47,11 +43,7 @@ export default class FederationUserFinger extends BaseCommand< const requester = await User.getServerActor(); - const signatureConstructor = await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - const manager = new FederationRequester(signatureConstructor); + const manager = await requester.getFederationRequester(); const uri = await User.webFinger(manager, username, host); diff --git a/packages/database-interface/emoji.ts b/packages/database-interface/emoji.ts index 8b0a2da1..4d040e62 100644 --- a/packages/database-interface/emoji.ts +++ b/packages/database-interface/emoji.ts @@ -1,20 +1,25 @@ +import { emojiValidatorWithColons } from "@/api"; import { proxyUrl } from "@/response"; import type { Emoji as ApiEmoji } from "@lysand-org/client/types"; import type { CustomEmojiExtension } from "@lysand-org/federation/types"; import { type InferInsertModel, + type InferSelectModel, type SQL, and, desc, eq, inArray, } from "drizzle-orm"; -import type { EmojiWithInstance } from "~/classes/functions/emoji"; import { db } from "~/drizzle/db"; import { Emojis, Instances } from "~/drizzle/schema"; import { BaseInterface } from "./base"; import { Instance } from "./instance"; +export type EmojiWithInstance = InferSelectModel & { + instance: InferSelectModel | null; +}; + export class Emoji extends BaseInterface { async reload(): Promise { const reloaded = await Emoji.fromId(this.data.id); @@ -152,6 +157,26 @@ export class Emoji extends BaseInterface { return this.data.id; } + /** + * Parse emojis from text + * + * @param text The text to parse + * @returns An array of emojis + */ + public static async parseFromText(text: string): Promise { + const matches = text.match(emojiValidatorWithColons); + if (!matches || matches.length === 0) { + return []; + } + + return Emoji.manyFromSql( + inArray( + Emojis.shortcode, + matches.map((match) => match.replace(/:/g, "")), + ), + ); + } + public toApi(): ApiEmoji { return { // @ts-expect-error ID is not in regular Mastodon API diff --git a/packages/database-interface/instance.ts b/packages/database-interface/instance.ts index f4107d13..c55d0eb5 100644 --- a/packages/database-interface/instance.ts +++ b/packages/database-interface/instance.ts @@ -1,7 +1,6 @@ import { getLogger } from "@logtape/logtape"; import { EntityValidator, - FederationRequester, type ResponseError, type ValidationError, } from "@lysand-org/federation"; @@ -20,6 +19,7 @@ import { import { db } from "~/drizzle/db"; import { Instances } from "~/drizzle/schema"; import { BaseInterface } from "./base"; +import { User } from "./user"; export type AttachmentType = InferSelectModel; @@ -139,8 +139,10 @@ export class Instance extends BaseInterface { const wellKnownUrl = new URL("/.well-known/lysand", origin); const logger = getLogger("federation"); + const requester = await User.getServerActor().getFederationRequester(); + try { - const { ok, raw, data } = await new FederationRequester() + const { ok, raw, data } = await requester .get(wellKnownUrl, { // @ts-expect-error Bun extension proxy: config.http.proxy.address, @@ -193,13 +195,14 @@ export class Instance extends BaseInterface { // Go to endpoint, then follow the links to the actual metadata const logger = getLogger("federation"); + const requester = await User.getServerActor().getFederationRequester(); try { const { raw: response, ok, data: wellKnown, - } = await new FederationRequester() + } = await requester .get<{ links: { rel: string; href: string }[]; }>(wellKnownUrl, { @@ -245,7 +248,7 @@ export class Instance extends BaseInterface { raw: metadataResponse, ok: ok2, data: metadata, - } = await new FederationRequester() + } = await requester .get<{ metadata: { nodeName?: string; diff --git a/packages/database-interface/note.ts b/packages/database-interface/note.ts index 11a8a3be..532140aa 100644 --- a/packages/database-interface/note.ts +++ b/packages/database-interface/note.ts @@ -7,7 +7,7 @@ import type { Attachment as ApiAttachment, Status as ApiStatus, } from "@lysand-org/client/types"; -import { EntityValidator, FederationRequester } from "@lysand-org/federation"; +import { EntityValidator } from "@lysand-org/federation"; import type { ContentFormat, Note as LysandNote, @@ -29,7 +29,6 @@ import { type Application, applicationToApi, } from "~/classes/functions/application"; -import { parseEmojis } from "~/classes/functions/emoji"; import { localObjectUri } from "~/classes/functions/federation"; import { type StatusWithRelations, @@ -190,6 +189,14 @@ export class Note extends BaseInterface { return this.data.id; } + async federateToUsers(): Promise { + const users = await this.getUsersToFederateTo(); + + for (const user of users) { + await this.author.federateToUser(this.toLysand(), user); + } + } + /** * Fetch the users that should be federated to for this note * @@ -336,7 +343,7 @@ export class Note extends BaseInterface { const parsedEmojis = [ ...(data.emojis ?? []), - ...(await parseEmojis(plaintextContent)), + ...(await Emoji.parseFromText(plaintextContent)), // Deduplicate by .id ].filter( (emoji, index, self) => @@ -429,7 +436,9 @@ export class Note extends BaseInterface { const parsedEmojis = [ ...(data.emojis ?? []), - ...(plaintextContent ? await parseEmojis(plaintextContent) : []), + ...(plaintextContent + ? await Emoji.parseFromText(plaintextContent) + : []), // Deduplicate by .id ].filter( (emoji, index, self) => @@ -592,7 +601,10 @@ export class Note extends BaseInterface { throw new Error(`Invalid URI to parse ${uri}`); } - const { data } = await new FederationRequester().get(uri, { + const requester = + await User.getServerActor().getFederationRequester(); + + const { data } = await requester.get(uri, { // @ts-expect-error Bun extension proxy: config.http.proxy.address, }); diff --git a/packages/database-interface/user.ts b/packages/database-interface/user.ts index 10ddd2ab..460d2b69 100644 --- a/packages/database-interface/user.ts +++ b/packages/database-interface/user.ts @@ -2,12 +2,20 @@ import { idValidator } from "@/api"; import { getBestContentType, urlToContentFormat } from "@/content_types"; import { randomString } from "@/math"; import { proxyUrl } from "@/response"; +import { sentry } from "@/sentry"; +import { getLogger } from "@logtape/logtape"; import type { Account as ApiAccount, Mention as ApiMention, } from "@lysand-org/client/types"; -import { EntityValidator, FederationRequester } from "@lysand-org/federation"; +import { + EntityValidator, + FederationRequester, + type HttpVerb, + SignatureConstructor, +} from "@lysand-org/federation"; import type { Entity, User as LysandUser } from "@lysand-org/federation/types"; +import chalk from "chalk"; import { type InferInsertModel, type SQL, @@ -23,7 +31,6 @@ import { sql, } from "drizzle-orm"; import { htmlToText } from "html-to-text"; -import { objectToInboxRequest } from "~/classes/functions/federation"; import { type UserWithRelations, findManyUsers, @@ -341,9 +348,8 @@ export class User extends BaseInterface { uri: string, instance: Instance, ): Promise { - const { data: json } = await new FederationRequester().get< - Partial - >(uri, { + const requester = await User.getServerActor().getFederationRequester(); + const { data: json } = await requester.get>(uri, { // @ts-expect-error Bun extension proxy: config.http.proxy.address, }); @@ -617,7 +623,66 @@ export class User extends BaseInterface { return updated.data; } - async federateToFollowers(object: Entity) { + /** + * Signs a Lysand entity with that user's private key + * + * @param entity Entity to sign + * @param signatureUrl URL to embed in signature (must be the same URI of queries made with this signature) + * @param signatureMethod HTTP method to embed in signature (default: POST) + * @returns The signed string and headers to send with the request + */ + async sign( + entity: Entity, + signatureUrl: string | URL, + signatureMethod: HttpVerb = "POST", + ): Promise<{ + headers: Headers; + signedString: string; + }> { + const signatureConstructor = await SignatureConstructor.fromStringKey( + this.data.privateKey ?? "", + this.getUri(), + ); + + const output = await signatureConstructor.sign( + signatureMethod, + new URL(signatureUrl), + JSON.stringify(entity), + ); + + if (config.debug.federation) { + const logger = getLogger("federation"); + + // Log public key + logger.debug`Sender public key: ${this.data.publicKey}`; + + // Log signed string + logger.debug`Signed string:\n${output.signedString}`; + } + + return output; + } + + /** + * Helper to get the appropriate Lysand SDK requester with this user's private key + * + * @returns The requester + */ + async getFederationRequester(): Promise { + const signatureConstructor = await SignatureConstructor.fromStringKey( + this.data.privateKey ?? "", + this.getUri(), + ); + + return new FederationRequester(signatureConstructor); + } + + /** + * Federates an entity to all followers of the user + * + * @param entity Entity to federate + */ + async federateToFollowers(entity: Entity): Promise { // Get followers const followers = await User.manyFromSql( and( @@ -627,19 +692,45 @@ export class User extends BaseInterface { ); for (const follower of followers) { - const federationRequest = await objectToInboxRequest( - object, - this, - follower, - ); - - // FIXME: Add to new queue system when it's implemented - fetch(federationRequest, { - proxy: config.http.proxy.address, - }); + await this.federateToUser(entity, follower); } } + /** + * Federates an entity to any user. + * + * @param entity Entity to federate + * @param user User to federate to + * @returns Whether the federation was successful + */ + async federateToUser(entity: Entity, user: User): Promise<{ ok: boolean }> { + const { headers } = await this.sign( + entity, + user.data.endpoints?.inbox ?? "", + ); + + try { + await new FederationRequester().post( + user.data.endpoints?.inbox ?? "", + entity, + { + // @ts-expect-error Bun extension + proxy: config.http.proxy.address, + headers, + }, + ); + } catch (e) { + getLogger("federation") + .error`Federating ${chalk.gray(entity.type)} to ${user.getUri()} ${chalk.bold.red("failed")}`; + getLogger("federation").error`${e}`; + sentry?.captureException(e); + + return { ok: false }; + } + + return { ok: true }; + } + toApi(isOwnAccount = false): ApiAccount { const user = this.data; return { diff --git a/server/api/api/v1/accounts/lookup/index.ts b/server/api/api/v1/accounts/lookup/index.ts index 819a0a02..fc4c5b77 100644 --- a/server/api/api/v1/accounts/lookup/index.ts +++ b/server/api/api/v1/accounts/lookup/index.ts @@ -2,10 +2,6 @@ import { applyConfig, auth, handleZodError } from "@/api"; import { errorResponse, jsonResponse } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import { eq } from "drizzle-orm"; import { anyOf, @@ -84,12 +80,7 @@ export default (app: Hono) => const requester = user ?? User.getServerActor(); - const signatureConstructor = - await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - const manager = new FederationRequester(signatureConstructor); + const manager = await requester.getFederationRequester(); const uri = await User.webFinger(manager, username, domain); diff --git a/server/api/api/v1/accounts/search/index.ts b/server/api/api/v1/accounts/search/index.ts index 62bbfe9a..d98a60ac 100644 --- a/server/api/api/v1/accounts/search/index.ts +++ b/server/api/api/v1/accounts/search/index.ts @@ -2,10 +2,6 @@ import { applyConfig, auth, handleZodError } from "@/api"; import { errorResponse, jsonResponse } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import { eq, ilike, not, or, sql } from "drizzle-orm"; import { anyOf, @@ -95,12 +91,7 @@ export default (app: Hono) => if (resolve && username && host) { const requester = self ?? User.getServerActor(); - const signatureConstructor = - await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - const manager = new FederationRequester(signatureConstructor); + const manager = await requester.getFederationRequester(); const uri = await User.webFinger(manager, username, host); diff --git a/server/api/api/v1/accounts/update_credentials/index.ts b/server/api/api/v1/accounts/update_credentials/index.ts index 00410b27..c83f2d7e 100644 --- a/server/api/api/v1/accounts/update_credentials/index.ts +++ b/server/api/api/v1/accounts/update_credentials/index.ts @@ -7,13 +7,12 @@ import { config } from "config-manager"; import { and, eq, isNull } from "drizzle-orm"; import ISO6391 from "iso-639-1"; import { z } from "zod"; -import { parseEmojis } from "~/classes/functions/emoji"; import { contentToHtml } from "~/classes/functions/status"; import { MediaManager } from "~/classes/media/media-manager"; import { db } from "~/drizzle/db"; import { EmojiToUser, RolePermissions, Users } from "~/drizzle/schema"; import { Attachment } from "~/packages/database-interface/attachment"; -import type { Emoji } from "~/packages/database-interface/emoji"; +import { Emoji } from "~/packages/database-interface/emoji"; import { User } from "~/packages/database-interface/user"; export const meta = applyConfig({ @@ -252,8 +251,8 @@ export default (app: Hono) => ); // Parse emojis - const nameEmojis = await parseEmojis(parsedName); - const valueEmojis = await parseEmojis(parsedValue); + const nameEmojis = await Emoji.parseFromText(parsedName); + const valueEmojis = await Emoji.parseFromText(parsedValue); fieldEmojis.push(...nameEmojis, ...valueEmojis); @@ -279,8 +278,9 @@ export default (app: Hono) => } // Parse emojis - const displaynameEmojis = await parseEmojis(sanitizedDisplayName); - const noteEmojis = await parseEmojis(self.note); + const displaynameEmojis = + await Emoji.parseFromText(sanitizedDisplayName); + const noteEmojis = await Emoji.parseFromText(self.note); self.emojis = [ ...displaynameEmojis, diff --git a/server/api/api/v1/statuses/index.ts b/server/api/api/v1/statuses/index.ts index fdd3dfc8..c0c2b3ac 100644 --- a/server/api/api/v1/statuses/index.ts +++ b/server/api/api/v1/statuses/index.ts @@ -5,7 +5,6 @@ import { zValidator } from "@hono/zod-validator"; import { config } from "config-manager"; import ISO6391 from "iso-639-1"; import { z } from "zod"; -import { federateNote } from "~/classes/functions/status"; import { RolePermissions } from "~/drizzle/schema"; import { Attachment } from "~/packages/database-interface/attachment"; import { Note } from "~/packages/database-interface/note"; @@ -164,7 +163,7 @@ export default (app: Hono) => }); if (!local_only) { - await federateNote(newNote); + await newNote.federateToUsers(); } return jsonResponse(await newNote.toApi(user)); diff --git a/server/api/api/v2/search/index.ts b/server/api/api/v2/search/index.ts index 92cb2825..45bd8073 100644 --- a/server/api/api/v2/search/index.ts +++ b/server/api/api/v2/search/index.ts @@ -8,10 +8,6 @@ import { import { errorResponse, jsonResponse } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; -import { - FederationRequester, - SignatureConstructor, -} from "@lysand-org/federation"; import { and, eq, inArray, sql } from "drizzle-orm"; import { z } from "zod"; import { searchManager } from "~/classes/search/search-manager"; @@ -133,14 +129,8 @@ export default (app: Hono) => if (resolve) { const requester = self ?? User.getServerActor(); - const signatureConstructor = - await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - const manager = new FederationRequester( - signatureConstructor, - ); + const manager = + await requester.getFederationRequester(); const uri = await User.webFinger( manager, diff --git a/server/api/objects/:id/index.ts b/server/api/objects/:id/index.ts index d41c2f7c..38b167d1 100644 --- a/server/api/objects/:id/index.ts +++ b/server/api/objects/:id/index.ts @@ -2,8 +2,6 @@ import { applyConfig, handleZodError } from "@/api"; import { errorResponse, response } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; -import { getLogger } from "@logtape/logtape"; -import { SignatureConstructor } from "@lysand-org/federation"; import type { Entity } from "@lysand-org/federation/types"; import { and, eq, inArray, sql } from "drizzle-orm"; import { z } from "zod"; @@ -100,22 +98,7 @@ export default (app: Hono) => const author = foundAuthor ?? User.getServerActor(); - const { headers, signedString } = await ( - await SignatureConstructor.fromStringKey( - author.data.privateKey ?? "", - author.getUri(), - ) - ).sign("POST", reqUrl, objectString); - - if (config.debug.federation) { - const logger = getLogger("federation"); - - // Log public key - logger.debug`Sender public key: ${author.data.publicKey}`; - - // Log signed string - logger.debug`Signed string:\n${signedString}`; - } + const { headers } = await author.sign(apiObject, reqUrl, "GET"); return response(objectString, 200, { "Content-Type": "application/json", diff --git a/server/api/users/:uuid/index.ts b/server/api/users/:uuid/index.ts index 412f34e6..8ef12745 100644 --- a/server/api/users/:uuid/index.ts +++ b/server/api/users/:uuid/index.ts @@ -2,8 +2,6 @@ import { applyConfig, handleZodError } from "@/api"; import { errorResponse, redirect, response } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; -import { getLogger } from "@logtape/logtape"; -import { SignatureConstructor } from "@lysand-org/federation"; import { z } from "zod"; import { config } from "~/packages/config-manager"; import { User } from "~/packages/database-interface/user"; @@ -84,22 +82,7 @@ export default (app: Hono) => reqUrl.protocol = "https:"; } - const { headers, signedString } = await ( - await SignatureConstructor.fromStringKey( - user.data.privateKey ?? "", - user.getUri(), - ) - ).sign("POST", reqUrl, userString); - - if (config.debug.federation) { - const logger = getLogger("federation"); - - // Log public key - logger.debug`Sender public key: ${user.data.publicKey}`; - - // Log signed string - logger.debug`Signed string:\n${signedString}`; - } + const { headers } = await user.sign(user.toLysand(), reqUrl, "GET"); return response(userString, 200, { "Content-Type": "application/json", diff --git a/server/api/well-known/webfinger/index.ts b/server/api/well-known/webfinger/index.ts index 909d1796..8091fd40 100644 --- a/server/api/well-known/webfinger/index.ts +++ b/server/api/well-known/webfinger/index.ts @@ -8,11 +8,7 @@ import { errorResponse, jsonResponse } from "@/response"; import type { Hono } from "@hono/hono"; import { zValidator } from "@hono/zod-validator"; import { getLogger } from "@logtape/logtape"; -import { - FederationRequester, - type ResponseError, - SignatureConstructor, -} from "@lysand-org/federation"; +import type { ResponseError } from "@lysand-org/federation"; import { and, eq, isNull } from "drizzle-orm"; import { lookup } from "mime-types"; import { z } from "zod"; @@ -84,13 +80,7 @@ export default (app: Hono) => if (config.federation.bridge.enabled) { const requester = await User.getServerActor(); - const signatureConstructor = - await SignatureConstructor.fromStringKey( - requester.data.privateKey ?? "", - requester.getUri(), - ); - - const manager = new FederationRequester(signatureConstructor); + const manager = await requester.getFederationRequester(); try { activityPubUrl = await manager.webFinger(