From 0d7c4554bc47cb6123679a4d6478105a77e98e0d Mon Sep 17 00:00:00 2001 From: VAIO73 <50487331+Vaso73@users.noreply.github.com> Date: Wed, 21 Oct 2026 03:14:16 +0000 Subject: [PATCH] fix: validate and type source viewer response fields --- AppImage/components/settings.tsx | 6 +++--- AppImage/lib/optimization-source-errors.ts | 9 +++++++++ tests/test_optimization_source.cjs | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/AppImage/components/settings.tsx b/AppImage/components/settings.tsx index c15a5059..feb59c4d 100644 --- a/AppImage/components/settings.tsx +++ b/AppImage/components/settings.tsx @@ -19,7 +19,7 @@ import { SUPPORTED_LANGUAGES, useI18n } from "../lib/i18n/provider" import { useIsPbs } from "../lib/use-platform" import type { LanguageCode } from "../lib/i18n/languages" import { NavTabOrderCard } from "./nav-tab-order-card" -import { optimizationSourceError, type OptimizationSourceError } from "../lib/optimization-source-errors" +import { optimizationSourceError, type OptimizationSourceError, type OptimizationSourceResponse } from "../lib/optimization-source-errors" // GitHub Dark color palette for bash syntax highlighting const BASH_KEYWORDS = new Set([ @@ -694,9 +694,9 @@ export function Settings() { deprecated: !!tool.deprecated, }) try { - const data = await fetchApi(`/api/proxmenux/tool-source/${tool.key}`) + const data = await fetchApi(`/api/proxmenux/tool-source/${tool.key}`) if (request !== codeRequest.current) return - if (data?.success && typeof data.source === "string" && data.source.trim()) { + if (data?.success === true && typeof data.source === "string" && data.source.trim()) { setCodeModal(prev => ({ ...prev, loading: false, functionName: typeof data.function === "string" ? data.function : '', source: data.source, script: typeof data.script === "string" ? data.script : '', deprecated: !!data.deprecated })) } else { setCodeModal(prev => ({ ...prev, loading: false, error: { kind: "unavailable", detail: typeof data?.error === "string" ? data.error : undefined } })) diff --git a/AppImage/lib/optimization-source-errors.ts b/AppImage/lib/optimization-source-errors.ts index 1d749c62..e0d0cdf8 100644 --- a/AppImage/lib/optimization-source-errors.ts +++ b/AppImage/lib/optimization-source-errors.ts @@ -5,6 +5,15 @@ export interface OptimizationSourceError { detail?: string } +export interface OptimizationSourceResponse { + success?: unknown + source?: unknown + function?: unknown + script?: unknown + deprecated?: unknown + error?: unknown +} + // Keep the blueprint's English API contract intact; translate only its display. export function optimizationSourceError(error: OptimizationSourceError, t: Translate): string { const detail = error.detail || "" diff --git a/tests/test_optimization_source.cjs b/tests/test_optimization_source.cjs index 5c0b1928..0ad7e279 100644 --- a/tests/test_optimization_source.cjs +++ b/tests/test_optimization_source.cjs @@ -67,7 +67,7 @@ async function main(){ for(const locale of ['en','sk','de']){ const f=fixture(locale);f.render();await f.settle() for(const [reply,key,param]of [ - [{success:false},'sourceUnavailable'],[null,'sourceUnavailable'],[{success:true,source:''},'sourceUnavailable'],[{success:true,source:' '},'sourceUnavailable'],[{success:true,source:17},'sourceUnavailable'], + [{success:false},'sourceUnavailable'],[null,'sourceUnavailable'],[{success:'yes',source:'invalid'},'sourceUnavailable'],[{success:true,source:''},'sourceUnavailable'],[{success:true,source:' '},'sourceUnavailable'],[{success:true,source:17},'sourceUnavailable'], [{http:404,body:{success:false,error:'Function not found in available scripts'}},'sourceFunctionMissing'], [{http:404,body:{success:false,error:'Unknown tool: demo'}},'sourceUnknownTool',{tool:'demo'}], [{http:404,body:{success:false,error:'No function mapping for demo'}},'sourceNoMapping',{tool:'demo'}],