Changeset 86cfa1a in Klonkt


Ignore:
Timestamp:
09/30/2026 07:00:30 AM (97 minutes ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
fd8faf5
Parents:
9eb6e1b
Message:

Een profiel op mastodon.social laadt: ook het profiel wordt ondertekend opgehaald

Plak je ​https://mastodon.social/@hotdogsladies in de zoekbalk, dan kwam er
"niet gevonden"; ​https://arvr.social/@bedrijfzondernaam liet gewoon een profiel
zien. Allebei Mastodon. Het verschil is authorized fetch: mastodon.social geeft
een onbetekende GET van een profiel een 401 {"error":"Request not signed"},
arvr.social serveert hem aan iedereen.

fetchActor kan dat al aan -- eerst onbetekend, en tekenen als dat niet lukt --
maar alleen als de aanroeper zegt als welke site. resolveRemoteActor gaf dat
nooit door, dus tekende nooit. De ironie: de zoekbalk probeert eerst "is het een
post?", en dat verzoek gaat WEL ondertekend en krijgt het profiel ook terug, maar
gooit het weg omdat het geen post is. Daarna haalde de profielstap hetzelfde
adres opnieuw op, onbetekend.

Gemeten op dev voor de wijziging: onbetekend niets, ondertekend als dev het
profiel met inbox. arvr.social in beide gevallen gevonden, en daar gaat ook
geen ondertekend verzoek uit: dat is alleen de terugval.

ALLEEN ALS JE INGELOGD BENT (Robin, 30-9). Tekenen is deze site die met haar
eigen sleutel voor het verzoek instaat, en dat mag alleen namens een ingelogde
beheerder van die site. resolveRemoteActor blijft zonder opts onbetekend; de
enige aanroepers die de site meegeven zijn de zoekbalk (achter mayLookUp) en
/authorize_interaction (requireSiteManager).

De volgknop had dit gat niet: followActor haalt al sinds 31-7 ondertekend op.

Getoetst: het profiel ondertekend op de zoekpagina, in de preview en op de
interactiepagina, en dat niet ingelogd geen enkel verzoek uitgaat, dus ook geen
ondertekend. Tegenproef: onbetekend in de zoekbalk, onbetekend op de
interactiepagina en de inlogcontrole eruit laten elk hun eigen toets omvallen.
Volledige suite 1286 groen.

shaer-utpi

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

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r9eb6e1b r86cfa1a  
    881881    try { target = await ActivityPubService.resolveRemoteNote(uri, site ? { asSlug: site.slug } : {}); } catch { /* ignore */ }
    882882    // Not a post? Maybe the URI is a profile/actor → offer Follow, not reply.
    883     if (!target) { try { followTarget = await ActivityPubService.resolveRemoteActor(uri); } catch { /* ignore */ } }
     883    if (!target) { try { followTarget = await ActivityPubService.resolveRemoteActor(uri, site ? { asSlug: site.slug } : {}); } catch { /* ignore */ } }
    884884  }
    885885  renderPage(req, res, 'pages/authorize-interaction', {
  • src/routes/search.js

    r9eb6e1b r86cfa1a  
    120120  if (remote) remoteKind = 'note';
    121121  if (!remote) {
    122     try { remote = await ActivityPubService.resolveRemoteActor(remoteUri); } catch { /* onbereikbaar */ }
     122    // Ook ondertekend: een profiel op een instance met authorized fetch
     123    // (mastodon.social) geeft anders een 401 en leek dan niet te bestaan.
     124    try { remote = await ActivityPubService.resolveRemoteActor(remoteUri, { asSlug: site.slug }); } catch { /* onbereikbaar */ }
    123125    if (remote) remoteKind = 'actor';
    124126  }
  • src/services/ap-following.js

    r9eb6e1b r86cfa1a  
    172172// authorize_interaction "Follow" flow). Returns display fields + inbox, or null
    173173// when it isn't a reachable actor (e.g. the input was a post, not a profile).
    174 export async function resolveRemoteActor(input) {
     174//
     175// ONDERTEKEND ALLEEN ALS DE AANROEPER DE SITE NOEMT (opts.asSlug). Een instance
     176// met authorized fetch (mastodon.social) geeft een onbetekende GET een 401, en
     177// dan leek een bestaand profiel te ontbreken -- terwijl een ander Mastodon
     178// zonder die instelling het wel toonde. fetchActor probeert eerst onbetekend en
     179// tekent pas als dat niet lukt.
     180//
     181// Tekenen is deze site die voor het verzoek instaat, met haar eigen sleutel.
     182// Dat mag alleen namens een ingelogde beheerder van die site: de zoekbalk
     183// (achter mayLookUp) en /authorize_interaction (requireSiteManager) zijn de
     184// enige die asSlug meegeven. Zonder opts blijft dit onbetekend.
     185export async function resolveRemoteActor(input, opts = {}) {
    175186  const s = String(input || '').trim();
    176187  const actorUrl = /^https?:\/\//i.test(s) ? (safeUrl(s) || null) : await webfingerResolve(s);
    177188  if (!actorUrl) return null;
    178   const actor = await fetchActor(actorUrl).catch(() => null);
     189  const actor = await fetchActor(actorUrl, opts.asSlug ? { asSlug: opts.asSlug } : {}).catch(() => null);
    179190  if (!actor || !actor.id || !actor.inbox) return null;
    180191  const ai = actorInfo(actor, actor.id);
  • test/search-fediverse.test.js

    r9eb6e1b r86cfa1a  
    5151  };
    5252};
    53 AP.resolveRemoteActor = async (uri) => {
     53let actorOpties = [];
     54AP.resolveRemoteActor = async (uri, opts) => {
    5455  gevraagd.push(['actor', uri]);
     56  actorOpties.push(opts || {});
    5557  if (!uri.includes('/u/')) return null;
    5658  return {
    … …  
    281283});
    282284
     285// ── Een profiel op een instance met authorized fetch ────────────────────────
     286//
     287// mastodon.social geeft een onbetekende GET van een profiel een 401; arvr.social
     288// niet. Het profiel werd onbetekend opgehaald, dus het ene Mastodon toonde een
     289// profiel en het andere "niet gevonden". De post-kant was al ondertekend, de
     290// profiel-kant niet (gemeten op dev, 30-9: onbetekend niets, als dev gevonden).
     291//
     292// En de regel eronder: ondertekenen is deze site die voor het verzoek instaat,
     293// en dat mag alleen namens een INGELOGDE beheerder. Een bezoeker laat niets
     294// ophalen, ondertekend of niet.
     295
     296test('een profiel wordt ondertekend opgehaald, op de zoekpagina en in de preview', async () => {
     297  actorOpties = [];
     298  await zoek('https://elders.test/u/oma');
     299  assert.equal(actorOpties[0] && actorOpties[0].asSlug, 'robo', 'de zoekpagina haalt het profiel als de site op');
     300  actorOpties = [];
     301  await preview('https://elders.test/u/oma');
     302  assert.equal(actorOpties[0] && actorOpties[0].asSlug, 'robo', 'de preview ook');
     303});
     304
     305test('ook de interactiepagina haalt een profiel ondertekend op', async () => {
     306  actorOpties = [];
     307  await fetch(`http://127.0.0.1:${poort2}/authorize_interaction?uri=${encodeURIComponent('https://elders.test/u/oma')}`,
     308    { signal: AbortSignal.timeout(10000) });
     309  assert.equal(actorOpties[0] && actorOpties[0].asSlug, 'robo');
     310});
     311
     312test('niet ingelogd gaat er geen enkel verzoek uit, dus ook geen ondertekend', async () => {
     313  ingelogd = false;
     314  try {
     315    actorOpties = [];
     316    await zoek('https://elders.test/u/oma');
     317    await preview('https://elders.test/u/oma');
     318    assert.deepEqual(gevraagd, [], 'geen post- en geen profielopvraging');
     319    assert.deepEqual(actorOpties, [], 'en dus niets dat de sleutel van de site gebruikt');
     320  } finally {
     321    ingelogd = true;
     322  }
     323});
     324
Note: See TracChangeset for help on using the changeset viewer.