Run the custom policy in a worker for security

This commit is contained in:
Alex Gleason 2024-05-15 20:19:49 -05:00
parent 6a1b8b0943
commit 9e9ab40886
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
8 changed files with 53 additions and 7 deletions

View File

@ -1,7 +1,7 @@
FROM denoland/deno:1.43.3 FROM denoland/deno:1.43.3
EXPOSE 4036 EXPOSE 4036
WORKDIR /app WORKDIR /app
RUN mkdir -p data && chown -R deno data RUN mkdir -p data/policy && chown -R deno data
USER deno USER deno
COPY . . COPY . .
RUN deno cache src/server.ts RUN deno cache src/server.ts

1
data/.gitignore vendored
View File

@ -1,2 +1,3 @@
* *
!.gitignore !.gitignore
!/policy

2
data/policy/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -13,7 +13,7 @@
"admin:role": "deno run -A scripts/admin-role.ts", "admin:role": "deno run -A scripts/admin-role.ts",
"stats:recompute": "deno run -A scripts/stats-recompute.ts" "stats:recompute": "deno run -A scripts/stats-recompute.ts"
}, },
"unstable": ["ffi", "kv"], "unstable": ["ffi", "kv", "worker-options"],
"exclude": ["./public"], "exclude": ["./public"],
"imports": { "imports": {
"@/": "./src/", "@/": "./src/",

View File

@ -221,7 +221,7 @@ class Conf {
} }
/** Path to the custom policy module. Must be an absolute path, https:, npm:, or jsr: URI. */ /** Path to the custom policy module. Must be an absolute path, https:, npm:, or jsr: URI. */
static get policy(): string { static get policy(): string {
return Deno.env.get('DITTO_POLICY') || new URL('../data/policy.ts', import.meta.url).toString(); return Deno.env.get('DITTO_POLICY') || new URL('../data/policy.ts', import.meta.url).pathname;
} }
} }

View File

@ -16,6 +16,7 @@ import { Storages } from '@/storages.ts';
import { getTagSet } from '@/tags.ts'; import { getTagSet } from '@/tags.ts';
import { eventAge, nostrDate, nostrNow, parseNip05, Time } from '@/utils.ts'; import { eventAge, nostrDate, nostrNow, parseNip05, Time } from '@/utils.ts';
import { fetchWorker } from '@/workers/fetch.ts'; import { fetchWorker } from '@/workers/fetch.ts';
import { policyWorker } from '@/workers/policy.ts';
import { TrendsWorker } from '@/workers/trends.ts'; import { TrendsWorker } from '@/workers/trends.ts';
import { verifyEventWorker } from '@/workers/verify.ts'; import { verifyEventWorker } from '@/workers/verify.ts';
import { AdminSigner } from '@/signers/AdminSigner.ts'; import { AdminSigner } from '@/signers/AdminSigner.ts';
@ -62,11 +63,11 @@ async function policyFilter(event: NostrEvent): Promise<void> {
]; ];
try { try {
const CustomPolicy = (await import(Conf.policy)).default; await policyWorker.import(Conf.policy);
policies.push(new CustomPolicy()); policies.push(policyWorker);
debug(`Using custom policy: ${Conf.policy}`); debug(`Using custom policy: ${Conf.policy}`);
} catch (e) { } catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND') { if (e.message.includes('Module not found')) {
debug('Custom policy not found <https://docs.soapbox.pub/ditto/policies/>'); debug('Custom policy not found <https://docs.soapbox.pub/ditto/policies/>');
} else { } else {
console.error(`DITTO_POLICY (error importing policy): ${Conf.policy}`, e); console.error(`DITTO_POLICY (error importing policy): ${Conf.policy}`, e);

23
src/workers/policy.ts Normal file
View File

@ -0,0 +1,23 @@
import * as Comlink from 'comlink';
import { Conf } from '@/config.ts';
import type { CustomPolicy } from '@/workers/policy.worker.ts';
const policyDir = new URL('../../data/policy', import.meta.url).pathname;
export const policyWorker = Comlink.wrap<CustomPolicy>(
new Worker(
new URL('./policy.worker.ts', import.meta.url),
{
type: 'module',
deno: {
permissions: {
read: [Conf.policy, policyDir],
write: [policyDir],
net: 'inherit',
env: false,
},
},
},
),
);

View File

@ -0,0 +1,19 @@
import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/nostrify';
import { ReadOnlyPolicy } from '@nostrify/nostrify/policies';
import * as Comlink from 'comlink';
export class CustomPolicy implements NPolicy {
private policy: NPolicy = new ReadOnlyPolicy();
// deno-lint-ignore require-await
async call(event: NostrEvent): Promise<NostrRelayOK> {
return this.policy.call(event);
}
async import(path: string): Promise<void> {
const Policy = (await import(path)).default;
this.policy = new Policy();
}
}
Comlink.expose(new CustomPolicy());