Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
initPluginEngine,
r,
} from "~/utils"
import { applyCustomize } from "~/utils/customize"
import { isTsWorker } from "~/utils/backend"
import { MustUser, UserOrGuest } from "./MustUser"
import "./index.css"
import { globalStyles } from "./theme"
Expand Down Expand Up @@ -57,7 +59,14 @@ const App: Component = () => {
(async () => {
handleRespWithoutAuthAndNotify(
(await r.get("/public/settings")) as Resp<Record<string, string>>,
setSettings,
(data) => {
setSettings(data)
// 注入自定义 CSS/JS(customize_head/body):仅 TS 模式前端运行时注入;
// Go 后端已在服务端完成注入,重复注入会导致自定义内容出现两次。
if (isTsWorker()) {
applyCustomize()
}
},
(e) => setErr(err().concat(e)),
)
})(),
Expand Down
19 changes: 13 additions & 6 deletions src/pages/manage/backup-restore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,12 +300,19 @@ const BackupRestore = () => {
appendLog(t("br.wrong_encrypt_password"), "error")
return
}
const dataArray = Object.values(data)
for (let i = dataArray.length - 4; i < dataArray.length; i++) {
const obj = dataArray[i]
console.log(obj)
for (let a = 0; a < obj.length; a++) {
const obj1 = obj[a]
// 解密 settings + users/storages/metas/shares(备份时这 5 个数组均被加密)。
// 原实现用 Object.values(data) 从 length-4 开始解密,会漏掉 settings
// (加密备份恢复后 settings 仍是密文,导致 customize_head/body 等配置失效)。
for (const name of [
"settings",
"users",
"storages",
"metas",
"shares",
] as const) {
const arr = (data as any)[name]
if (!Array.isArray(arr)) continue
for (const obj1 of arr) {
for (const key in obj1) {
obj1[key] = decrypt(obj1[key], password(), false, encrypted)
}
Expand Down
43 changes: 43 additions & 0 deletions src/utils/customize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { getSetting } from "~/store/settings"

/**
* 运行时注入自定义内容(对齐 Go 后端服务端注入 index.html 的
* `<!-- customize head -->` / `<!-- customize body -->` 占位符)。
*
* Go 后端在返回 HTML 前完成占位符替换;TS/静态部署前端 HTML 不经后端,
* 因此无法走服务端注入,改由前端在 settings 加载完成后动态注入:
* customize_head -> 注入到 <head> 末尾
* customize_body -> 注入到 <body> 末尾
*
* 注意:insertAdjacentHTML / innerHTML 不会执行插入的 <script>,这里用
* <template> 解析后对 <script> 节点重建,确保自定义 JS 能真正执行。
*/
function injectFragment(target: ParentNode, html: string): void {
if (!html) return
const template = document.createElement("template")
template.innerHTML = html
const nodes = Array.from(template.content.childNodes)
for (const node of nodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
const el = node as Element
if (el.tagName === "SCRIPT") {
const script = document.createElement("script")
for (const attr of Array.from(el.attributes)) {
script.setAttribute(attr.name, attr.value)
}
script.textContent = el.textContent || ""
target.appendChild(script)
} else {
target.appendChild(node.cloneNode(true))
}
} else {
target.appendChild(node.cloneNode(true))
}
}
}

/** 注入自定义 CSS/JS(customize_head + customize_body) */
export const applyCustomize = (): void => {
injectFragment(document.head, getSetting("customize_head"))
injectFragment(document.body, getSetting("customize_body"))
}