From a992f6d79a54ec944c005fab7a3dbcc2894ab0e7 Mon Sep 17 00:00:00 2001
From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com>
Date: Wed, 12 Aug 2026 22:08:05 +0300
Subject: [PATCH] Fix CSP vulnerability by removing unsafe-inline for styles
Removes the 'unsafe-inline' directive from the style-src Content
Security Policy to prevent potential Cross-Site Scripting (XSS)
or malicious style injections. Replaces inline style manipulations
(`style.display = "none"`, `style=""`) with class list toggling
using a new `.d-none` utility class.
---
index.html | 2 +-
src-tauri/tauri.conf.json | 2 +-
src/main.ts | 12 ++++++------
src/ui/app.css | 1 +
4 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/index.html b/index.html
index 10761fd..d6c85c6 100644
--- a/index.html
+++ b/index.html
@@ -30,7 +30,7 @@
-
+
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index f69c987..df6e47e 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -23,7 +23,7 @@
}
],
"security": {
- "csp": "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src ipc: http://ipc.localhost https://open.er-api.com https://api.coingecko.com https://query1.finance.yahoo.com https://query2.finance.yahoo.com https://api.frankfurter.dev"
+ "csp": "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; img-src 'self' data:; font-src 'self' data:; connect-src ipc: http://ipc.localhost https://open.er-api.com https://api.coingecko.com https://query1.finance.yahoo.com https://query2.finance.yahoo.com https://api.frankfurter.dev"
}
},
"bundle": {
diff --git a/src/main.ts b/src/main.ts
index 8d3d343..5e2be4d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -596,7 +596,7 @@ function applyAllRates(): void {
async function refreshMarket(force = false): Promise {
if (!isTauri()) return;
const info = $("#market-info") as HTMLElement;
- info.style.display = "";
+ info.classList.remove("d-none");
info.classList.add("spin");
info.textContent = t("market");
const prices = await fetchMarketData(MARKET_SYMBOLS);
@@ -636,8 +636,8 @@ async function fetchNeededHistoricalRates(text: string): Promise {
function renderMarketInfo(): void {
const el = $("#market-info") as HTMLElement;
- if (marketFetchedAt === 0) { el.style.display = "none"; return; }
- el.style.display = "";
+ if (marketFetchedAt === 0) { el.classList.add("d-none"); return; }
+ el.classList.remove("d-none");
el.textContent = `${t("market")}: ${agoText(marketFetchedAt)} ↺`;
el.title = t("refreshRates");
}
@@ -661,9 +661,9 @@ function renderTotal(): void {
lbl.textContent = label;
line.append(lbl, document.createTextNode(total));
line.dataset.value = total;
- line.style.display = "";
+ line.classList.remove("d-none");
} else {
- line.style.display = "none";
+ line.classList.add("d-none");
delete line.dataset.value;
}
}
@@ -872,7 +872,7 @@ async function bindWindowControls(): Promise {
$("#win-min").addEventListener("click", () => void win.minimize());
$("#win-close").addEventListener("click", () => void win.hide());
} else {
- $("#win-controls").style.display = "none";
+ $("#win-controls").classList.add("d-none");
}
}
diff --git a/src/ui/app.css b/src/ui/app.css
index 3efd810..8265960 100644
--- a/src/ui/app.css
+++ b/src/ui/app.css
@@ -654,3 +654,4 @@ body {
}
.cm-tooltip-autocomplete ul li { font-family: var(--mono); font-size: 13px; color: var(--fg); }
.cm-tooltip-autocomplete ul li[aria-selected] { background: var(--sel); color: var(--fg); }
+.d-none { display: none !important; }