security(phase-9): complete security hardening
- Add safeJsonParse utility with schema validation - Migrate tokens to OS keyring storage - Add Ed25519 key encryption at rest - Enable WSS configuration option - Fix JSON.parse in HandParamsForm, WorkflowEditor, WorkflowList - Update test mock data to match valid status values Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
Info,
|
||||
} from 'lucide-react';
|
||||
import type { HandParameter } from '../types/hands';
|
||||
import { parseJsonOrDefault, safeJsonParse } from '../lib/json-utils';
|
||||
|
||||
// === Types ===
|
||||
|
||||
@@ -144,13 +145,9 @@ function getPresetStorageKey(handId: string): string {
|
||||
}
|
||||
|
||||
function loadPresets(handId: string): ParameterPreset[] {
|
||||
try {
|
||||
const stored = localStorage.getItem(getPresetStorageKey(handId));
|
||||
if (stored) {
|
||||
return JSON.parse(stored) as ParameterPreset[];
|
||||
}
|
||||
} catch {
|
||||
// Ignore parse errors
|
||||
const stored = localStorage.getItem(getPresetStorageKey(handId));
|
||||
if (stored) {
|
||||
return parseJsonOrDefault<ParameterPreset[]>(stored, []);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -405,15 +402,15 @@ function ObjectParamInput({ param, value, onChange, disabled, error }: ParamInpu
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||
onChange(parsed);
|
||||
const result = safeJsonParse<unknown>(text);
|
||||
if (result.success) {
|
||||
if (typeof result.data === 'object' && !Array.isArray(result.data)) {
|
||||
onChange(result.data as Record<string, unknown>);
|
||||
setParseError(null);
|
||||
} else {
|
||||
setParseError('Value must be a JSON object');
|
||||
}
|
||||
} catch {
|
||||
} else {
|
||||
setParseError('Invalid JSON format');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -574,6 +574,8 @@ export function RightPanel() {
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
AlertCircle,
|
||||
GitBranch,
|
||||
} from 'lucide-react';
|
||||
import { safeJsonParse } from '../lib/json-utils';
|
||||
|
||||
// === Types ===
|
||||
|
||||
@@ -163,11 +164,15 @@ function StepEditor({ step, hands, index, onUpdate, onRemove, onMoveUp, onMoveDo
|
||||
<textarea
|
||||
value={step.params ? JSON.stringify(step.params, null, 2) : ''}
|
||||
onChange={(e) => {
|
||||
try {
|
||||
const params = e.target.value.trim() ? JSON.parse(e.target.value) : undefined;
|
||||
onUpdate({ ...step, params });
|
||||
} catch {
|
||||
// Invalid JSON, keep current params
|
||||
const text = e.target.value.trim();
|
||||
if (text) {
|
||||
const result = safeJsonParse<Record<string, unknown>>(text);
|
||||
if (result.success) {
|
||||
onUpdate({ ...step, params: result.data });
|
||||
}
|
||||
// If parse fails, keep current params
|
||||
} else {
|
||||
onUpdate({ ...step, params: undefined });
|
||||
}
|
||||
}}
|
||||
placeholder='{"key": "value"}'
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
Loader2,
|
||||
X,
|
||||
} from 'lucide-react';
|
||||
import { safeJsonParse } from '../lib/json-utils';
|
||||
|
||||
// === View Toggle Types ===
|
||||
|
||||
@@ -44,12 +45,12 @@ function ExecuteModal({ workflow, isOpen, onClose, onExecute, isExecuting }: Exe
|
||||
const handleExecute = async () => {
|
||||
let parsedInput: Record<string, unknown> | undefined;
|
||||
if (input.trim()) {
|
||||
try {
|
||||
parsedInput = JSON.parse(input);
|
||||
} catch {
|
||||
alert('输入格式错误,请使用有效的 JSON 格式。');
|
||||
const result = safeJsonParse<Record<string, unknown>>(input);
|
||||
if (!result.success) {
|
||||
alert('Input format error, please use valid JSON format.');
|
||||
return;
|
||||
}
|
||||
parsedInput = result.data;
|
||||
}
|
||||
await onExecute(workflow.id, parsedInput);
|
||||
setInput('');
|
||||
|
||||
Reference in New Issue
Block a user