Changeset 0bafe9e in Klonkt for test/authorized-fetch.test.js


Ignore:
Timestamp:
08/06/2026 10:49:06 AM (5 weeks ago)
Author:
Claude (agent) <aiclaude@…>
Branches:
main
Children:
d74a461
Parents:
5d0d41d
git-author:
Robin <roboburr@…> (08/06/2026 10:49:05 AM)
git-committer:
Claude (agent) <aiclaude@…> (08/06/2026 10:49:06 AM)
Message:

Niet standaard ondertekenen bij de sleutel-ophaal (regressie van 9561d58)

Robins vraag legde bloot wat ik een uur eerder zelf had verslechterd.
verifyRequest haalt de keyId-URL op VOORDAT er iets geverifieerd is, en die URL
komt uit een header die iedereen mag sturen. Sinds 9561d58 werd dat verzoek
standaard ondertekend als een van onze actors -- dus kon een volslagen onbekende
met één POST boiert een ONDERTEKEND verzoek laten sturen naar een adres van zijn
keuze, met onze identiteit eronder. Dat is hoe een instance op een blocklist
belandt.

fetchActor probeert nu onbetekend eerst en tekent alleen als dat niets bruikbaars
oplevert. Voor een instance met authorized fetch verandert er niets behalve één
extra verzoek; voor alle andere verdwijnt de handtekening weer. Een document dat
onbetekend wél komt maar zonder publicKey telt als mislukt -- voor een
verificatie heb je daar niets aan.

Twee tests erbij die de VOLGORDE vastleggen, want dat is hier de hele zaak: een
open instance krijgt precies één, onbetekend verzoek, en een kaal document leidt
tot een tweede, ondertekende poging.

Wat hiermee NIET is opgelost, en in shaer-afq staat: de ophaal blijft aanroepbaar
door een onbekende, alleen niet meer namens ons. Het smaller maken van de
dereference (alleen bij een inReplyTo die we kennen) en het onthouden van
mislukte pogingen zijn aparte stappen.

Suite 454/454.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/authorized-fetch.test.js

    r5d0d41d r0bafe9e  
    6666});
    6767
    68 test('mislukt ondertekend ophalen, dan volgt de onbetekende poging alsnog', async () => {
    69   // Niet elke 401 komt van secure mode, en een instance die geen handtekening
    70   // verwacht mag er niet door stukgaan. OPEN_ACTOR antwoordt op allebei, dus we
    71   // meten dat er ECHT twee pogingen zijn wanneer de eerste niets oplevert.
     68test('een OPEN instance wordt NIET ondertekend opgehaald', () => {
     69  // De veiligheidskant van shaer-afq: verifyRequest haalt de keyId-URL op
     70  // voordat er iets geverifieerd is, en die URL komt uit een header die iedereen
     71  // mag sturen. Tekenden we standaard, dan kan een vreemde ons een ondertekend
     72  // verzoek naar een adres van zijn keuze laten sturen, met onze identiteit
     73  // eronder. Onbetekend eerst dus, en alleen tekenen als het anders niet lukt.
    7274  verzoeken = [];
     75  return AP.fetchActor(OPEN_ACTOR, { asSlug: 'me' }).then((actor) => {
     76    assert.ok(actor);
     77    assert.equal(verzoeken.length, 1, 'één poging, geen tweede');
     78    assert.equal(verzoeken[0].ondertekend, false, 'en die was onbetekend');
     79  });
     80});
     81
     82test('een document zonder sleutel telt als mislukt en leidt tot een ondertekende poging', async () => {
     83  // Sommige instances serveren onbetekend wel iets, maar zonder publicKey. Voor
     84  // een verificatie hebben we daar niets aan.
     85  const KAAL = 'https://203.0.113.50/users/kaal';
    7386  const stubOrig = globalThis.fetch;
    74   let eerste = true;
    7587  globalThis.fetch = async (url, opts = {}) => {
    7688    const ondertekend = !!(opts.headers && (opts.headers.Signature || opts.headers.signature));
    77     if (String(url) === OPEN_ACTOR && ondertekend && eerste) { eerste = false; return new Response('nee', { status: 500 }); }
     89    if (String(url) === KAAL) {
     90      verzoeken.push({ url: String(url), ondertekend });
     91      const body = ondertekend
     92        ? { id: KAAL, type: 'Person', publicKey: { id: `${KAAL}#k`, owner: KAAL, publicKeyPem: 'x' } }
     93        : { id: KAAL, type: 'Person' };   // kaal: geen sleutel
     94      return new Response(JSON.stringify(body), { status: 200, headers: { 'content-type': 'application/activity+json' } });
     95    }
    7896    return stubOrig(url, opts);
    7997  };
    80   const actor = await AP.fetchActor(OPEN_ACTOR, { asSlug: 'me' });
     98  verzoeken = [];
     99  const actor = await AP.fetchActor(KAAL, { asSlug: 'me' });
    81100  globalThis.fetch = stubOrig;
    82   assert.ok(actor, 'de terugval hoort hem alsnog op te halen');
     101  assert.ok(actor.publicKey && actor.publicKey.publicKeyPem, 'de ondertekende poging levert de sleutel');
     102  assert.deepEqual(verzoeken.map((v) => v.ondertekend), [false, true], 'eerst onbetekend, daarna pas ondertekend');
    83103});
    84104
Note: See TracChangeset for help on using the changeset viewer.