Changeset aae5881 in Klonkt for test/thread.test.js


Ignore:
Timestamp:
08/10/2026 08:14:13 AM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
86ec01b
Parents:
75f2897
Message:

De thread-melding wijst nu naar de juiste partij

Bart opende een post van boiert.eu en las "Replies could not be loaded from
your server" terwijl onze server het prima deed: de BRON weigerde. Het was een
friends-only post van een account dat hij 's ochtends nog volgde en nu niet
meer, en Klonkt geeft een niet-publieke note alleen aan followers -- boiert
weigerde dus terecht, met 404, ook op het ondertekende verzoek.

signedGetJson slikte die status ("if (!r.ok) return null"), dus getThread wist
niet WAAROM het misging en de route kon het niet zeggen. Nu geeft hij de status
door aan wie erom vraagt, en getThread draagt hem als sourceStatus.

De route splitst daarop: 401/403/404/410 is een besluit van die server (niet
gedeeld, of weg) en blijft 404 'not shared by source'; al het andere, inclusief
een status die we niet eens kregen, wordt 502 'source unreachable'. Zonder dat
onderscheid vervang je een verkeerde schuldige door een andere gok.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/thread.test.js

    r75f2897 raae5881  
    193193  assert.ok(!na.attributedTo.tag, 'ook niet in de byline');
    194194});
     195
     196// ── Wiens schuld is het? ─────────────────────────────────────────────
     197//
     198// "Replies could not be loaded from your server" wees naar de verkeerde
     199// partij: onze server deed het prima en de BRON weigerde. Een weigering
     200// (401/403/404/410 -- niet gedeeld, of weg) is iets anders dan een storing, en
     201// alleen de server weet welke van de twee het was.
     202test('een weigering van de bron is 404, een storing is 502', async (t) => {
     203  const crypto = await import('crypto');
     204  const express = (await import('express')).default;
     205  const routes = (await import('../src/routes/activitypub.js')).default;
     206
     207  const bearer = 'test-token-' + 'd'.repeat(24);
     208  db.prepare('INSERT INTO oauth_tokens (token_hash, client_id, user_id, site_slug, scope) VALUES (?,?,?,?,?)')
     209    .run(crypto.createHash('sha256').update(bearer).digest('base64url'), 'c', 'u1', 'kind', 'read write');
     210
     211  const app = express();
     212  app.use(routes);
     213  const server = app.listen(0);
     214  t.after(() => server.close());
     215  await new Promise((r) => server.once('listening', r));
     216
     217  const vorige = globalThis.fetch;
     218  t.after(() => { globalThis.fetch = vorige; });
     219  const vraag = async (uri) => {
     220    const r = await echteFetch(
     221      `http://127.0.0.1:${server.address().port}/ap/users/kind/thread?object=${encodeURIComponent(uri)}`,
     222      { headers: { Authorization: `Bearer ${bearer}` } });
     223    return { status: r.status, body: await r.json() };
     224  };
     225
     226  // De bron zegt nee -- precies wat boiert.eu doet met een friends-only post
     227  // voor iemand die de auteur niet (meer) volgt.
     228  const DICHT = 'https://203.0.113.50/notes/dicht';
     229  globalThis.fetch = async () => new Response('nope', { status: 404 });
     230  const nee = await vraag(DICHT);
     231  assert.equal(nee.status, 404);
     232  assert.equal(nee.body.error, 'not shared by source');
     233  assert.equal(nee.body.sourceStatus, 404);
     234
     235  // De bron ligt eruit. Dezelfde lege uitkomst, een andere waarheid.
     236  const STUK = 'https://203.0.113.51/notes/stuk';
     237  globalThis.fetch = async () => new Response('boem', { status: 500 });
     238  const stuk = await vraag(STUK);
     239  assert.equal(stuk.status, 502);
     240  assert.equal(stuk.body.error, 'source unreachable');
     241});
Note: See TracChangeset for help on using the changeset viewer.