mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
fix(mastodon): use lookupWithSecurity for remote profile resolution
Replace direct ctx.lookupObject() call in resolveRemoteAccount with lookupWithSecurity() so servers that reject signed GETs are retried unsigned. Also add 5 s Promise.race timeouts to followers/following/ outbox collection fetches to prevent profile loads from hanging on slow remote servers. Fixes missing profile pictures and zero follower stats in Mastodon client views. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
import { serializeAccount } from "../entities/account.js";
|
import { serializeAccount } from "../entities/account.js";
|
||||||
import { cacheAccountStats } from "./account-cache.js";
|
import { cacheAccountStats } from "./account-cache.js";
|
||||||
|
import { lookupWithSecurity } from "../../lookup-helpers.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} acct - Account identifier (user@domain or URL)
|
* @param {string} acct - Account identifier (user@domain or URL)
|
||||||
@@ -37,7 +38,9 @@ export async function resolveRemoteAccount(acct, pluginOptions, baseUrl) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actor = await ctx.lookupObject(actorUri);
|
// Use signed→unsigned fallback so servers rejecting signed GETs still resolve
|
||||||
|
const documentLoader = await ctx.getDocumentLoader({ identifier: handle });
|
||||||
|
const actor = await lookupWithSecurity(ctx, actorUri, { documentLoader });
|
||||||
if (!actor) return null;
|
if (!actor) return null;
|
||||||
|
|
||||||
// Extract data from the Fedify actor object
|
// Extract data from the Fedify actor object
|
||||||
@@ -61,20 +64,23 @@ export async function resolveRemoteAccount(acct, pluginOptions, baseUrl) {
|
|||||||
headerUrl = image?.url?.href || "";
|
headerUrl = image?.url?.href || "";
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
// Get collection counts (followers, following, outbox)
|
// Get collection counts (followers, following, outbox) — with 5 s timeout each
|
||||||
|
const withTimeout = (promise, ms = 5000) =>
|
||||||
|
Promise.race([promise, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), ms))]);
|
||||||
|
|
||||||
let followersCount = 0;
|
let followersCount = 0;
|
||||||
let followingCount = 0;
|
let followingCount = 0;
|
||||||
let statusesCount = 0;
|
let statusesCount = 0;
|
||||||
try {
|
try {
|
||||||
const followers = await actor.getFollowers();
|
const followers = await withTimeout(actor.getFollowers());
|
||||||
if (followers?.totalItems != null) followersCount = followers.totalItems;
|
if (followers?.totalItems != null) followersCount = followers.totalItems;
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
try {
|
try {
|
||||||
const following = await actor.getFollowing();
|
const following = await withTimeout(actor.getFollowing());
|
||||||
if (following?.totalItems != null) followingCount = following.totalItems;
|
if (following?.totalItems != null) followingCount = following.totalItems;
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
try {
|
try {
|
||||||
const outbox = await actor.getOutbox();
|
const outbox = await withTimeout(actor.getOutbox());
|
||||||
if (outbox?.totalItems != null) statusesCount = outbox.totalItems;
|
if (outbox?.totalItems != null) statusesCount = outbox.totalItems;
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user