Compare commits

..

No commits in common. "b613334312a90af64b1ec2247e3dee545e261db9" and "42f581d350f8131804cd4618311a9c79e3f54093" have entirely different histories.

5 changed files with 31 additions and 97 deletions

View file

@ -3,7 +3,7 @@ import { HashtagPolicy } from '@nostrify/policies';
export default class TestPolicy implements NPolicy { export default class TestPolicy implements NPolicy {
call(event: NostrEvent): Promise<NostrRelayOK> { call(event: NostrEvent): Promise<NostrRelayOK> {
return new HashtagPolicy(['potato']).call(event); return new HashtagPolicy(['other-blocked-tag']).call(event);
} }
info?: NostrRelayInfo | undefined; info?: NostrRelayInfo | undefined;
} }

View file

@ -1,5 +1,5 @@
import { type AppController } from '@/app.ts'; import { type AppController } from '@/app.ts';
import { createPolicyEvent, DEFAULT_POLICY_SPEC } from '@/utils/policies/mod.ts'; import { createPolicyEvent } from '@/utils/policies/mod.ts';
import { policyRegistry } from '@/utils/policies/mod.ts'; import { policyRegistry } from '@/utils/policies/mod.ts';
import { z } from 'zod'; import { z } from 'zod';
@ -27,7 +27,7 @@ export const adminCurrentPolicyController: AppController = async (c) => {
}]).then((events) => events[0]); }]).then((events) => events[0]);
if (current) return c.json({ spec: JSON.parse(current.content) }); if (current) return c.json({ spec: JSON.parse(current.content) });
return c.json({ spec: { policies: DEFAULT_POLICY_SPEC } }); return c.json({ spec: { policies: [] } });
}; };
const PolicySpecSchema = z.object({ const PolicySpecSchema = z.object({

View file

@ -1,103 +1,45 @@
import { DittoConf } from '@ditto/conf'; import { DittoConf } from '@ditto/conf';
import { generateSecretKey, nip19 } from 'nostr-tools'; import { generateSecretKey, nip19 } from 'nostr-tools';
import { PolicyWorker } from '@/workers/policy.ts'; import { PolicyWorker } from '@/workers/policy.ts';
import { assert, assertEquals } from '@std/assert'; import { assertEquals } from '@std/assert/assert-equals';
import { join } from '@std/path'; import { join } from '@std/path';
import { createPolicyEvent } from '../utils/policies/mod.ts';
import { createTestDB } from '../test.ts';
const blocked = { const blocked = {
id: '19afd70437944671e7f5a02b29221ad444ef7cf60113a5731667e272e59a3979', id: '19afd70437944671e7f5a02b29221ad444ef7cf60113a5731667e272e59a3979',
pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
kind: 1, kind: 1,
tags: [['t', 'potato'], ['t', 'tomato']], tags: [['t', 'porn'], ['t', 'other-blocked-tag']],
content: 'this is a test of the policy system', content: 'this is a test of the policy system',
sig: sig:
'1d73a7480cfd737b89dc1e0e7175dff67119915f31d24a279a45d56622f4b991b01e431d07b693ee6cd652f3f27274d9e203ee43ae44af7e70ce8647e5326196', '1d73a7480cfd737b89dc1e0e7175dff67119915f31d24a279a45d56622f4b991b01e431d07b693ee6cd652f3f27274d9e203ee43ae44af7e70ce8647e5326196',
created_at: 1743685015, created_at: 1743685015,
}; };
Deno.test('Tests for policy workers', async (t) => { Deno.test('PolicyWorker with script policy', async () => {
const nsec = nip19.nsecEncode(generateSecretKey()); const conf = new DittoConf(
const env = new Map([ new Map([
['DITTO_NSEC', nsec], ['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())],
['DATABASE_URL', Deno.env.get('DATABASE_URL')], ['DATABASE_URL', Deno.env.get('DATABASE_URL')],
]); ['DITTO_POLICY', join(Deno.cwd(), 'fixtures', 'policy.ts')],
]),
);
await using db = await createTestDB(); const worker = new PolicyWorker(conf);
const [, , ok] = await worker.call(blocked);
async function clearPolicyEvents() { assertEquals(ok, false);
await db.store.remove([{ kinds: [11984] }]); });
}
await clearPolicyEvents(); Deno.test('PolicyWorker with event policy', async () => {
const conf = new DittoConf(
await t.step('No DITTO_POLICY, no event-based policy (default allow)', async () => { new Map([
await clearPolicyEvents(); ['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())],
const conf = new DittoConf(env); ['DATABASE_URL', Deno.env.get('DATABASE_URL')],
]),
const worker = new PolicyWorker(conf); );
const [, , ok] = await worker.call(blocked);
const worker = new PolicyWorker(conf);
assertEquals(ok, true, 'Should not block anything in default config'); const [, , ok] = await worker.call(blocked);
});
assertEquals(ok, false);
// Edge 2: No DITTO_POLICY, valid event-based policy (blocks "tomato")
await t.step('No DITTO_POLICY, valid event-based policy (blocks "tomato")', async () => {
await clearPolicyEvents();
const conf = new DittoConf(env);
await db.store.event(
await createPolicyEvent(conf, {
policies: [
{ 'name': 'HashtagPolicy', 'params': { 'hashtags': ['tomato'] } },
],
}),
);
using worker = new PolicyWorker(conf);
const [, , ok] = await worker.call(blocked);
assert(!ok, 'Event policy should block events with #tomato');
});
// Edge 3: DITTO_POLICY set but policy script is missing (should fallback)
await t.step('DITTO_POLICY set but file is missing (should fallback)', async () => {
await clearPolicyEvents();
const thisEnv = new Map([...env, ['DITTO_POLICY', 'not-a-policy.ts']]);
const conf = new DittoConf(thisEnv);
using worker = new PolicyWorker(conf);
const [, , ok] = await worker.call(blocked);
assertEquals(
ok,
true,
'Missing script policy should fall back to allowing (default policy)',
);
});
await t.step('Both DITTO_POLICY and event policy', async () => {
await clearPolicyEvents();
const policyScriptPath = join(Deno.cwd(), 'fixtures', 'policy.ts');
const thisEnv = new Map([...env, ['DITTO_POLICY', policyScriptPath]]);
const conf = new DittoConf(thisEnv);
await db.store.event(
await createPolicyEvent(conf, {
policies: [
{ 'name': 'HashtagPolicy', 'params': { 'hashtags': ['tomato'] } },
],
}),
);
using worker = new PolicyWorker(conf);
const [, , ok] = await worker.call(blocked);
assert(
!ok,
'Both script and event-based policy are present: event should be blocked if either blocks',
);
});
}); });

View file

@ -86,8 +86,4 @@ export class PolicyWorker implements NPolicy {
throw new Error(`DITTO_POLICY (error importing policy): ${conf.policy}`); throw new Error(`DITTO_POLICY (error importing policy): ${conf.policy}`);
} }
} }
[Symbol.dispose]() {
this.worker.close();
}
} }

View file

@ -85,10 +85,6 @@ export class CustomPolicy implements NPolicy {
this.policy = new PipePolicy(policies); this.policy = new PipePolicy(policies);
} }
close() {
self.close();
}
} }
Comlink.expose(new CustomPolicy()); Comlink.expose(new CustomPolicy());