| 1 | // C2S Block / Undo(Block): Shaer "in Orbit" is a real server-side block.
|
|---|
| 2 | // The activity lands in ap_blocks (the Block tab) via the same blockTarget
|
|---|
| 3 | // the web UI uses; Undo(Block) releases it.
|
|---|
| 4 | import { test } from 'node:test';
|
|---|
| 5 | import assert from 'node:assert/strict';
|
|---|
| 6 |
|
|---|
| 7 | process.env.DATABASE_PATH = ':memory:';
|
|---|
| 8 | process.env.PUBLIC_BASE_URL = 'https://test.example';
|
|---|
| 9 |
|
|---|
| 10 | const dbMod = await import('../src/config/database.js');
|
|---|
| 11 | const db = dbMod.default;
|
|---|
| 12 | dbMod.initializeDatabase();
|
|---|
| 13 | const AP = (await import('../src/services/ActivityPubService.js')).default;
|
|---|
| 14 |
|
|---|
| 15 | db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)').run('u1', 'u1', 'u1@test', 'x', 'god');
|
|---|
| 16 | db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,?)').run('s1', 'me', 'Me', 'u1', 1);
|
|---|
| 17 | const site = db.prepare('SELECT * FROM sites WHERE id = ?').get('s1');
|
|---|
| 18 | const user = { id: 'u1', username: 'u1' };
|
|---|
| 19 |
|
|---|
| 20 | const BULLY = 'https://r.test/u/bully';
|
|---|
| 21 |
|
|---|
| 22 | test('C2S Block lands in ap_blocks (the Block tab)', async () => {
|
|---|
| 23 | const out = await AP.ingestOutboxActivity(site, user, { type: 'Block', object: BULLY });
|
|---|
| 24 | assert.equal(out.status, 202);
|
|---|
| 25 | assert.equal(out.url, BULLY);
|
|---|
| 26 | const rows = AP.listBlocks('me');
|
|---|
| 27 | assert.equal(rows.length, 1);
|
|---|
| 28 | assert.equal(rows[0].target, BULLY);
|
|---|
| 29 | assert.equal(rows[0].kind, 'actor');
|
|---|
| 30 | });
|
|---|
| 31 |
|
|---|
| 32 | test('C2S Undo(Block) releases it again', async () => {
|
|---|
| 33 | const out = await AP.ingestOutboxActivity(site, user, {
|
|---|
| 34 | type: 'Undo',
|
|---|
| 35 | object: { type: 'Block', object: BULLY },
|
|---|
| 36 | });
|
|---|
| 37 | assert.equal(out.status, 202);
|
|---|
| 38 | assert.equal(AP.listBlocks('me').length, 0);
|
|---|
| 39 | });
|
|---|
| 40 |
|
|---|
| 41 | test('Block without an object is a clean 400', async () => {
|
|---|
| 42 | const out = await AP.ingestOutboxActivity(site, user, { type: 'Block' });
|
|---|
| 43 | assert.equal(out.status, 400);
|
|---|
| 44 | });
|
|---|
| 45 |
|
|---|
| 46 | test('the actor advertises the blocked collection (AP 5.6)', () => {
|
|---|
| 47 | site.primary_slug = 'me';
|
|---|
| 48 | const actor = AP.buildActor('https://test.example', site);
|
|---|
| 49 | assert.equal(actor.blocked, 'https://test.example/ap/users/me/blocked');
|
|---|
| 50 | });
|
|---|
| 51 |
|
|---|
| 52 | test('actor-kind blocks form the collection items; domain blocks stay out', async () => {
|
|---|
| 53 | await AP.ingestOutboxActivity(site, user, { type: 'Block', object: BULLY });
|
|---|
| 54 | await AP.blockTarget(site, 'nare-server.example'); // domain block
|
|---|
| 55 | const items = AP.listBlocks('me').filter((b) => b.kind === 'actor').map((b) => b.target);
|
|---|
| 56 | assert.deepEqual(items, [BULLY]);
|
|---|
| 57 | });
|
|---|