fix(federation): 🐛 Fix remote emojis being incorrectly marked as local

This commit is contained in:
Jesse Wierzbinski 2024-12-09 13:11:23 +01:00
parent c94dd7c59d
commit cbbf49905b
No known key found for this signature in database
4 changed files with 40 additions and 24 deletions

View file

@ -2,7 +2,7 @@ import { emojiValidatorWithColons, emojiValidatorWithIdentifiers } from "@/api";
import { proxyUrl } from "@/response"; import { proxyUrl } from "@/response";
import type { Emoji as APIEmoji } from "@versia/client/types"; import type { Emoji as APIEmoji } from "@versia/client/types";
import type { CustomEmojiExtension } from "@versia/federation/types"; import type { CustomEmojiExtension } from "@versia/federation/types";
import { db } from "@versia/kit/db"; import { type Instance, db } from "@versia/kit/db";
import { Emojis, Instances } from "@versia/kit/tables"; import { Emojis, Instances } from "@versia/kit/tables";
import { import {
type InferInsertModel, type InferInsertModel,
@ -12,10 +12,10 @@ import {
desc, desc,
eq, eq,
inArray, inArray,
isNull,
} from "drizzle-orm"; } from "drizzle-orm";
import { z } from "zod"; import { z } from "zod";
import { BaseInterface } from "./base.ts"; import { BaseInterface } from "./base.ts";
import { Instance } from "./instance.ts";
type EmojiWithInstance = InferSelectModel<typeof Emojis> & { type EmojiWithInstance = InferSelectModel<typeof Emojis> & {
instance: InferSelectModel<typeof Instances> | null; instance: InferSelectModel<typeof Instances> | null;
@ -135,7 +135,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
public static async fetchFromRemote( public static async fetchFromRemote(
emojiToFetch: CustomEmojiExtension["emojis"][0], emojiToFetch: CustomEmojiExtension["emojis"][0],
host?: string, instance: Instance,
): Promise<Emoji> { ): Promise<Emoji> {
const existingEmoji = await db const existingEmoji = await db
.select() .select()
@ -144,7 +144,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
.where( .where(
and( and(
eq(Emojis.shortcode, emojiToFetch.name), eq(Emojis.shortcode, emojiToFetch.name),
host ? eq(Instances.baseUrl, host) : undefined, eq(Instances.id, instance.id),
), ),
) )
.limit(1); .limit(1);
@ -159,9 +159,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
return found; return found;
} }
const foundInstance = host ? await Instance.resolve(host) : null; return await Emoji.fromVersia(emojiToFetch, instance);
return await Emoji.fromVersia(emojiToFetch, foundInstance?.id ?? null);
} }
public get id(): string { public get id(): string {
@ -181,10 +179,13 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
} }
return Emoji.manyFromSql( return Emoji.manyFromSql(
and(
inArray( inArray(
Emojis.shortcode, Emojis.shortcode,
matches.map((match) => match.replace(/:/g, "")), matches.map((match) => match.replace(/:/g, "")),
), ),
isNull(Emojis.instanceId),
),
); );
} }
@ -216,7 +217,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
public static fromVersia( public static fromVersia(
emoji: CustomEmojiExtension["emojis"][0], emoji: CustomEmojiExtension["emojis"][0],
instanceId: string | null, instance: Instance,
): Promise<Emoji> { ): Promise<Emoji> {
// Extracts the shortcode from the emoji name (e.g. :shortcode: -> shortcode) // Extracts the shortcode from the emoji name (e.g. :shortcode: -> shortcode)
const shortcode = [ const shortcode = [
@ -233,7 +234,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
alt: Object.entries(emoji.url)[0][1].description || undefined, alt: Object.entries(emoji.url)[0][1].description || undefined,
contentType: Object.keys(emoji.url)[0], contentType: Object.keys(emoji.url)[0],
visibleInPicker: true, visibleInPicker: true,
instanceId, instanceId: instance.id,
}); });
} }
} }

View file

@ -13,7 +13,7 @@ import type {
Delete as VersiaDelete, Delete as VersiaDelete,
Note as VersiaNote, Note as VersiaNote,
} from "@versia/federation/types"; } from "@versia/federation/types";
import { type Instance, Notification, db } from "@versia/kit/db"; import { Instance, Notification, db } from "@versia/kit/db";
import { import {
Attachments, Attachments,
EmojiToNote, EmojiToNote,
@ -715,6 +715,11 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
*/ */
public static async saveFromRemote(uri: string): Promise<Note | null> { public static async saveFromRemote(uri: string): Promise<Note | null> {
let note: VersiaNote | null = null; let note: VersiaNote | null = null;
const instance = await Instance.resolve(uri);
if (!instance) {
return null;
}
if (uri) { if (uri) {
if (!URL.canParse(uri)) { if (!URL.canParse(uri)) {
@ -741,7 +746,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
throw new Error("Invalid object author"); throw new Error("Invalid object author");
} }
return await Note.fromVersia(note, author); return await Note.fromVersia(note, author, instance);
} }
/** /**
@ -753,19 +758,21 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
public static async fromVersia( public static async fromVersia(
note: VersiaNote, note: VersiaNote,
author: User, author: User,
instance: Instance,
): Promise<Note> { ): Promise<Note> {
const emojis: Emoji[] = []; const emojis: Emoji[] = [];
const logger = getLogger(["federation", "resolvers"]); const logger = getLogger(["federation", "resolvers"]);
for (const emoji of note.extensions?.["pub.versia:custom_emojis"] for (const emoji of note.extensions?.["pub.versia:custom_emojis"]
?.emojis ?? []) { ?.emojis ?? []) {
const resolvedEmoji = await Emoji.fetchFromRemote(emoji).catch( const resolvedEmoji = await Emoji.fetchFromRemote(
(e) => { emoji,
instance,
).catch((e) => {
logger.error`${e}`; logger.error`${e}`;
sentry?.captureException(e); sentry?.captureException(e);
return null; return null;
}, });
);
if (resolvedEmoji) { if (resolvedEmoji) {
emojis.push(resolvedEmoji); emojis.push(resolvedEmoji);

View file

@ -667,7 +667,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
const userEmojis = const userEmojis =
data.extensions?.["pub.versia:custom_emojis"]?.emojis ?? []; data.extensions?.["pub.versia:custom_emojis"]?.emojis ?? [];
const emojis = await Promise.all( const emojis = await Promise.all(
userEmojis.map((emoji) => Emoji.fromVersia(emoji, instance.id)), userEmojis.map((emoji) => Emoji.fromVersia(emoji, instance)),
); );
if (emojis.length > 0) { if (emojis.length > 0) {

View file

@ -16,7 +16,7 @@ import type {
User as VersiaUser, User as VersiaUser,
} from "@versia/federation/types"; } from "@versia/federation/types";
import { import {
type Instance, Instance,
Like, Like,
Note, Note,
Notification, Notification,
@ -277,6 +277,14 @@ export class InboxProcessor {
private async processNote(): Promise<Response | null> { private async processNote(): Promise<Response | null> {
const note = this.body as VersiaNote; const note = this.body as VersiaNote;
const author = await User.resolve(note.author); const author = await User.resolve(note.author);
const instance = await Instance.resolve(note.uri);
if (!instance) {
return Response.json(
{ error: "Instance not found" },
{ status: 404 },
);
}
if (!author) { if (!author) {
return Response.json( return Response.json(
@ -285,7 +293,7 @@ export class InboxProcessor {
); );
} }
await Note.fromVersia(note, author); await Note.fromVersia(note, author, instance);
return null; return null;
} }