refactor(federation): 🔥 Remove old code and simplify federation requests

This commit is contained in:
Jesse Wierzbinski 2024-07-26 18:51:39 +02:00
parent ad9ed2598c
commit 2f823317c2
No known key found for this signature in database
18 changed files with 182 additions and 302 deletions

View file

@ -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<typeof Emojis> & {
instance: InferSelectModel<typeof Instances> | 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<Emoji[]> => {
const matches = text.match(emojiValidatorWithColons);
if (!matches || matches.length === 0) {
return [];
}
return Emoji.manyFromSql(
inArray(
Emojis.shortcode,
matches.map((match) => match.replace(/:/g, "")),
),
);
};

View file

@ -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<Request> => {
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 {

View file

@ -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()}`;
}
}
};

View file

@ -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 = (