From c50cbc15d604256ed938e78c7a75dd839d7d3f5f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:11:03 +0000
Subject: [PATCH 01/11] Initial plan
From 261df398b452fec54d395a5940bd11c8e7696cc8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:21:59 +0000
Subject: [PATCH 02/11] feat: add configurable home background blur
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
.../settings/cards/DisplaySettingsCard.vue | 9 +++
src/pages/index.vue | 68 +++++++++++++++++++
src/utils/settings.js | 20 ++++++
3 files changed, 97 insertions(+)
diff --git a/src/components/settings/cards/DisplaySettingsCard.vue b/src/components/settings/cards/DisplaySettingsCard.vue
index b8bb090..ff168ee 100644
--- a/src/components/settings/cards/DisplaySettingsCard.vue
+++ b/src/components/settings/cards/DisplaySettingsCard.vue
@@ -19,6 +19,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/index.vue b/src/pages/index.vue
index a674d50..5d85e9e 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -1,4 +1,16 @@
+
+
{{ titleText }}
@@ -657,6 +669,41 @@ export default {
return `${deviceName} - ${currentDateStr}的作业`;
}
},
+ hasBackgroundImage() {
+ return !!this.backgroundImageUrl;
+ },
+ backgroundImageUrl() {
+ void this.settingsTick;
+ return (getSetting("display.backgroundImage") || "").trim();
+ },
+ backgroundBlurAmount() {
+ void this.settingsTick;
+ const value = Number(getSetting("display.backgroundBlur"));
+ return Number.isFinite(value) ? value : 0;
+ },
+ backgroundDimAmount() {
+ void this.settingsTick;
+ const value = Number(getSetting("display.backgroundDim"));
+ return Number.isFinite(value) ? value : 0;
+ },
+ backgroundImageStyle() {
+ const url = this.backgroundImageUrl;
+ if (!url) return { display: "none" };
+
+ const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
+ return {
+ backgroundImage: `url("${url}")`,
+ filter: `blur(${blur}px)`,
+ };
+ },
+ backgroundOverlayStyle() {
+ if (!this.hasBackgroundImage) return { display: "none" };
+
+ const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 100);
+ return {
+ backgroundColor: `rgba(0, 0, 0, ${dim / 100})`,
+ };
+ },
sortedItems() {
const items = [];
@@ -2353,3 +2400,24 @@ export default {
},
};
+
+
diff --git a/src/utils/settings.js b/src/utils/settings.js
index c74cb1b..8774b91 100644
--- a/src/utils/settings.js
+++ b/src/utils/settings.js
@@ -147,6 +147,26 @@ const settingsDefinitions = {
description: "是否启用增强触摸模式",
icon: "mdi-gesture-tap-button",
},
+ "display.backgroundImage": {
+ type: "string",
+ default: "",
+ description: "主页背景图地址",
+ icon: "mdi-image-outline",
+ },
+ "display.backgroundBlur": {
+ type: "number",
+ default: 12,
+ validate: (value) => value >= 0 && value <= 30,
+ description: "背景模糊强度",
+ icon: "mdi-blur",
+ },
+ "display.backgroundDim": {
+ type: "number",
+ default: 35,
+ validate: (value) => value >= 0 && value <= 90,
+ description: "背景暗色程度(%)",
+ icon: "mdi-weather-night",
+ },
"display.showAntiScreenBurnCard": {
type: "boolean",
default: false,
From 2b411a13cad4a547ce8cf4058a82f14fd9ad3f44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:24:06 +0000
Subject: [PATCH 03/11] refine background settings validation and safety
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 33 +++++++++++++++++++++++++++++----
src/utils/settings.js | 2 +-
2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 5d85e9e..9111b6f 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -688,11 +688,11 @@ export default {
},
backgroundImageStyle() {
const url = this.backgroundImageUrl;
- if (!url) return { display: "none" };
+ if (!this.isSafeBackgroundUrl(url)) return { display: "none" };
const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
return {
- backgroundImage: `url("${url}")`,
+ backgroundImage: `url("${this.sanitizeBackgroundUrl(url)}")`,
filter: `blur(${blur}px)`,
};
},
@@ -700,8 +700,10 @@ export default {
if (!this.hasBackgroundImage) return { display: "none" };
const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 100);
+ const overlayBlur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50) / 3;
return {
backgroundColor: `rgba(0, 0, 0, ${dim / 100})`,
+ backdropFilter: `blur(${overlayBlur}px)`,
};
},
sortedItems() {
@@ -2203,6 +2205,30 @@ export default {
return nameMap[lastPart] || lastPart;
},
+ isSafeBackgroundUrl(url) {
+ if (!url) return false;
+ const trimmed = url.trim();
+ if (trimmed.toLowerCase().startsWith("javascript:")) return false;
+
+ try {
+ const parsed = new URL(trimmed, window.location.origin);
+ const protocol = parsed.protocol.replace(":", "");
+ if (["http", "https", "data", "blob"].includes(protocol)) return true;
+ } catch (e) {
+ // Allow relative paths
+ if (
+ trimmed.startsWith("/") ||
+ trimmed.startsWith("./") ||
+ trimmed.startsWith("../")
+ ) {
+ return true;
+ }
+ }
+ return false;
+ },
+ sanitizeBackgroundUrl(url) {
+ return url.replace(/["'()]/g, "");
+ },
safeBase64Decode(base64String) {
try {
@@ -2414,10 +2440,9 @@ export default {
}
.home-background {
- transform: scale(1.04);
+ transform: scale(1.02);
}
.home-background-overlay {
- backdrop-filter: blur(2px);
}
diff --git a/src/utils/settings.js b/src/utils/settings.js
index 8774b91..349dd57 100644
--- a/src/utils/settings.js
+++ b/src/utils/settings.js
@@ -156,7 +156,7 @@ const settingsDefinitions = {
"display.backgroundBlur": {
type: "number",
default: 12,
- validate: (value) => value >= 0 && value <= 30,
+ validate: (value) => value >= 0 && value <= 50,
description: "背景模糊强度",
icon: "mdi-blur",
},
From cdbe06f528d2eabcd68a920478d9c36c6992c0fe Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:25:15 +0000
Subject: [PATCH 04/11] harden background url handling
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 9111b6f..d3e6e7b 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -699,7 +699,7 @@ export default {
backgroundOverlayStyle() {
if (!this.hasBackgroundImage) return { display: "none" };
- const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 100);
+ const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 90);
const overlayBlur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50) / 3;
return {
backgroundColor: `rgba(0, 0, 0, ${dim / 100})`,
@@ -2227,7 +2227,13 @@ export default {
return false;
},
sanitizeBackgroundUrl(url) {
- return url.replace(/["'()]/g, "");
+ if (!this.isSafeBackgroundUrl(url)) return "";
+ try {
+ const parsed = new URL(url, window.location.origin);
+ return parsed.href;
+ } catch (e) {
+ return url.replace(/["'()\\]/g, "");
+ }
},
safeBase64Decode(base64String) {
@@ -2442,7 +2448,4 @@ export default {
.home-background {
transform: scale(1.02);
}
-
-.home-background-overlay {
-}
From b96484d26a11552500a2b5c50eb0858dffdd00b8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:26:32 +0000
Subject: [PATCH 05/11] improve background url sanitization
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index d3e6e7b..5c84091 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -689,10 +689,12 @@ export default {
backgroundImageStyle() {
const url = this.backgroundImageUrl;
if (!this.isSafeBackgroundUrl(url)) return { display: "none" };
+ const safeUrl = this.sanitizeBackgroundUrl(url);
+ if (!safeUrl) return { display: "none" };
const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
return {
- backgroundImage: `url("${this.sanitizeBackgroundUrl(url)}")`,
+ backgroundImage: `url("${encodeURI(safeUrl)}")`,
filter: `blur(${blur}px)`,
};
},
@@ -700,7 +702,9 @@ export default {
if (!this.hasBackgroundImage) return { display: "none" };
const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 90);
- const overlayBlur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50) / 3;
+ // Slightly reduce overlay blur to avoid overwhelming foreground
+ const overlayBlur =
+ Math.min(Math.max(this.backgroundBlurAmount, 0), 50) / 3;
return {
backgroundColor: `rgba(0, 0, 0, ${dim / 100})`,
backdropFilter: `blur(${overlayBlur}px)`,
@@ -2232,7 +2236,8 @@ export default {
const parsed = new URL(url, window.location.origin);
return parsed.href;
} catch (e) {
- return url.replace(/["'()\\]/g, "");
+ // Fallback for relative paths when URL parsing fails
+ return url.replace(/[^a-zA-Z0-9-._~!$&'()*+,;=/:@%]/g, "");
}
},
From 2c12051c45d14ab56cc4022c227b6c74431dbc6a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:28:00 +0000
Subject: [PATCH 06/11] harden css escaping for background
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 5c84091..d7554a6 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -693,8 +693,9 @@ export default {
if (!safeUrl) return { display: "none" };
const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
+ const escaped = this.cssEscape(encodeURI(safeUrl));
return {
- backgroundImage: `url("${encodeURI(safeUrl)}")`,
+ backgroundImage: `url("${escaped}")`,
filter: `blur(${blur}px)`,
};
},
@@ -2217,7 +2218,7 @@ export default {
try {
const parsed = new URL(trimmed, window.location.origin);
const protocol = parsed.protocol.replace(":", "");
- if (["http", "https", "data", "blob"].includes(protocol)) return true;
+ if (["http", "https", "blob"].includes(protocol)) return true;
} catch (e) {
// Allow relative paths
if (
@@ -2237,9 +2238,15 @@ export default {
return parsed.href;
} catch (e) {
// Fallback for relative paths when URL parsing fails
- return url.replace(/[^a-zA-Z0-9-._~!$&'()*+,;=/:@%]/g, "");
+ return url.replace(/[^a-zA-Z0-9-._~/:@%+#?&=]/g, "");
}
},
+ cssEscape(value) {
+ if (typeof CSS !== "undefined" && CSS.escape) {
+ return CSS.escape(value);
+ }
+ return value.replace(/[^a-zA-Z0-9_\-]/g, (char) => `\\${char}`);
+ },
safeBase64Decode(base64String) {
try {
From 3d0c51dfa156596486b75868e2fe31de664879a1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:29:04 +0000
Subject: [PATCH 07/11] tighten background url validation
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index d7554a6..f440a9e 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -693,7 +693,7 @@ export default {
if (!safeUrl) return { display: "none" };
const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
- const escaped = this.cssEscape(encodeURI(safeUrl));
+ const escaped = this.cssEscape(safeUrl);
return {
backgroundImage: `url("${escaped}")`,
filter: `blur(${blur}px)`,
@@ -2218,18 +2218,12 @@ export default {
try {
const parsed = new URL(trimmed, window.location.origin);
const protocol = parsed.protocol.replace(":", "");
- if (["http", "https", "blob"].includes(protocol)) return true;
+ if (!["http", "https", "blob"].includes(protocol)) return false;
+ if (parsed.pathname.includes("..")) return false;
+ return true;
} catch (e) {
- // Allow relative paths
- if (
- trimmed.startsWith("/") ||
- trimmed.startsWith("./") ||
- trimmed.startsWith("../")
- ) {
- return true;
- }
+ return false;
}
- return false;
},
sanitizeBackgroundUrl(url) {
if (!this.isSafeBackgroundUrl(url)) return "";
@@ -2237,15 +2231,17 @@ export default {
const parsed = new URL(url, window.location.origin);
return parsed.href;
} catch (e) {
- // Fallback for relative paths when URL parsing fails
- return url.replace(/[^a-zA-Z0-9-._~/:@%+#?&=]/g, "");
+ return "";
}
},
cssEscape(value) {
if (typeof CSS !== "undefined" && CSS.escape) {
return CSS.escape(value);
}
- return value.replace(/[^a-zA-Z0-9_\-]/g, (char) => `\\${char}`);
+ return value
+ .replace(/["'\\]/g, "\\$&")
+ .replace(/[\n\r\f]/g, "")
+ .replace(/[^a-zA-Z0-9_\-/:.@%?#=&]/g, (char) => `\\${char}`);
},
safeBase64Decode(base64String) {
From 85ab4d6c9f9c9d90bde7b898e064ac154abf1746 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:30:32 +0000
Subject: [PATCH 08/11] restrict background protocols and document scaling
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index f440a9e..f73ebd8 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -2218,7 +2218,7 @@ export default {
try {
const parsed = new URL(trimmed, window.location.origin);
const protocol = parsed.protocol.replace(":", "");
- if (!["http", "https", "blob"].includes(protocol)) return false;
+ if (!["http", "https"].includes(protocol)) return false;
if (parsed.pathname.includes("..")) return false;
return true;
} catch (e) {
@@ -2238,10 +2238,7 @@ export default {
if (typeof CSS !== "undefined" && CSS.escape) {
return CSS.escape(value);
}
- return value
- .replace(/["'\\]/g, "\\$&")
- .replace(/[\n\r\f]/g, "")
- .replace(/[^a-zA-Z0-9_\-/:.@%?#=&]/g, (char) => `\\${char}`);
+ return encodeURI(value);
},
safeBase64Decode(base64String) {
@@ -2454,6 +2451,6 @@ export default {
}
.home-background {
- transform: scale(1.02);
+ transform: scale(1.02); /* slight zoom to mask blur edges */
}
From aa0a0550ca522eb6fbb78ee6550e72969980f40c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 10:35:54 +0000
Subject: [PATCH 09/11] Add configurable home background image with blur and
dim controls
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/pages/index.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.vue b/src/pages/index.vue
index f73ebd8..5d5608d 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -2213,7 +2213,7 @@ export default {
isSafeBackgroundUrl(url) {
if (!url) return false;
const trimmed = url.trim();
- if (trimmed.toLowerCase().startsWith("javascript:")) return false;
+ if (/^(javascript|data|vbscript):/i.test(trimmed)) return false;
try {
const parsed = new URL(trimmed, window.location.origin);
From 730db45387ede704e5a8280b96c0e8c2323eb670 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 12:38:40 +0000
Subject: [PATCH 10/11] chore: add browser globals for eslint
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
eslint.config.js | 8 ++++++++
src/pages/settings.vue | 2 --
src/pages/socket-debugger.vue | 4 ++--
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/eslint.config.js b/eslint.config.js
index 944e82b..af8cda3 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,5 +1,6 @@
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
+import globals from 'globals'
export default [
{
@@ -16,6 +17,13 @@ export default [
...pluginVue.configs['flat/recommended'],
{
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node,
+ ...globals.serviceworker,
+ },
+ },
rules: {
'vue/multi-word-component-names': 'off',
},
diff --git a/src/pages/settings.vue b/src/pages/settings.vue
index cebe40e..711aa8d 100644
--- a/src/pages/settings.vue
+++ b/src/pages/settings.vue
@@ -305,8 +305,6 @@ export default {
return {isMobile: mobile};
},
data() {
- const provider = getSetting("server.provider");
-
const settings = {
server: {
domain: getSetting("server.domain"),
diff --git a/src/pages/socket-debugger.vue b/src/pages/socket-debugger.vue
index 1e1f288..d236a8f 100644
--- a/src/pages/socket-debugger.vue
+++ b/src/pages/socket-debugger.vue
@@ -339,7 +339,7 @@