Ignore:
Timestamp:
06/25/2026 09:08:20 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
7c62efb
Parents:
4c12783
Message:

feat(ap): authorize_interaction handles actor URIs as a Follow

The fediverse interaction page only did reply/like — it always tried to
resolve the URI as a post. A profile/actor URL fell through to the reply
composer, so 'following' produced a reply. Now: if the URI isn't a post,
resolve it as an actor and show a Follow action (followActor, which now
accepts a profile URL as well as an @handle). Adds fedi.follow_* i18n (nl/en/de).

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r4c12783 r8ad1784  
    10251025  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
    10261026  if (!base || !site || !site.slug) return { error: 'config' };
    1027   const actorUrl = await webfingerResolve(handle);
     1027  // Accept either an @user@host handle (WebFinger) or a profile/actor URL directly
     1028  // (the authorize_interaction Follow flow passes a URL).
     1029  const s = String(handle || '').trim();
     1030  const actorUrl = /^https?:\/\//i.test(s) ? (safeUrl(s) || null) : await webfingerResolve(s);
    10281031  if (!actorUrl) return { error: 'not_found' };
    10291032  const actor = await fetchActor(actorUrl).catch(() => null);
     
    10391042  console.log('[AP] follow', site.slug, '→', actor.id);
    10401043  return { ok: true, name: ai.name, handle: ai.handle };
     1044}
     1045
     1046// Resolve a profile URL or @handle to a followable remote actor (for the
     1047// authorize_interaction "Follow" flow). Returns display fields + inbox, or null
     1048// when it isn't a reachable actor (e.g. the input was a post, not a profile).
     1049export async function resolveRemoteActor(input) {
     1050  const s = String(input || '').trim();
     1051  const actorUrl = /^https?:\/\//i.test(s) ? (safeUrl(s) || null) : await webfingerResolve(s);
     1052  if (!actorUrl) return null;
     1053  const actor = await fetchActor(actorUrl).catch(() => null);
     1054  if (!actor || !actor.id || !actor.inbox) return null;
     1055  const ai = actorInfo(actor, actor.id);
     1056  return { actor_uri: actor.id, actor_name: ai.name, actor_handle: ai.handle, actor_url: ai.url, actor_icon: ai.icon, inbox: actor.inbox };
    10411057}
    10421058
     
    11621178  getInteractions, getInteractionById, buildReplyNote, getOutboxNote, deliverReply, resolveRemoteNote,
    11631179  listOutbox, deliverOutboxDelete,
    1164   webfingerResolve, followActor, unfollowActor, listFollowing, getTimeline, sendInteraction,
     1180  webfingerResolve, followActor, resolveRemoteActor, unfollowActor, listFollowing, getTimeline, sendInteraction,
    11651181  getNotifications, listBlocks, isBlockedAny, blockTarget, unblock,
    11661182  deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker,
Note: See TracChangeset for help on using the changeset viewer.