source: Klonkt/test/block-federeert.test.js@ e311202

main
Last change on this file since e311202 was e311202, checked in by Robin <roboburr@…>, 3 weeks ago

A block now leaves the house: Block out, Undo(Block) back

Blocking was purely local — row in ap_blocks, purge the cached content,
drop the follower — and the other side never heard about it. The hub
kept the channel and every post, because nothing told it and its
unsigned crawl kept reading the public outbox (seen on dev.klonkt.com,
21-8).

Now blocking delivers a Block to the blocked actor's inbox and
unblocking an Undo(Block), so the way back stays open. Delivery can
never hold up the block itself: the row is written first and a
failed delivery is swallowed. Domain blocks send nothing — no inbox to
address.

Second door: a signed reader we block gets the same 404 on /ap/notes/:id
that a stranger gets, matching what the outbox already did. Unsigned
callers stay anonymous to us and keep the public view; that is what the
Block delivery is for.

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

  • Property mode set to 100644
File size: 3.6 KB
Line 
1// Een blokkade wordt ook VERSTUURD (Robin, 21-8).
2//
3// Aanleiding: dev.klonkt.com blokkeerde de hub, en op de hub bleef het kanaal
4// met alle berichten gewoon staan. De blokkade bleef namelijk binnenshuis --
5// rij in ap_blocks, inhoud opruimen, volger eruit -- en de andere kant hoorde
6// er nooit van. Nu gaat er een Block naar de inbox van wie je blokkeert, en
7// bij opheffen een Undo(Block), zodat de weg terug openligt.
8//
9// De fetch is gestubd: het gaat om WAT er de deur uit gaat, niet om echte HTTP.
10import { test, after } from 'node:test';
11import assert from 'node:assert/strict';
12
13process.env.DATABASE_PATH = ':memory:';
14process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
15
16const dbMod = await import('../src/config/database.js');
17const db = dbMod.default;
18dbMod.initializeDatabase();
19const AP = (await import('../src/services/ActivityPubService.js')).default;
20
21db.prepare("INSERT INTO users (id, username, email, password_hash, role) VALUES ('u1','u1','u1@t','x','god')").run();
22db.prepare("INSERT INTO sites (id, slug, title, owner_id, is_public) VALUES ('s1','dev','Dev','u1',1)").run();
23const site = () => db.prepare("SELECT * FROM sites WHERE id = 's1'").get();
24
25// IP-literal: safeFetch slaat de DNS-lookup over en de stub vangt de rest.
26const DOEL = 'https://203.0.113.80/ap/actor';
27const bezorgd = [];
28const echteFetch = globalThis.fetch;
29globalThis.fetch = async (url, opts = {}) => {
30 const u = String(url);
31 if (opts.method === 'POST') {
32 try { bezorgd.push({ naar: u, activiteit: JSON.parse(opts.body) }); } catch { /* niet-JSON telt niet mee */ }
33 return new Response('', { status: 202 });
34 }
35 return new Response(JSON.stringify({
36 id: DOEL, type: 'Application', preferredUsername: 'hub', inbox: `${DOEL}/inbox`,
37 }), { status: 200, headers: { 'content-type': 'application/activity+json' } });
38};
39after(() => { globalThis.fetch = echteFetch; });
40
41test('blokkeren stuurt een Block naar de geblokkeerde', async () => {
42 bezorgd.length = 0;
43 const r = await AP.blockTarget(site(), DOEL);
44 assert.equal(r.ok, true);
45 assert.equal(db.prepare('SELECT count(*) c FROM ap_blocks WHERE target = ?').get(DOEL).c, 1, 'de blokkade staat vast');
46 const blok = bezorgd.find((b) => b.activiteit.type === 'Block');
47 assert.ok(blok, 'er is een Block bezorgd');
48 assert.equal(blok.naar, `${DOEL}/inbox`);
49 assert.equal(blok.activiteit.object, DOEL);
50 assert.equal(blok.activiteit.actor, 'https://klonkt.test/ap/users/dev');
51});
52
53test('opheffen stuurt een Undo(Block), anders komt de ander nooit terug', async () => {
54 bezorgd.length = 0;
55 await AP.unblock(site(), DOEL);
56 assert.equal(db.prepare('SELECT count(*) c FROM ap_blocks WHERE target = ?').get(DOEL).c, 0, 'de blokkade is weg');
57 const undo = bezorgd.find((b) => b.activiteit.type === 'Undo');
58 assert.ok(undo, 'er is een Undo bezorgd');
59 assert.equal(undo.activiteit.object.type, 'Block');
60 assert.equal(undo.activiteit.object.object, DOEL);
61});
62
63test('een DOMEIN-blokkade verstuurt niets: daar is geen inbox voor', async () => {
64 bezorgd.length = 0;
65 await AP.blockTarget(site(), 'spam.example');
66 assert.equal(db.prepare("SELECT count(*) c FROM ap_blocks WHERE kind = 'domain'").get().c, 1);
67 assert.equal(bezorgd.length, 0);
68});
69
70test('een onbereikbare tegenpartij houdt de blokkade niet tegen', async () => {
71 const stuk = globalThis.fetch;
72 globalThis.fetch = async () => { throw new Error('down'); };
73 const r = await AP.blockTarget(site(), 'https://203.0.113.99/ap/actor');
74 globalThis.fetch = stuk;
75 assert.equal(r.ok, true, 'de blokkade staat, ook zonder bezorging');
76 assert.equal(db.prepare('SELECT count(*) c FROM ap_blocks WHERE target = ?').get('https://203.0.113.99/ap/actor').c, 1);
77});
Note: See TracBrowser for help on using the repository browser.