mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
always run custom policy
This commit is contained in:
parent
3d1ece7ec8
commit
aede53e9a9
7 changed files with 49 additions and 71 deletions
8
deno.lock
generated
8
deno.lock
generated
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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');
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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')],
|
||||||
]),
|
]),
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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,40 +43,47 @@ 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) {
|
||||||
const registry = new PolicyRegistry({ store, antiDuplicationPolicyStore: await Deno.openKv() });
|
if (e instanceof Error && e.message.includes('Module not found')) {
|
||||||
const policies: NPolicy[] = [];
|
logi({
|
||||||
const event = await store
|
level: 'info',
|
||||||
.query([{ kinds: [11984], authors: [await conf.signer.getPublicKey()] }])
|
ns: 'ditto.system.policy',
|
||||||
.then((results) => results[0]);
|
msg: 'Custom policy not found <https://docs.soapbox.pub/ditto/policies/>',
|
||||||
|
path: null,
|
||||||
const spec: PolicySpec = event ? JSON.parse(event.content) : DEFAULT_POLICY_SPEC;
|
});
|
||||||
|
|
||||||
for (const item of spec.policies) {
|
|
||||||
const policy = registry.available[item.name];
|
|
||||||
if (!policy) continue;
|
|
||||||
try {
|
|
||||||
policies.push(policy.instantiate(item.params || {}));
|
|
||||||
} catch (e) {
|
|
||||||
logi({
|
|
||||||
level: 'error',
|
|
||||||
ns: 'ditto.system.policy.worker',
|
|
||||||
msg: `Error instantiating policy ${item.name} with params \`${JSON.stringify(item.params)}\`: ${e}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.policy = new PipePolicy(policies);
|
|
||||||
}
|
}
|
||||||
|
const registry = new PolicyRegistry({ store, antiDuplicationPolicyStore: await Deno.openKv() });
|
||||||
|
const event = await store
|
||||||
|
.query([{ kinds: [11984], authors: [await conf.signer.getPublicKey()] }])
|
||||||
|
.then((results) => results[0]);
|
||||||
|
|
||||||
|
const spec: PolicySpec = event ? JSON.parse(event.content) : DEFAULT_POLICY_SPEC;
|
||||||
|
|
||||||
|
for (const item of spec.policies) {
|
||||||
|
const policy = registry.available[item.name];
|
||||||
|
if (!policy) continue;
|
||||||
|
try {
|
||||||
|
policies.push(policy.instantiate(item.params || {}));
|
||||||
|
} catch (e) {
|
||||||
|
logi({
|
||||||
|
level: 'error',
|
||||||
|
ns: 'ditto.system.policy.worker',
|
||||||
|
msg: `Error instantiating policy ${item.name} with params \`${JSON.stringify(item.params)}\`: ${e}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.policy = new PipePolicy(policies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue