From ca80a49b82a1009537f988d25d6c743d044042a7 Mon Sep 17 00:00:00 2001 From: Florian Demmer Date: Mon, 24 Jun 2024 18:37:56 +0100 Subject: [PATCH 1/2] stricter parameter meta JSON parsing to enforce a top level JSON object, not just a valid JSON string --- src/actions/instances.ts | 20 ++++++------ src/components/meta/metaEditorModal.tsx | 42 +++++++++++-------------- src/lib/util.ts | 25 ++++++++++++++- src/models/parameter.ts | 13 +++++--- 4 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/actions/instances.ts b/src/actions/instances.ts index 9b197094..26d27b3f 100644 --- a/src/actions/instances.ts +++ b/src/actions/instances.ts @@ -304,18 +304,16 @@ export const clearParameterMidiMappingOnRemote = (id: InstanceStateRecord["id"], const param = instance.parameters.get(paramId); if (!param) return; - const meta = param.getParsedMeta(); - if (typeof meta === "object" && !Array.isArray(meta)) { - delete meta.midi; - const message = { - address: `${param.path}/meta`, - args: [ - { type: "s", value: JSON.stringify(meta) } - ] - }; + const meta = param.getParsedMetaObject(); + delete meta.midi; + const message = { + address: `${param.path}/meta`, + args: [ + { type: "s", value: JSON.stringify(meta) } + ] + }; - oscQueryBridge.sendPacket(writePacket(message)); - } + oscQueryBridge.sendPacket(writePacket(message)); }; export const setInstanceMessagePortMetaOnRemote = (_instance: InstanceStateRecord, port: MessagePortRecord, value: string): AppThunk => diff --git a/src/components/meta/metaEditorModal.tsx b/src/components/meta/metaEditorModal.tsx index f290501e..80cece7a 100644 --- a/src/components/meta/metaEditorModal.tsx +++ b/src/components/meta/metaEditorModal.tsx @@ -4,8 +4,9 @@ import { useIsMobileDevice } from "../../hooks/useIsMobileDevice"; import { faCode, faXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { modals } from "@mantine/modals"; -import { AnyJson } from "../../lib/types"; +import { JsonMap } from "../../lib/types"; import { MetadataScope } from "../../lib/constants"; +import { parseParamMetaJSONString } from "../../lib/util"; export type MetaEditorModalProps = { name: string; @@ -125,13 +126,12 @@ export const MetaEditorModal: FC = memo(function WrappedPa onConfirm: () => { setValue(meta); setHasChanges(false); + try { - if (meta) { - JSON.parse(meta); // ensure valid - } + if (meta) parseParamMetaJSONString(meta); // ensure valid setError(undefined); - } catch (err) { - setError(new Error("Invalid JSON.")); + } catch (err: unknown) { + setError(err instanceof Error ? err : new Error("Invalid JSON format.")); } } }); @@ -139,10 +139,10 @@ export const MetaEditorModal: FC = memo(function WrappedPa setValue(meta); setHasChanges(false); try { - JSON.parse(meta); // ensure valid + parseParamMetaJSONString(meta); // ensure valid setError(undefined); - } catch (err) { - setError(new Error("Invalid JSON.")); + } catch (err: unknown) { + setError(err instanceof Error ? err : new Error("Invalid JSON format.")); } } }, [setValue, hasChanges, setHasChanges, meta, setError]); @@ -151,12 +151,10 @@ export const MetaEditorModal: FC = memo(function WrappedPa if (error) { try { const v = e.currentTarget.value; - if (v) { - JSON.parse(v); // ensure valid - } + if (v) parseParamMetaJSONString(v); // ensure valid setError(undefined); - } catch (err) { - setError(new Error("Invalid JSON.")); + } catch (err: unknown) { + setError(err instanceof Error ? err : new Error("Invalid JSON format.")); } } setValue(e.currentTarget.value); @@ -166,25 +164,23 @@ export const MetaEditorModal: FC = memo(function WrappedPa const onInputBlur = useCallback(() => { try { if (value) { - const j: AnyJson = JSON.parse(value); // ensure valid + const j: JsonMap = parseParamMetaJSONString(value); // ensure valid setValue(JSON.stringify(j, null, 2)); } setError(undefined); - } catch (err) { - setError(new Error("Invalid JSON.")); + } catch (err: unknown) { + setError(err instanceof Error ? err : new Error("Invalid JSON format.")); } }, [value, setError, setValue]); const onSaveValue = useCallback((e: FormEvent) => { e.preventDefault(); try { - if (value) { - JSON.parse(value); // ensure valid - } + if (value) parseParamMetaJSONString(value); // ensure valid setHasChanges(false); onSaveMeta(value); - } catch (err) { - setError(new Error("Invalid JSON.")); + } catch (err: unknown) { + setError(err instanceof Error ? err : new Error("Invalid JSON format.")); } }, [setError, setHasChanges, onSaveMeta, value]); @@ -238,7 +234,7 @@ export const MetaEditorModal: FC = memo(function WrappedPa