From 0e39313ac4770ec69a7f5f5bd55084a5ece57971 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Thu, 12 Oct 2023 21:31:41 +0200 Subject: [PATCH] [mastodon-client] Correctly parse invalid remote mentions --- .../src/server/api/mastodon/converters/announcement.ts | 2 +- .../backend/src/server/api/mastodon/converters/note.ts | 2 +- .../backend/src/server/api/mastodon/converters/user.ts | 8 ++++---- packages/backend/src/server/api/mastodon/helpers/mfm.ts | 7 +++++-- packages/backend/src/server/api/mastodon/helpers/note.ts | 6 +++--- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/converters/announcement.ts b/packages/backend/src/server/api/mastodon/converters/announcement.ts index 35cd142df..6098cf1f3 100644 --- a/packages/backend/src/server/api/mastodon/converters/announcement.ts +++ b/packages/backend/src/server/api/mastodon/converters/announcement.ts @@ -6,7 +6,7 @@ export class AnnouncementConverter { public static encode(announcement: Announcement, isRead: boolean): MastodonEntity.Announcement { return { id: announcement.id, - content: `

${MfmHelpers.toHtml(mfm.parse(announcement.title), []) ?? 'Announcement'}

${MfmHelpers.toHtml(mfm.parse(announcement.text), []) ?? ''}`, + content: `

${MfmHelpers.toHtml(mfm.parse(announcement.title), [], null) ?? 'Announcement'}

${MfmHelpers.toHtml(mfm.parse(announcement.text), [], null) ?? ''}`, starts_at: null, ends_at: null, published: true, diff --git a/packages/backend/src/server/api/mastodon/converters/note.ts b/packages/backend/src/server/api/mastodon/converters/note.ts index 287f9e9ad..4c8c77c39 100644 --- a/packages/backend/src/server/api/mastodon/converters/note.ts +++ b/packages/backend/src/server/api/mastodon/converters/note.ts @@ -117,7 +117,7 @@ export class NoteConverter { in_reply_to_id: note.replyId, in_reply_to_account_id: note.replyUserId, reblog: reblog.then(reblog => note.text === null ? reblog : null), - content: text.then(text => text !== null ? MfmHelpers.toHtml(mfm.parse(text), JSON.parse(note.mentionedRemoteUsers)) ?? escapeMFM(text) : ""), + content: text.then(async text => text !== null ? await host.then(host => MfmHelpers.toHtml(mfm.parse(text), JSON.parse(note.mentionedRemoteUsers), host)) ?? escapeMFM(text) : ""), text: text, created_at: note.createdAt.toISOString(), emojis: noteEmoji, diff --git a/packages/backend/src/server/api/mastodon/converters/user.ts b/packages/backend/src/server/api/mastodon/converters/user.ts index 08f0a252e..9abaebb72 100644 --- a/packages/backend/src/server/api/mastodon/converters/user.ts +++ b/packages/backend/src/server/api/mastodon/converters/user.ts @@ -31,7 +31,7 @@ export class UserConverter { acctUrl = `https://${u.host}/@${u.username}`; } const profile = UserProfiles.findOneBy({ userId: u.id }); - const bio = profile.then(profile => MfmHelpers.toHtml(mfm.parse(profile?.description ?? "")) ?? escapeMFM(profile?.description ?? "")); + const bio = profile.then(profile => MfmHelpers.toHtml(mfm.parse(profile?.description ?? ""), [], u.host) ?? escapeMFM(profile?.description ?? "")); const avatar = u.avatarId ? (DriveFiles.findOneBy({ id: u.avatarId })) .then(p => p?.url ?? Users.getIdenticonUrl(u.id)) @@ -92,7 +92,7 @@ export class UserConverter { header_static: banner, emojis: populateEmojis(u.emojis, u.host).then(emoji => emoji.map((e) => EmojiConverter.encode(e))), moved: null, //FIXME - fields: profile.then(profile => profile?.fields.map(p => this.encodeField(p)) ?? []), + fields: profile.then(profile => profile?.fields.map(p => this.encodeField(p, u.host)) ?? []), bot: u.isBot, discoverable: u.isExplorable }).then(p => { @@ -107,10 +107,10 @@ export class UserConverter { return Promise.all(encoded); } - private static encodeField(f: Field): MastodonEntity.Field { + private static encodeField(f: Field, host: string | null): MastodonEntity.Field { return { name: f.name, - value: MfmHelpers.toHtml(mfm.parse(f.value), undefined, true) ?? escapeMFM(f.value), + value: MfmHelpers.toHtml(mfm.parse(f.value), [], host, true) ?? escapeMFM(f.value), verified_at: f.verified ? (new Date()).toISOString() : null, } } diff --git a/packages/backend/src/server/api/mastodon/helpers/mfm.ts b/packages/backend/src/server/api/mastodon/helpers/mfm.ts index 931036e29..1ad879654 100644 --- a/packages/backend/src/server/api/mastodon/helpers/mfm.ts +++ b/packages/backend/src/server/api/mastodon/helpers/mfm.ts @@ -8,6 +8,7 @@ export class MfmHelpers { public static toHtml( nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], + objectHost: string | null, inline: boolean = false ) { if (nodes == null) { @@ -142,7 +143,7 @@ export class MfmHelpers { remoteUser.username === username && remoteUser.host === host, ); const localpart = `@${username}`; - const isLocal = host === config.domain || host === null; + const isLocal = host === config.domain || (host == null && objectHost == null); const acct = isLocal ? localpart: node.props.acct; a.href = remoteUserInfo ? remoteUserInfo.url @@ -150,7 +151,9 @@ export class MfmHelpers { : remoteUserInfo.uri : isLocal ? `${config.url}/${acct}` - : `https://${host}/${localpart}`; + : host == null + ? `https://${objectHost}/${localpart}` + : `https://${host}/${localpart}`; a.className = "u-url mention"; const span = doc.createElement("span"); span.textContent = username; diff --git a/packages/backend/src/server/api/mastodon/helpers/note.ts b/packages/backend/src/server/api/mastodon/helpers/note.ts index 776515876..3e571d9fd 100644 --- a/packages/backend/src/server/api/mastodon/helpers/note.ts +++ b/packages/backend/src/server/api/mastodon/helpers/note.ts @@ -179,8 +179,8 @@ export class NoteHelpers { } public static async getNoteEditHistory(note: Note, ctx: MastoContext): Promise { - const account = Promise.resolve(note.user ?? await UserHelpers.getUserCached(note.userId, ctx)) - .then(p => UserConverter.encode(p, ctx)); + const user = Promise.resolve(note.user ?? await UserHelpers.getUserCached(note.userId, ctx)); + const account = user.then(p => UserConverter.encode(p, ctx)); const edits = await NoteEdits.find({ where: { noteId: note.id }, order: { id: "ASC" } }); const history: Promise[] = []; @@ -201,7 +201,7 @@ export class NoteHelpers { const files = DriveFiles.packMany(edit.fileIds); const item = { account: account, - content: MfmHelpers.toHtml(mfm.parse(edit.text ?? ''), JSON.parse(note.mentionedRemoteUsers)) ?? '', + content: user.then(user => MfmHelpers.toHtml(mfm.parse(edit.text ?? ''), JSON.parse(note.mentionedRemoteUsers), user.host) ?? ''), created_at: lastDate.toISOString(), emojis: [], sensitive: files.then(files => files.length > 0 ? files.some((f) => f.isSensitive) : false),