always run custom policy

This commit is contained in:
Siddharth Singh 2025-04-12 03:04:20 +05:30
parent 3d1ece7ec8
commit aede53e9a9
No known key found for this signature in database
7 changed files with 49 additions and 71 deletions

8
deno.lock generated
View file

@ -7,6 +7,7 @@
"jsr:@denosaurs/plug@1.0.3": "1.0.3", "jsr:@denosaurs/plug@1.0.3": "1.0.3",
"jsr:@esroyo/scoped-performance@^3.1.0": "3.1.0", "jsr:@esroyo/scoped-performance@^3.1.0": "3.1.0",
"jsr:@gfx/canvas-wasm@~0.4.2": "0.4.2", "jsr:@gfx/canvas-wasm@~0.4.2": "0.4.2",
"jsr:@gleasonator/policy@*": "0.9.0",
"jsr:@hono/hono@^4.4.6": "4.7.5", "jsr:@hono/hono@^4.4.6": "4.7.5",
"jsr:@negrel/http-ece@0.6.0": "0.6.0", "jsr:@negrel/http-ece@0.6.0": "0.6.0",
"jsr:@negrel/webpush@0.3": "0.3.0", "jsr:@negrel/webpush@0.3": "0.3.0",
@ -133,6 +134,13 @@
"jsr:@std/encoding@1.0.5" "jsr:@std/encoding@1.0.5"
] ]
}, },
"@gleasonator/policy@0.9.0": {
"integrity": "483f87c3a18fb39f795495d3388453193f1115ab7e130981121f7828ce6b51bb",
"dependencies": [
"jsr:@nostrify/nostrify@0.36",
"jsr:@nostrify/policies"
]
},
"@hono/hono@4.7.5": { "@hono/hono@4.7.5": {
"integrity": "36a7e1b3db8a58e5dc2bd36a76be53346f0966e04c24c635c4d6f58875575b0a" "integrity": "36a7e1b3db8a58e5dc2bd36a76be53346f0966e04c24c635c4d6f58875575b0a"
}, },

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(['porn']).call(event); return new HashtagPolicy(['other-blocked-tag']).call(event);
} }
info?: NostrRelayInfo | undefined; info?: NostrRelayInfo | undefined;
} }

View file

@ -368,10 +368,6 @@ export class DittoConf {
return this.env.get('DITTO_POLICY') || path.join(this.dataDir, 'policy.ts'); return this.env.get('DITTO_POLICY') || path.join(this.dataDir, 'policy.ts');
} }
get policyMode(): 'script' | 'event' {
return this.env.get('DITTO_CUSTOM_POLICY') ? 'script' : 'event';
}
/** Absolute path to the data directory used by Ditto. */ /** Absolute path to the data directory used by Ditto. */
get dataDir(): string { get dataDir(): string {
return this.env.get('DITTO_DATA_DIR') || path.join(Deno.cwd(), 'data'); return this.env.get('DITTO_DATA_DIR') || path.join(Deno.cwd(), 'data');

View file

@ -26,10 +26,10 @@ export const adminCurrentPolicyController: AppController = async (c) => {
kinds: [11984], kinds: [11984],
}]).then((events) => events[0]); }]).then((events) => events[0]);
if (current) return c.json({ mode: conf.policyMode, spec: JSON.parse(current.content) }); if (current) return c.json({ spec: JSON.parse(current.content) });
await relay.event(await createPolicyEvent(conf, DEFAULT_POLICY_SPEC)); await relay.event(await createPolicyEvent(conf, DEFAULT_POLICY_SPEC));
return c.json({ mode: conf.policyMode, spec: DEFAULT_POLICY_SPEC }); return c.json({ spec: DEFAULT_POLICY_SPEC });
}; };
const PolicySpecSchema = z.object({ const PolicySpecSchema = z.object({
@ -41,13 +41,6 @@ const PolicySpecSchema = z.object({
export const adminUpdatePolicyController: AppController = async (c) => { export const adminUpdatePolicyController: AppController = async (c) => {
const { relay, conf } = c.var; const { relay, conf } = c.var;
if (conf.policyMode === 'script') {
return c.json({
error:
"The Ditto policy mode is set to 'script'. You will not be able to use the Policy UI until you change it to 'event'.",
});
}
try { try {
const req = await c.req.json(); const req = await c.req.json();
const parsed = PolicySpecSchema.parse(req); const parsed = PolicySpecSchema.parse(req);

View file

@ -9,8 +9,8 @@ const blocked = {
id: '19afd70437944671e7f5a02b29221ad444ef7cf60113a5731667e272e59a3979', id: '19afd70437944671e7f5a02b29221ad444ef7cf60113a5731667e272e59a3979',
pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
kind: 1, kind: 1,
tags: [['t', 'porn']], tags: [['t', 'porn'], ['t', 'other-blocked-tag']],
content: 'this is a test of the policy system #porn', content: 'this is a test of the policy system',
sig: sig:
'1d73a7480cfd737b89dc1e0e7175dff67119915f31d24a279a45d56622f4b991b01e431d07b693ee6cd652f3f27274d9e203ee43ae44af7e70ce8647e5326196', '1d73a7480cfd737b89dc1e0e7175dff67119915f31d24a279a45d56622f4b991b01e431d07b693ee6cd652f3f27274d9e203ee43ae44af7e70ce8647e5326196',
created_at: 1743685015, created_at: 1743685015,
@ -20,7 +20,6 @@ Deno.test('PolicyWorker with script policy', async () => {
const conf = new DittoConf( const conf = new DittoConf(
new Map([ new Map([
['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())], ['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())],
['DITTO_CUSTOM_POLICY', '1'],
['DATABASE_URL', Deno.env.get('DATABASE_URL')], ['DATABASE_URL', Deno.env.get('DATABASE_URL')],
['DITTO_POLICY', join(Deno.cwd(), 'fixtures', 'policy.ts')], ['DITTO_POLICY', join(Deno.cwd(), 'fixtures', 'policy.ts')],
]), ]),

View file

@ -53,28 +53,15 @@ export class PolicyWorker implements NPolicy {
path: conf.policy, path: conf.policy,
databaseUrl: conf.databaseUrl, databaseUrl: conf.databaseUrl,
pubkey: await conf.signer.getPublicKey(), pubkey: await conf.signer.getPublicKey(),
mode: conf.policyMode,
}); });
logi({ logi({
level: 'info', level: 'info',
ns: 'ditto.system.policy', ns: 'ditto.system.policy',
msg: `Using ${conf.policyMode === 'script' ? 'custom' : 'event'} policy`, msg: `Initialising custom policy`,
path: conf.policyMode === 'script' ? conf.policy : undefined, path: conf.policy,
enabled: true, enabled: true,
}); });
} catch (e) { } catch (e) {
if (e instanceof Error && e.message.includes('Module not found')) {
logi({
level: 'info',
ns: 'ditto.system.policy',
msg: 'Custom policy not found <https://docs.soapbox.pub/ditto/policies/>',
path: null,
enabled: false,
});
this.enabled = false;
return;
}
if (e instanceof Error && e.message.includes('PGlite is not supported in worker threads')) { if (e instanceof Error && e.message.includes('PGlite is not supported in worker threads')) {
logi({ logi({
level: 'warn', level: 'warn',

View file

@ -13,26 +13,14 @@ import { logi } from '@soapbox/logi';
// @ts-ignore Don't try to access the env from this worker. // @ts-ignore Don't try to access the env from this worker.
Deno.env = new Map<string, string>(); Deno.env = new Map<string, string>();
interface PolicyInitCommon { interface PolicyInit {
/** Database URL to connect to. */ /** Database URL to connect to. */
databaseUrl: string; databaseUrl: string;
/** Admin pubkey to use for DittoPgStore checks. */ /** Admin pubkey to use for DittoPgStore checks. */
pubkey: string; pubkey: string;
mode: 'script' | 'event';
}
interface ScriptPolicyInit {
/** Path to the policy module (https, jsr, file, etc) */
path: string; path: string;
mode: 'script';
} }
interface EventPolicyInit {
mode: 'event';
}
type PolicyInit = PolicyInitCommon & (ScriptPolicyInit | EventPolicyInit);
export class CustomPolicy implements NPolicy { export class CustomPolicy implements NPolicy {
private policy: NPolicy = new ReadOnlyPolicy(); private policy: NPolicy = new ReadOnlyPolicy();
@ -55,18 +43,26 @@ export class CustomPolicy implements NPolicy {
}, },
}); });
const policies: NPolicy[] = [];
const store = new DittoPgStore({ const store = new DittoPgStore({
db, db,
conf, conf,
timeout: 5_000, timeout: 5_000,
}); });
try {
if (opts.mode === 'script') {
const Policy = (await import(opts.path)).default; const Policy = (await import(opts.path)).default;
this.policy = new Policy({ db, store, pubkey }); policies.push(new Policy({ db, store, pubkey }));
} else { } catch (e) {
if (e instanceof Error && e.message.includes('Module not found')) {
logi({
level: 'info',
ns: 'ditto.system.policy',
msg: 'Custom policy not found <https://docs.soapbox.pub/ditto/policies/>',
path: null,
});
}
}
const registry = new PolicyRegistry({ store, antiDuplicationPolicyStore: await Deno.openKv() }); const registry = new PolicyRegistry({ store, antiDuplicationPolicyStore: await Deno.openKv() });
const policies: NPolicy[] = [];
const event = await store const event = await store
.query([{ kinds: [11984], authors: [await conf.signer.getPublicKey()] }]) .query([{ kinds: [11984], authors: [await conf.signer.getPublicKey()] }])
.then((results) => results[0]); .then((results) => results[0]);
@ -89,7 +85,6 @@ export class CustomPolicy implements NPolicy {
this.policy = new PipePolicy(policies); this.policy = new PipePolicy(policies);
} }
}
} }
Comlink.expose(new CustomPolicy()); Comlink.expose(new CustomPolicy());