Make Pleroma config more resilient to corrupted events

This commit is contained in:
Alex Gleason 2024-02-22 11:39:11 -06:00
parent 40c7f8b093
commit c24e1f42a6
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 22 additions and 43 deletions

View File

@ -1,26 +1,14 @@
import { type AppController } from '@/app.ts'; import { type AppController } from '@/app.ts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { z } from '@/deps.ts'; import { z } from '@/deps.ts';
import { configSchema, elixirTupleSchema } from '@/schemas/pleroma-api.ts'; import { configSchema, elixirTupleSchema, type PleromaConfig } from '@/schemas/pleroma-api.ts';
import { AdminSigner } from '@/signers/AdminSigner.ts'; import { AdminSigner } from '@/signers/AdminSigner.ts';
import { eventsDB } from '@/storages.ts'; import { eventsDB } from '@/storages.ts';
import { createAdminEvent } from '@/utils/api.ts'; import { createAdminEvent } from '@/utils/api.ts';
import { jsonSchema } from '@/schema.ts'; import { jsonSchema } from '@/schema.ts';
const frontendConfigController: AppController = async (c) => { const frontendConfigController: AppController = async (c) => {
const { signal } = c.req.raw; const configs = await getConfigs(c.req.raw.signal);
const [event] = await eventsDB.query([{
kinds: [30078],
authors: [Conf.pubkey],
'#d': ['pub.ditto.pleroma.config'],
limit: 1,
}], { signal });
const configs = jsonSchema.pipe(z.array(configSchema)).catch([]).parse(
event?.content ? await new AdminSigner().nip44.decrypt(Conf.pubkey, event.content) : '',
);
const frontendConfig = configs.find(({ group, key }) => group === ':pleroma' && key === ':frontend_configurations'); const frontendConfig = configs.find(({ group, key }) => group === ':pleroma' && key === ':frontend_configurations');
if (frontendConfig) { if (frontendConfig) {
@ -36,39 +24,15 @@ const frontendConfigController: AppController = async (c) => {
}; };
const configController: AppController = async (c) => { const configController: AppController = async (c) => {
const { pubkey } = Conf; const configs = await getConfigs(c.req.raw.signal);
const { signal } = c.req.raw;
const [event] = await eventsDB.query([{
kinds: [30078],
authors: [pubkey],
'#d': ['pub.ditto.pleroma.config'],
limit: 1,
}], { signal });
const configs = jsonSchema.pipe(z.array(configSchema)).catch([]).parse(
event?.content ? await new AdminSigner().nip44.decrypt(pubkey, event.content) : '',
);
return c.json({ configs, need_reboot: false }); return c.json({ configs, need_reboot: false });
}; };
/** Pleroma admin config controller. */ /** Pleroma admin config controller. */
const updateConfigController: AppController = async (c) => { const updateConfigController: AppController = async (c) => {
const { pubkey } = Conf; const { pubkey } = Conf;
const { signal } = c.req.raw;
const [event] = await eventsDB.query([{
kinds: [30078],
authors: [pubkey],
'#d': ['pub.ditto.pleroma.config'],
limit: 1,
}], { signal });
const configs = jsonSchema.pipe(z.array(configSchema)).catch([]).parse(
event?.content ? await await new AdminSigner().nip44.decrypt(pubkey, event.content) : '',
);
const configs = await getConfigs(c.req.raw.signal);
const { configs: newConfigs } = z.object({ configs: z.array(configSchema) }).parse(await c.req.json()); const { configs: newConfigs } = z.object({ configs: z.array(configSchema) }).parse(await c.req.json());
for (const { group, key, value } of newConfigs) { for (const { group, key, value } of newConfigs) {
@ -98,4 +62,19 @@ const pleromaAdminDeleteStatusController: AppController = async (c) => {
return c.json({}); return c.json({});
}; };
async function getConfigs(signal: AbortSignal): Promise<PleromaConfig[]> {
const { pubkey } = Conf;
const [event] = await eventsDB.query([{
kinds: [30078],
authors: [pubkey],
'#d': ['pub.ditto.pleroma.config'],
limit: 1,
}], { signal });
return jsonSchema.pipe(configSchema.array()).catch([]).parse(
await new AdminSigner().nip44.decrypt(Conf.pubkey, event.content).catch(() => ''),
);
}
export { configController, frontendConfigController, pleromaAdminDeleteStatusController, updateConfigController }; export { configController, frontendConfigController, pleromaAdminDeleteStatusController, updateConfigController };

View File

@ -13,7 +13,7 @@ interface ElixirTuple {
tuple: [string, ElixirValue]; tuple: [string, ElixirValue];
} }
interface Config { interface PleromaConfig {
group: string; group: string;
key: string; key: string;
value: ElixirValue; value: ElixirValue;
@ -37,10 +37,10 @@ const elixirValueSchema: z.ZodType<ElixirValue> = z.union([
elixirTupleSchema, elixirTupleSchema,
]); ]);
const configSchema: z.ZodType<Config> = z.object({ const configSchema: z.ZodType<PleromaConfig> = z.object({
group: z.string(), group: z.string(),
key: z.string(), key: z.string(),
value: elixirValueSchema, value: elixirValueSchema,
}); });
export { type Config, configSchema, type ElixirTuple, elixirTupleSchema, type ElixirValue }; export { configSchema, type ElixirTuple, elixirTupleSchema, type ElixirValue, type PleromaConfig };