From d768a3f6ba277906c359ca61741cf64ed9269e47 Mon Sep 17 00:00:00 2001 From: kang Date: Tue, 26 May 2026 09:57:08 +0800 Subject: [PATCH] feat: enhance wallet transfer handling and improve HTML safety - Added emitWalletRefresh function to trigger wallet refresh events after successful transfers and error handling. - Introduced removeScriptTags function to sanitize HTML content by removing script tags, preventing potential security issues. - Updated transfer handling logic to ensure wallet refresh is emitted in relevant scenarios, improving user experience. --- src/features/wallet/wallet-transfer-forms.tsx | 10 ++++++++++ src/lib/play-rules-html.ts | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/features/wallet/wallet-transfer-forms.tsx b/src/features/wallet/wallet-transfer-forms.tsx index 8227a97..5aaf8e6 100644 --- a/src/features/wallet/wallet-transfer-forms.tsx +++ b/src/features/wallet/wallet-transfer-forms.tsx @@ -29,6 +29,12 @@ import { formatWalletClientError } from "@/lib/wallet-api-error"; import { LotteryApiBizError } from "@/types/api/errors"; /** 处理中 / 待对账:刷新数据后提示用文案即可 */ +function emitWalletRefresh() { + if (typeof window !== "undefined") { + window.dispatchEvent(new Event("lottery-wallet-refresh")); + } +} + async function handleTransferMaybePending( e: unknown, onRefresh: () => Promise, @@ -37,11 +43,13 @@ async function handleTransferMaybePending( if (e instanceof LotteryApiBizError && e.code === 1002) { toast.message(e.message || t("wallet.pendingToast")); await onRefresh(); + emitWalletRefresh(); return true; } if (isAxiosError(e) && e.response?.status === 409) { toast.message(t("wallet.pendingShort")); await onRefresh(); + emitWalletRefresh(); return true; } return false; @@ -166,6 +174,7 @@ export function TransferInPanel({ toast.success(t("wallet.successIn")); setAmountText(""); await onSuccess(); + emitWalletRefresh(); } catch (e) { if (await handleTransferMaybePending(e, onSuccess, t)) { setLocalError(formatWalletClientError(e, t)); @@ -298,6 +307,7 @@ export function TransferOutPanel({ toast.success(t("wallet.successOut")); setAmountText(""); await onSuccess(); + emitWalletRefresh(); } catch (e) { if (await handleTransferMaybePending(e, onSuccess, t)) { setLocalError(formatWalletClientError(e, t)); diff --git a/src/lib/play-rules-html.ts b/src/lib/play-rules-html.ts index 75eaacf..f9facc1 100644 --- a/src/lib/play-rules-html.ts +++ b/src/lib/play-rules-html.ts @@ -7,6 +7,15 @@ const KEY_NE = "frontend.play_rules_html_ne"; type SettingItem = { key: string; value: unknown }; +function removeScriptTags(html: string | null): string | null { + if (!html) return html; + // React won't execute scripts injected via `dangerouslySetInnerHTML`. + // Removing them avoids the warning and prevents unintended script injection. + return html + .replace(/]*>[\s\S]*?<\/script>/gi, "") + .replace(/]*\/>/gi, ""); +} + function asNonEmptyString(value: unknown): string | null { if (typeof value !== "string") { return null; @@ -29,10 +38,10 @@ export function resolvePlayRulesHtml( const lang: AppLanguage = normalizeLanguage(language); if (lang === "zh") { - return zh ?? legacy; + return removeScriptTags(zh ?? legacy); } if (lang === "ne") { - return ne ?? en ?? zh ?? legacy; + return removeScriptTags(ne ?? en ?? zh ?? legacy); } - return en ?? zh ?? legacy; + return removeScriptTags(en ?? zh ?? legacy); }