diff --git a/src/controllers/api/pleroma.ts b/src/controllers/api/pleroma.ts index 98e64b51..d9289df1 100644 --- a/src/controllers/api/pleroma.ts +++ b/src/controllers/api/pleroma.ts @@ -1,4 +1,3 @@ -import { NSchema as n, NStore } from '@nostrify/nostrify'; import { z } from 'zod'; import { type AppController } from '@/app.ts'; @@ -8,11 +7,11 @@ import { AdminSigner } from '@/signers/AdminSigner.ts'; import { Storages } from '@/storages.ts'; import { createAdminEvent, updateAdminEvent, updateUser } from '@/utils/api.ts'; import { lookupPubkey } from '@/utils/lookup.ts'; -import { PleromaConfigDB } from '@/utils/PleromaConfigDB.ts'; +import { getPleromaConfigs } from '@/utils/pleroma.ts'; const frontendConfigController: AppController = async (c) => { const store = await Storages.db(); - const configDB = await getConfigs(store, c.req.raw.signal); + const configDB = await getPleromaConfigs(store, c.req.raw.signal); const frontendConfig = configDB.get(':pleroma', ':frontend_configurations'); if (frontendConfig) { @@ -29,7 +28,7 @@ const frontendConfigController: AppController = async (c) => { const configController: AppController = async (c) => { const store = await Storages.db(); - const configs = await getConfigs(store, c.req.raw.signal); + const configs = await getPleromaConfigs(store, c.req.raw.signal); return c.json({ configs, need_reboot: false }); }; @@ -38,7 +37,7 @@ const updateConfigController: AppController = async (c) => { const { pubkey } = Conf; const store = await Storages.db(); - const configs = await getConfigs(store, c.req.raw.signal); + const configs = await getPleromaConfigs(store, c.req.raw.signal); const { configs: newConfigs } = z.object({ configs: z.array(configSchema) }).parse(await c.req.json()); configs.merge(newConfigs); @@ -64,29 +63,6 @@ const pleromaAdminDeleteStatusController: AppController = async (c) => { return c.json({}); }; -async function getConfigs(store: NStore, signal: AbortSignal): Promise { - const { pubkey } = Conf; - - const [event] = await store.query([{ - kinds: [30078], - authors: [pubkey], - '#d': ['pub.ditto.pleroma.config'], - limit: 1, - }], { signal }); - - if (!event) { - return new PleromaConfigDB([]); - } - - try { - const decrypted = await new AdminSigner().nip44.decrypt(Conf.pubkey, event.content); - const configs = n.json().pipe(configSchema.array()).catch([]).parse(decrypted); - return new PleromaConfigDB(configs); - } catch (_e) { - return new PleromaConfigDB([]); - } -} - const pleromaAdminTagSchema = z.object({ nicknames: z.string().array(), tags: z.string().array(), diff --git a/src/middleware/cspMiddleware.ts b/src/middleware/cspMiddleware.ts index 00c4ecc3..2701e214 100644 --- a/src/middleware/cspMiddleware.ts +++ b/src/middleware/cspMiddleware.ts @@ -1,15 +1,30 @@ import { AppMiddleware } from '@/app.ts'; import { Conf } from '@/config.ts'; +import { PleromaConfigDB } from '@/utils/PleromaConfigDB.ts'; +import { Storages } from '@/storages.ts'; +import { getPleromaConfigs } from '@/utils/pleroma.ts'; + +let configDBCache: Promise | undefined; export const cspMiddleware = (): AppMiddleware => { return async (c, next) => { + const store = await Storages.db(); + + if (!configDBCache) { + configDBCache = getPleromaConfigs(store); + } + const { host, protocol, origin } = Conf.url; const wsProtocol = protocol === 'http:' ? 'ws:' : 'wss:'; + const configDB = await configDBCache; + const sentryDsn = configDB.getIn(':pleroma', ':frontend_configurations', ':soapbox_fe', 'sentryDsn'); const policies = [ 'upgrade-insecure-requests', `script-src 'self'`, - `connect-src 'self' blob: ${origin} ${wsProtocol}//${host}`, + `connect-src 'self' blob: ${origin} ${wsProtocol}//${host}` + typeof sentryDsn === 'string' + ? ` ${sentryDsn}` + : '', `media-src 'self' https:`, `img-src 'self' data: blob: https:`, `default-src 'none'`, diff --git a/src/utils/pleroma.ts b/src/utils/pleroma.ts new file mode 100644 index 00000000..05c35b7c --- /dev/null +++ b/src/utils/pleroma.ts @@ -0,0 +1,29 @@ +import { NSchema as n, NStore } from '@nostrify/nostrify'; + +import { Conf } from '@/config.ts'; +import { configSchema } from '@/schemas/pleroma-api.ts'; +import { AdminSigner } from '@/signers/AdminSigner.ts'; +import { PleromaConfigDB } from '@/utils/PleromaConfigDB.ts'; + +export async function getPleromaConfigs(store: NStore, signal?: AbortSignal): Promise { + const { pubkey } = Conf; + + const [event] = await store.query([{ + kinds: [30078], + authors: [pubkey], + '#d': ['pub.ditto.pleroma.config'], + limit: 1, + }], { signal }); + + if (!event) { + return new PleromaConfigDB([]); + } + + try { + const decrypted = await new AdminSigner().nip44.decrypt(Conf.pubkey, event.content); + const configs = n.json().pipe(configSchema.array()).catch([]).parse(decrypted); + return new PleromaConfigDB(configs); + } catch (_e) { + return new PleromaConfigDB([]); + } +}