[backend] Federate outgoing invalid mentions as text

This commit is contained in:
Laura Hausmann 2023-10-17 20:53:36 +02:00
parent 5dcd4c4fff
commit 4920b0c768
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
3 changed files with 27 additions and 34 deletions

View file

@ -3,7 +3,7 @@ import type * as mfm from "mfm-js";
import config from "@/config/index.js"; import config from "@/config/index.js";
import { intersperse } from "@/prelude/array.js"; import { intersperse } from "@/prelude/array.js";
import type { IMentionedRemoteUsers } from "@/models/entities/note.js"; import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
import { resolveMentionWithFallback } from "@/remote/resolve-user.js"; import { resolveMentionFromCache } from "@/remote/resolve-user.js";
export async function toHtml( export async function toHtml(
nodes: mfm.MfmNode[] | null, nodes: mfm.MfmNode[] | null,
@ -113,19 +113,26 @@ export async function toHtml(
return a; return a;
}, },
async mention(node) { mention(node) {
const el = doc.createElement("span");
el.setAttribute("class", "h-card");
el.setAttribute("translate", "no");
const a = doc.createElement("a");
const { username, host, acct } = node.props; const { username, host, acct } = node.props;
a.href = await resolveMentionWithFallback(username, host, objectHost, mentionedRemoteUsers); const href = resolveMentionFromCache(username, host, objectHost, mentionedRemoteUsers);
a.className = "u-url mention";
const span = doc.createElement("span"); const el = doc.createElement("span");
span.textContent = username; if (href === null) {
a.textContent = '@'; el.textContent = acct;
a.appendChild(span); } else {
el.appendChild(a); el.setAttribute("class", "h-card");
el.setAttribute("translate", "no");
const a = doc.createElement("a");
a.href = href;
a.className = "u-url mention";
const span = doc.createElement("span");
span.textContent = username;
a.textContent = '@';
a.appendChild(span);
el.appendChild(a);
}
return el; return el;
}, },

View file

@ -13,7 +13,6 @@ import { IMentionedRemoteUsers } from "@/models/entities/note.js";
const logger = remoteLogger.createSubLogger("resolve-user"); const logger = remoteLogger.createSubLogger("resolve-user");
const uriHostCache = new Cache<string>("resolveUserUriHost", 60 * 60 * 24); const uriHostCache = new Cache<string>("resolveUserUriHost", 60 * 60 * 24);
const mentionUriCache = new Cache<string>("resolveMentionUserUri", 60 * 60 * 72);
export async function resolveUser( export async function resolveUser(
username: string, username: string,
@ -207,24 +206,13 @@ export function getMentionFallbackUri(username: string, host: string | null, obj
return fallback; return fallback;
} }
export async function resolveMentionWithFallback(username: string, host: string | null, objectHost: string | null, cache: IMentionedRemoteUsers, cachedOnly: boolean = false): Promise<string> { export function resolveMentionFromCache(username: string, host: string | null, objectHost: string | null, cache: IMentionedRemoteUsers): string | null {
const fallback = getMentionFallbackUri(username, host, objectHost); const fallback = getMentionFallbackUri(username, host, objectHost);
const cached = cache.find(r => r.username.toLowerCase() === username.toLowerCase() && r.host === host); const cached = cache.find(r => r.username.toLowerCase() === username.toLowerCase() && r.host === host);
if (cached) return cached.url ?? cached.uri ?? fallback; if (cached) return cached.url ?? cached.uri ?? fallback;
if ((host === null && objectHost === null) || host === config.domain) return fallback; if ((host === null && objectHost === null) || host === config.domain) return fallback;
if (cachedOnly) return fallback; return null;
return mentionUriCache.fetch(fallback, async () => {
try {
const user = await resolveUser(username, host ?? objectHost, false);
const profile = await UserProfiles.findOneBy({ userId: user.id });
return profile?.url ?? user.uri ?? fallback;
}
catch {
return fallback;
}
});
} }
export async function getSubjectHostFromUri(uri: string): Promise<string | null> { export async function getSubjectHostFromUri(uri: string): Promise<string | null> {

View file

@ -3,7 +3,7 @@ import { JSDOM } from "jsdom";
import config from "@/config/index.js"; import config from "@/config/index.js";
import { intersperse } from "@/prelude/array.js"; import { intersperse } from "@/prelude/array.js";
import mfm from "mfm-js"; import mfm from "mfm-js";
import { resolveMentionWithFallback } from "@/remote/resolve-user.js"; import { resolveMentionFromCache } from "@/remote/resolve-user.js";
export class MfmHelpers { export class MfmHelpers {
public static async toHtml( public static async toHtml(
@ -135,20 +135,18 @@ export class MfmHelpers {
return a; return a;
}, },
async mention(node) { mention(node) {
const { username, host, acct } = node.props; const { username, host, acct } = node.props;
const fallback = await resolveMentionWithFallback(username, host, objectHost, mentionedRemoteUsers, true); const href = resolveMentionFromCache(username, host, objectHost, mentionedRemoteUsers);
const isLocal = (host === null && objectHost === null) || host === config.domain;
const isInvalid = fallback.startsWith(config.url) && !isLocal;
const el = doc.createElement("span"); const el = doc.createElement("span");
if (isInvalid) { if (href === null) {
el.textContent = acct; el.textContent = acct;
} else { } else {
el.setAttribute("class", "h-card"); el.setAttribute("class", "h-card");
el.setAttribute("translate", "no"); el.setAttribute("translate", "no");
const a = doc.createElement("a"); const a = doc.createElement("a");
a.href = fallback; a.href = href;
a.className = "u-url mention"; a.className = "u-url mention";
const span = doc.createElement("span"); const span = doc.createElement("span");
span.textContent = username; span.textContent = username;