diff --git a/src/aura/init/main/ipcModules/aikariIpcHandler.js b/src/aura/init/main/ipcModules/aikariIpcHandler.js index f8cf273..cb016b3 100644 --- a/src/aura/init/main/ipcModules/aikariIpcHandler.js +++ b/src/aura/init/main/ipcModules/aikariIpcHandler.js @@ -218,12 +218,17 @@ const applyAikariIpcHandler = (ipcMain) => { const AIKARI_DEFAULT_INSTALL_DIR = path.join( "C:\\Program Files", - "HugoAura Aikari" + "HugoAura", + "Aikari" ); const AIKARI_LAUNCHER_PATH = path.join( AIKARI_DEFAULT_INSTALL_DIR, "Aikari-Launcher.exe" ); + const AIKARI_UNINSTALLER_PATH = path.join( + AIKARI_DEFAULT_INSTALL_DIR, + "unins000.exe" + ); const AIKARI_SVC_NAME = "HugoAuraAikari"; const isAikariDetached = process.argv.includes("--aikari-detach"); @@ -502,27 +507,27 @@ const applyAikariIpcHandler = (ipcMain) => { return await functions.execCommand( logHeader, AIKARI_LAUNCHER_PATH, - "--startup auto install" + "--service install" ); case "uninstSvc": { const result = await functions.execCommand( logHeader, AIKARI_LAUNCHER_PATH, - "remove" + "--service uninstall" ); return result; } case "startSvc": return await functions.execCommand( logHeader, - AIKARI_LAUNCHER_PATH, - "start" + "sc.exe", + `start ${AIKARI_SVC_NAME}` ); case "stopSvc": { const result = await functions.execCommand( logHeader, - AIKARI_LAUNCHER_PATH, - "stop" + "sc.exe", + `stop ${AIKARI_SVC_NAME}` ); if (result.success && global.__HUGO_AURA__.aikariStats) { global.__HUGO_AURA__.aikariStats.connected = false; @@ -547,7 +552,11 @@ const applyAikariIpcHandler = (ipcMain) => { case "inst": // TODO: Impl Aikari INST case "uninst": - // same + return await functions.execCommand( + logHeader, + AIKARI_UNINSTALLER_PATH, + "" + ); default: return { success: false, errorObj: new Error("Method not found") }; } diff --git a/src/aura/ui/aikari/onConnectedSeq.js b/src/aura/ui/aikari/onConnectedSeq.js index c4e287a..c8af9ea 100644 --- a/src/aura/ui/aikari/onConnectedSeq.js +++ b/src/aura/ui/aikari/onConnectedSeq.js @@ -54,6 +54,29 @@ const actions = { return null; } }, + getAikariPLSRules: async (wsObj) => { + const eventId = genRandomHex(); + wsObj.send( + JSON.stringify({ + module: "pls", + eventId, + method: "config.rules.getConfig", + }) + ); + const promise = new Promise((resolve) => { + wsGetCallbacks.set(eventId, resolve); + }); + const data = await promise; + if (data.success) { + console.debug( + "[HugoAura / UI / Aikari OCMS] Received Aikari PLS rules: ", + data + ); + return data.data; + } else { + return null; + } + }, }; const onAikariConnectedMsgSeq = async ({ curAikariStates, wsObj }) => { @@ -66,6 +89,7 @@ const onAikariConnectedMsgSeq = async ({ curAikariStates, wsObj }) => { document.addEventListener("onAikariMessageRecv", onMsgRecvListener); // Get Aikari Version await actions.getAikariVersion(updatedAikariStates, wsObj); + // Get Aikari Launcher Config const aikariLauncherConfig = await actions.getAikariLauncherConfig(wsObj); if (aikariLauncherConfig) { global.ipcRenderer.invoke( @@ -73,6 +97,14 @@ const onAikariConnectedMsgSeq = async ({ curAikariStates, wsObj }) => { aikariLauncherConfig ); } + // Get Aikari PLS Rules + const aikariPLSRules = await actions.getAikariPLSRules(wsObj); + if (aikariPLSRules) { + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariRules`, + aikariPLSRules + ); + } return updatedAikariStates; }; diff --git a/src/aura/ui/composables/aikariConfigManager.js b/src/aura/ui/composables/aikariConfigManager.js index 51828b7..abd536a 100644 --- a/src/aura/ui/composables/aikariConfigManager.js +++ b/src/aura/ui/composables/aikariConfigManager.js @@ -35,7 +35,12 @@ const { genRandomHex } = require("../../utils/crypto"); * @param {string} configKey * @param {any} configValue */ -const updateAikariConfigToRemote = async (configKey, configValue) => { +const updateAikariConfigToRemote = async ( + configKey, + configValue, + module = "launcher", + writeToDisk = true +) => { const configLevels = configKey.split("."); const aikariConfigUpdateEvent = new CustomEvent("onAikariConfigUpdate", { @@ -57,18 +62,65 @@ const updateAikariConfigToRemote = async (configKey, configValue) => { /** * @type {ClientAikariRequest} */ - /* const data = { - method: "config.action.updateConfig", + method: "config.actions.updateConfig", data: { key: configKey, value: configValue, + write: writeToDisk, }, eventId: genRandomHex(), // 不用 crypto, 因为会带来不必要的性能开销 - };*/ - // TODO: Impl this ↑ + module: module, + }; - // global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncAikariConfig`, { + basic: global.__HUGO_AURA__.aikariSettings, + rules: global.__HUGO_AURA__.aikariRules, + }); +}; + +// [!] Will be deprecated +const updateAikariPLSRulesToRemote = async ( + configKey, + configValue, + affiliated, + writeToDisk = true +) => { + const configLevels = configKey.split("."); + + const aikariRuleConfigUpdateEvent = new CustomEvent("onAikariConfigUpdate", { + detail: { + path: configLevels, + value: configValue, + }, + }); + document.dispatchEvent(aikariRuleConfigUpdateEvent); + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" + ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(aikariRuleConfigUpdateEvent); + }); + } + + /** + * @type {ClientAikariRequest} + */ + const data = { + method: "config.rules.updateConfig", + data: { + key: configKey, + value: configValue, + write: writeToDisk, + affiliated, + }, + eventId: genRandomHex(), + module: "pls", + }; + + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncAikariConfig`, { basic: global.__HUGO_AURA__.aikariSettings, rules: global.__HUGO_AURA__.aikariRules, @@ -80,4 +132,5 @@ module.exports = { updateAikariStatusFromLocal, updateAikariSettingsFromLocal, updateAikariConfigToRemote, + updateAikariPLSRulesToRemote, }; diff --git a/src/aura/ui/composables/rawCmdExec/fs.js b/src/aura/ui/composables/rawCmdExec/fs.js new file mode 100644 index 0000000..7cf3a80 --- /dev/null +++ b/src/aura/ui/composables/rawCmdExec/fs.js @@ -0,0 +1,28 @@ +const childProc = require("child_process"); + +const fileSystemRawCmds = { + getDiskCaptions: async () => { + const waitForCmd = new Promise((resolve) => { + childProc.exec( + "wmic logicaldisk get caption", + (error, stdout, stderr) => { + if (error) { + console.error( + `[HugoAura / UI / Composables / Raw CMD / FS] Failed to exec wmic getCaption: ${error}` + ); + resolve([]); + } + const drives = stdout + .trim() + .split("\r\n") + .slice(1) + .map((line) => line.trim()); + resolve(drives); + } + ); + }); + return waitForCmd; + }, +}; + +module.exports = fileSystemRawCmds; diff --git a/src/aura/ui/composables/settingsRenderer.js b/src/aura/ui/composables/settingsRenderer.js index c148407..946ab76 100755 --- a/src/aura/ui/composables/settingsRenderer.js +++ b/src/aura/ui/composables/settingsRenderer.js @@ -50,9 +50,9 @@ const setDisableStatus = (el, isDisable, hint = null) => { tooltipIns.enable(); } } else { - el.setAttribute("data-bs-toggle", "tooltip"); - el.setAttribute("data-bs-placement", "top"); - el.setAttribute("data-bs-title", "None"); + el.removeAttribute("data-bs-toggle"); + el.removeAttribute("data-bs-placement"); + el.removeAttribute("data-bs-title"); el.classList.remove("ase-operation-area-disabled"); const tooltipIns = bootstrap.Tooltip.getInstance(el); if (tooltipIns) { @@ -100,7 +100,18 @@ const renderInputArea = (entry, operationArea, descriptionArea) => { case "radio": { const elValue = entry.valueGetter(); const elArr = []; - for (const template of entry.templates) { + let targetTemplatesArr = []; + let targetTemplateLablesArr = []; + targetTemplatesArr = + typeof entry.templates === "function" + ? entry.templates() + : entry.templates; + targetTemplateLablesArr = + typeof entry.templateLabels === "function" + ? entry.templateLabels() + : entry.templateLabels; + + for (const template of targetTemplatesArr) { const inlineContainerEl = document.createElement("div"); inlineContainerEl.classList.add("form-check", "form-check-inline"); const radioEl = document.createElement("input"); @@ -108,7 +119,7 @@ const renderInputArea = (entry, operationArea, descriptionArea) => { radioEl.classList.add("form-check-input"); radioEl.type = "radio"; radioEl.name = `${entry.id}Radios`; - radioEl.id = `${entry.id}Radio${entry.templates.indexOf(template)}`; + radioEl.id = `${entry.id}Radio${targetTemplatesArr.indexOf(template)}`; radioEl.checked = template === elValue ? true : false; radioEl.addEventListener("change", async (event) => { if (event.target.checked) { @@ -126,7 +137,53 @@ const renderInputArea = (entry, operationArea, descriptionArea) => { labelEl.classList.add("form-check-label"); labelEl.setAttribute("for", radioEl.id); labelEl.textContent = - entry.templateLabels[entry.templates.indexOf(template)]; + targetTemplateLablesArr[targetTemplatesArr.indexOf(template)]; + inlineContainerEl.appendChild(labelEl); + elArr.push(inlineContainerEl); + } + return elArr; + } + case "checkbox": { + const elValue = entry.valueGetter(); + const elArr = []; + let targetTemplatesArr = []; + let targetTemplateLablesArr = []; + targetTemplatesArr = + typeof entry.templates === "function" + ? entry.templates() + : entry.templates; + targetTemplateLablesArr = + typeof entry.templateLabels === "function" + ? entry.templateLabels() + : entry.templateLabels; + + for (const templateName of targetTemplatesArr) { + const inlineContainerEl = document.createElement("div"); + inlineContainerEl.classList.add("form-check", "form-check-inline"); + const chkBoxEl = document.createElement("input"); + chkBoxEl.value = templateName; + chkBoxEl.classList.add("form-check-input"); + chkBoxEl.type = "checkbox"; + chkBoxEl.name = `${entry.id}Checkbox`; + chkBoxEl.id = `${entry.id}Checkbox${targetTemplatesArr.indexOf( + templateName + )}`; + chkBoxEl.checked = elValue.includes(templateName) ? true : false; + chkBoxEl.addEventListener("change", async (event) => { + showToast(entry); + await entry.callbackFn( + event.target.value, + chkBoxEl, + operationArea, + descriptionArea + ); + }); + inlineContainerEl.appendChild(chkBoxEl); + const labelEl = document.createElement("label"); + labelEl.classList.add("form-check-label"); + labelEl.setAttribute("for", chkBoxEl.id); + labelEl.textContent = + targetTemplateLablesArr[targetTemplatesArr.indexOf(templateName)]; inlineContainerEl.appendChild(labelEl); elArr.push(inlineContainerEl); } @@ -219,7 +276,7 @@ const renderNormalSettingsItem = (entry, formEl) => { powerIcon.setAttribute("data-bs-title", "需要重启 Electron 进程"); entryTitle.appendChild(powerIcon); } - if (entry.AikariRequired) { + if (entry.aikariRequired) { const aikariIcon = document.createElement("i"); aikariIcon.classList.add( "layui-icon", @@ -302,14 +359,14 @@ const renderNormalSettingsItem = (entry, formEl) => { insertOrRemoveEl(entryOperationArea, targetEl, true); } }; - const channel = entry.AikariRequired + const channel = entry.aikariRequired ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate"; entryContainerEl.addEventListener(channel, evtListener); // createOnLeaveEvtListener(channel, evtListener); } - if (entry.AikariRequired) { + if (entry.aikariRequired) { if (!global.__HUGO_AURA__.aikariStats.connected) { setDisableStatus(entryOperationArea, true, "连接至 Aikari 以继续"); } @@ -332,7 +389,7 @@ const renderNormalSettingsItem = (entry, formEl) => { const isDisabledRet = entry.auraDisable(); setDisableStatus( entryOperationArea, - isDisabledRet.value, + global.__HUGO_AURA__.aikariStats.connected ? isDisabledRet.value : true, isDisabledRet.tooltip ); }; @@ -354,7 +411,7 @@ const renderNormalSettingsItem = (entry, formEl) => { updateDisableStatus(); } }; - const channel = entry.AikariRequired + const channel = entry.aikariRequired ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate"; entryContainerEl.addEventListener(channel, evtListener); @@ -397,7 +454,9 @@ const renderPreviewItem = (entry, formEl) => { }; document.addEventListener( - eventChannel === "pls" ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate", + eventChannel === "aikari" + ? "onAikariConfigUpdate" + : "onHugoAuraConfigUpdate", eventListener ); createOnLeaveEvtListener(eventListener); // Clean up diff --git a/src/aura/ui/js/global.js b/src/aura/ui/js/global.js index 4605597..124f32c 100755 --- a/src/aura/ui/js/global.js +++ b/src/aura/ui/js/global.js @@ -6,9 +6,11 @@ let tooltipTriggerCache = null; const refreshBsTooltip = (selector = '[data-bs-toggle="tooltip"]') => { if (tooltipTriggerCache) { - [...tooltipTriggerCache].map((el) => - bootstrap.Tooltip.getInstance(el).disable() - ); + [...tooltipTriggerCache].map((el) => { + if (bootstrap.Tooltip.getInstance(el)) { + bootstrap.Tooltip.getInstance(el).disable(); + } + }); } const tooltipTriggerList = document.querySelectorAll(selector); diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html index 99d736a..1b1cdf2 100644 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html @@ -27,7 +27,7 @@
-

下载内核

+

下载应用

-
+
{ global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.downloadAndInstallAikariBin(); }; @@ -104,10 +106,10 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) // ↓ 这边的确可以把这些全都合并到一个可复用 fn 里去, 但没必要 // 如果后续要引入错误视觉反馈, 合并到单个 fn 反而会增加实现复杂度 - case "Install": + case "InstallSvc": btnEl.onclick = async () => { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( - "Install", + "InstallSvc", true ); global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( @@ -145,24 +147,26 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); }; break; - case "Uninstall": - if (btnContent === "删除内核") { + case "UninstallSvc": + if (btnContent === "卸载应用") { btnEl.onclick = async () => { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( - "Uninstall", + "UninstallSvc", true ); global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "warning", - "正在删除内核", - null, + "正在卸载 Aikari", + `

+ 请在弹出窗口中完成操作 +

`, false, false, null ); const ret = await ipcRenderer.invoke( `${IPC_METHOD_BASE}.aikariLifecycleControl`, - { target: "rmBin" } + { target: "uninst" } ); if (ret.success) { lifecycleStatus.installed = false; @@ -176,7 +180,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ); global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", - "内核已删除", + "Aikari 已完成卸载", null, true, true, @@ -185,7 +189,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } else { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", - "内核删除失败", + "Aikari 卸载失败", `

${ret.errorObj ? ret.errorObj : "检查日志以获取详细信息"}

`, @@ -199,7 +203,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } else { btnEl.onclick = async () => { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( - "Uninstall", + "UninstallSvc", true ); global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( @@ -239,7 +243,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } const ret = await ipcRenderer.invoke( `${IPC_METHOD_BASE}.aikariLifecycleControl`, - { target: "rmSvc" } + { target: "uninstSvc" } ); if (ret.success) { lifecycleStatus.svcInstalled = false; @@ -296,7 +300,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) 2000 ); await global.__HUGO_AURA_GLOBAL__.utils.sleep(100); - await ipcRenderer.invoke(`${IPC_METHOD_BASE}.retryAikariConnect`); + await ipcRenderer.invoke( + `${IPC_METHOD_BASE}.retryAikariConnect` + ); global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); } else { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); @@ -375,20 +381,25 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) switch (lifecycleStatus.installed) { case true: if (!lifecycleStatus.svcInstalled) { - updateStatusEl(acIdInst, atIdInst, "WARNING", "已下载, 服务未安装"); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", false); + updateStatusEl( + acIdInst, + atIdInst, + "WARNING", + "应用已安装, 服务未安装" + ); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("InstallSvc", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Uninstall", + "UninstallSvc", false, - "删除内核" + "卸载应用" ); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Start", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Stop", true); } else { updateStatusEl(acIdInst, atIdInst, "SUCCESS", "已安装"); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("InstallSvc", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Uninstall", + "UninstallSvc", false, "卸载服务" ); @@ -396,9 +407,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) break; case false: updateStatusEl(acIdInst, atIdInst, "PENDING", "未下载"); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", false); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Uninstall", true); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", false); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("InstallSvc", true); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("UninstallSvc", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Start", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Stop", true); } @@ -450,7 +461,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) if (curAikariStats.version && curAikariStats.version !== "unknown") { versionTextEl.textContent = curAikariStats.version; } else { - versionTextEl.textContent = "不可用" + versionTextEl.textContent = "不可用"; } }, @@ -468,7 +479,10 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) const binExistsRet = await ipcRenderer.invoke( `${IPC_METHOD_BASE}.getIfAikariBinExists` ); - if ((binExistsRet.success && binExistsRet.data.isExists) || lifecycleStatus.detached) { + if ( + (binExistsRet.success && binExistsRet.data.isExists) || + lifecycleStatus.detached + ) { lifecycleStatus.installed = true; global.__HUGO_AURA__.aikariStats.installed = true; ipcRenderer.invoke( @@ -628,7 +642,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportAikariInstallStep`; if (!retrieveMode) { - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "正在检查"); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true, "正在检查"); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", true); await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensureAikariInstallDir`); GLOBAL_FUNCTIONS.updateToast( @@ -639,7 +653,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) true, 2000 ); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true); } else { GLOBAL_FUNCTIONS.updateToast( "info", @@ -683,9 +697,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ipcRenderer.off(CUR_CHANNEL, callbackFn); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Download", + "Install", false, - "下载内核" + "下载应用" ); break; case "done": @@ -711,9 +725,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ipcRenderer.off(CUR_CHANNEL, callbackFn); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Download", + "Install", true, - "下载内核" + "下载应用" ); lifecycleStatus.installed = true; global.__HUGO_AURA__.aikariStats.installed = true; @@ -756,9 +770,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) case "cancelled": GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Download", + "Install", false, - "下载内核" + "下载应用" ); break; } @@ -852,14 +866,16 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) "acs-bc-aikari-status-page-status-area success"; break; case "FAILED": - areaContainerEl.className = "acs-bc-aikari-status-page-status-area failed"; + areaContainerEl.className = + "acs-bc-aikari-status-page-status-area failed"; break; case "WARNING": areaContainerEl.className = "acs-bc-aikari-status-page-status-area warning"; break; case "INFO": - areaContainerEl.className = "acs-bc-aikari-status-page-status-area info"; + areaContainerEl.className = + "acs-bc-aikari-status-page-status-area info"; break; default: return false; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html index 69ce598..2ac543d 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html @@ -36,13 +36,13 @@ class="nav-link" id="security-config-tab" data-bs-toggle="pill" - data-bs-target="#security-config-subpage" + data-bs-target="#device-info-post-config-subpage" type="button" role="tab" - aria-controls="security-config-subpage" + aria-controls="device-info-post-config-subpage" aria-selected="false" > - 设备安全 + 信息上报 @@ -61,7 +61,7 @@ >
diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js index 23a8585..6df1c69 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js @@ -7,29 +7,41 @@ } = require(`${REQUIRE_BASE}/../../../../composables/settingsRenderer`); const { basicSettings } = require(`${REQUIRE_BASE}/basic`); - const { deviceSecuritySettings } = require(`${REQUIRE_BASE}/deviceSecurity`); + const { deviceInfoPostSettings } = require(`${REQUIRE_BASE}/deviceInfoPost`); const { updateAikariSettingsFromLocal, updateAikariRulesFromLocal, } = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); + const fileSystemRawCmds = require(`${REQUIRE_BASE}/../../../../composables/rawCmdExec/fs`); + const initStatusPage = () => { global.__HUGO_AURA_LOADER__[ "Aura.UI.Assistant.Config.BehaviourCtrl.AikariStatus" ].active = true; }; + const preInitUIReactives = async () => { + if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) + global.__HUGO_AURA_UI_REACTIVES__.subConfig = {}; + if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared) + global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared = {}; + + global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared.diskCaptions = + await fileSystemRawCmds.getDiskCaptions(); + }; + const initBasicSettingsPage = () => { const basicSubPageEl = document.getElementById("basic-config-subpage"); settingsRenderer(basicSubPageEl, basicSettings); }; - const initDeviceSecuritySettingsPage = () => { - const deviceSecuritySubPageEl = document.getElementById( - "security-config-subpage" + const initDeviceInfoPostSettingsPage = () => { + const deviceInfoPostSubPageEl = document.getElementById( + "device-info-post-config-subpage" ); - settingsRenderer(deviceSecuritySubPageEl, deviceSecuritySettings); + settingsRenderer(deviceInfoPostSubPageEl, deviceInfoPostSettings); }; const renderSubPages = async () => { @@ -37,15 +49,16 @@ await updateAikariRulesFromLocal(); initBasicSettingsPage(); - initDeviceSecuritySettingsPage(); + initDeviceInfoPostSettingsPage(); }; const onMounted = () => { const rootEl = document.getElementById("acs-behaviour-control-el"); + preInitUIReactives(); initStatusPage(); setTimeout(() => { rootEl.classList.remove("acs-behaviour-control-hidden"); - renderSubPages(); // 如果立即渲染子页面, 此时 plsRules 还未初始化, 会导致子页面 auraIf 失效 + renderSubPages(); }, 500); }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js index 82006ab..22db8b9 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js @@ -4,28 +4,6 @@ const { updateAikariConfigToRemote, } = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); -const reusableChkFn = { - checkRelativePath: () => { - if (newVal === "" || !newVal) - return { valid: false, hint: "请输入证书路径" }; - - if (newVal.includes(":/") || newVal.includes(":\\")) { - return { valid: false, hint: "请输入相对路径, 而非绝对路径" }; - } - - if (newVal.includes("\\")) { - return { - valid: false, - hint: '请输入正确的路径, 使用 "/" 作为路径符', - }; - } - - return { - valid: true, - }; - }, -}; - const basicSettings = [ { id: 0, @@ -33,137 +11,70 @@ const basicSettings = [ child: [ { index: 0, - id: "plsListenPort", + id: "aikarWsPreferPort", type: "input", subType: "number", - name: "PLS WS 默认监听端口", - description: "PLS 的 WebSocket 服务器将默认监听指定的端口", + name: "Aikari WS 默认监听端口", + description: "Aikari WebSocket 服务器默认监听的端口", reactive: true, reactiveVal: ["root.settings"], restart: false, reload: false, - AikariRequired: true, + aikariRequired: true, restartAikari: false, warning: true, - warningContent: "PLS 仍会在默认端口被占用时, 自动随机端口重试", + warningContent: "Aikari 仍会在默认端口被占用时, 自动随机端口重试", associateVal: null, auraIf: () => true, defaultValue: "", placeHolder: "输入端口号 (10000 ~ 65535)", valueGetter: () => { if (!global.__HUGO_AURA__.aikariSettings) return ""; - return global.__HUGO_AURA__.aikariSettings.wsPort; + return global.__HUGO_AURA__.aikariSettings.wsPreferPort; }, callbackFn: (newVal) => { if (newVal === "" || !newVal) return { valid: false, hint: "请输入端口号" }; const numberNewVal = Number(newVal); - if (numberNewVal === NaN || !(10000 <= numberNewVal) || !(newVal <= 65535)) { + if ( + numberNewVal === NaN || + !(10000 <= numberNewVal) || + !(newVal <= 65535) + ) { return { valid: false, hint: "请输入合法的端口号 (10000 ~ 65535)" }; } - global.__HUGO_AURA__.aikariSettings.wsPort = numberNewVal; - updateAikariConfigToRemote("wsPort", numberNewVal); + global.__HUGO_AURA__.aikariSettings.wsPreferPort = numberNewVal; + updateAikariConfigToRemote("wsPreferPort", numberNewVal); return { valid: true }; }, }, { index: 1, - id: "plsCertPath", - type: "input", - subType: "text", - name: "WSS TLS 证书相对路径", - description: "PLS 将使用指定路径下的证书启动 WSS 服务器", - reactive: true, - reactiveVal: ["root.settings"], - restart: false, - reload: false, - AikariRequired: true, - restartAikari: true, - tip: true, - tipTitle: - '路径相对于 "%PROGRAMDATA%\\HugoAura\\Aura-PLS\\", 使用 "/" 作为路径符', - associateVal: null, - auraIf: () => true, - defaultValue: "", - placeHolder: "输入相对路径, 例如: config/vme50/cert.crt", - valueGetter: () => { - if (!global.__HUGO_AURA__.aikariSettings) return ""; - return global.__HUGO_AURA__.aikariSettings.certPath; - }, - callbackFn: (newVal) => { - const validate = reusableChkFn.checkRelativePath(); - if (!validate.valid) { - return validate; - } - - global.__HUGO_AURA__.aikariSettings.certPath = newVal; - updateAikariConfigToRemote("certPath", newVal); - return { valid: true }; - }, - }, - { - index: 2, - id: "plsCertPath", - type: "input", - subType: "text", - name: "WSS TLS 证书私钥相对路径", - description: "PLS 将使用指定路径下的私钥启动 WSS 服务器", - reactive: true, - reactiveVal: ["root.settings"], - restart: false, - reload: false, - AikariRequired: true, - restartAikari: true, - tip: true, - tipTitle: - '路径相对于 "%PROGRAMDATA%\\HugoAura\\Aura-PLS\\", 使用 "/" 作为路径符', - warning: true, - warningContent: "请使用 PEM 格式的密钥", - associateVal: null, - auraIf: () => true, - defaultValue: "", - placeHolder: "输入相对路径, 例如: config/vme50/cert.key", - valueGetter: () => { - if (!global.__HUGO_AURA__.aikariSettings) return ""; - return global.__HUGO_AURA__.aikariSettings.keyPath; - }, - callbackFn: (newVal) => { - const validate = reusableChkFn.checkRelativePath(); - if (!validate.valid) { - return validate; - } - - global.__HUGO_AURA__.aikariSettings.keyPath = newVal; - updateAikariConfigToRemote("keyPath", newVal); - return { valid: true }; - }, - }, - { - index: 3, - id: "plsRegenCertAftRelaunch", + id: "aikariForceRegenWsTlsCert", type: "switch", - name: "重新生成 TLS 证书", - description: "PLS 将在下次启动时重新生成 TLS 证书", + name: "重新生成 WS TLS 证书", + description: "Aikari 将在下次启动时重新生成用于 WebSocket 的 TLS 证书", reactive: true, reactiveVal: ["root.settings"], restart: false, reload: false, - AikariRequired: true, + aikariRequired: true, restartAikari: true, associateVal: null, auraIf: () => true, defaultValue: false, valueGetter: () => { if (!global.__HUGO_AURA__.aikariSettings) return ""; - return global.__HUGO_AURA__.aikariSettings.regenCert; + return global.__HUGO_AURA__.aikariSettings.tls.regenWsCertNextLaunch; }, callbackFn: (newVal) => { if (typeof newVal !== "boolean") return false; - global.__HUGO_AURA__.aikariSettings.regenCert = newVal; - updateAikariConfigToRemote("regenCert", newVal); + global.__HUGO_AURA__.aikariSettings.tls.regenWsCertNextLaunch = + newVal; + updateAikariConfigToRemote("tls.regenWsCertNextLaunch", newVal); return true; }, }, diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceInfoPost.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceInfoPost.js new file mode 100644 index 0000000..f774d2c --- /dev/null +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceInfoPost.js @@ -0,0 +1,257 @@ +// [!] Will be deprecated + +const REQUIRE_BASE = "."; + +const { + updateAikariPLSRulesToRemote, +} = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); + +const composables = {}; + +const deviceInfoPostSettings = [ + { + id: 0, + categoryName: "冰点管理", + child: [ + { + index: 0, + id: "enableFreezeInfoReportOverride", + type: "switch", + name: "启用冰冻状态篡改", + description: "篡改上报的冰冻数据, 可自定义集控端显示的状态", + reactive: true, + reactiveVal: ["root.ruleSettings"], + restart: false, + reload: false, + aikariRequired: true, + restartAikari: false, + associateVal: null, + auraIf: () => true, + defaultValue: false, + valueGetter: () => { + if (!global.__HUGO_AURA__.aikariRules) return ""; + return global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies + .freezeManagement.freezeDiskInfoPost.enabled; + }, + callbackFn: (newVal) => { + if (typeof newVal !== "boolean") return; + if (!global.__HUGO_AURA__.aikariRules) return; + + global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost.enabled = + newVal; + updateAikariPLSRulesToRemote( + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost.enabled", + newVal, + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost" + ); + return true; + }, + }, + { + index: 1, + id: "freezeInfoReportFrozenDisks", + type: "checkbox", + name: "被冻结的磁盘", + description: "选中的磁盘会被上报为冻结 (不是实际行为)", + restart: false, + reload: false, + aikariRequired: true, + restartAikari: false, + warning: true, + warningContent: + "如果可选的磁盘盘符与下方预览不一致, 则多出的盘符可能为 DVD 驱动器 / 软盘 / 可移动磁盘, 忽略即可", + reactive: true, + reactiveVal: ["root.ruleSettings"], + associateVal: [ + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost.enabled", + ], + auraIf: () => true, + auraDisable: () => { + if (!global.__HUGO_AURA__.aikariRules) return { value: true }; + if ( + !global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared + .diskCaptions + ) + return { + value: true, + tooltip: "发生错误, 请上报至 HugoAura GitHub Issues", + }; + if ( + !global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared + .diskCaptions.length === 0 + ) + return { + value: true, + tooltip: "发生错误, 请上报至 HugoAura GitHub Issues", + }; + + return { + value: + !global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies + .freezeManagement.freezeDiskInfoPost.enabled, + }; + }, + defaultValue: [], + templates: () => { + try { + if ( + global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared + .diskCaptions.length === 0 + ) { + return ["error"]; + } else { + return global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared.diskCaptions.map( + (element) => { + return element.toLowerCase().replace(/:/g, ""); + } + ); + } + } catch (err) { + console.error(err); + return ["error"]; + } + }, + templateLabels: () => { + try { + if ( + global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared + .diskCaptions.length === 0 + ) { + return ["获取盘符时发生错误, 请上报至 GitHub Issues"]; + } else { + return global.__HUGO_AURA_UI_REACTIVES__.subConfig.behaviourCtrlShared.diskCaptions.map( + (element) => { + return element.replace(/:/g, " 盘"); + } + ); + } + } catch (err) { + console.error(err); + return ["发生未知错误"]; + } + }, + valueGetter: () => { + if (!global.__HUGO_AURA__.aikariRules) return []; + + return global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies + .freezeManagement.freezeDiskInfoPost.frozenDisks; + }, + callbackFn: (affectedData, affectedEl) => { + const targetArr = + global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies + .freezeManagement.freezeDiskInfoPost.frozenDisks; + if (affectedEl.checked) { + targetArr.push(affectedData); + } else { + targetArr.splice(targetArr.indexOf(affectedData), 1); + } + updateAikariPLSRulesToRemote( + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost.frozenDisks", + targetArr, + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost" + ); + return true; + }, + }, + { + index: 2, + id: "freezeInfoReportOverridePreview", + type: "preview", + loaderTarget: + "Aura.UI.Assistant.Config.BehaviourCtrl.DeviceSecurity.FreezeOverridePreview", + associateVal: [ + "ssaFeatures.securityPolicies.freezeManagement.freezeDiskInfoPost.frozenDisks", + ], + listenerType: "aikari", + }, + ], + }, + { + id: 1, + categoryName: "软件信息", + child: [ + { + index: 0, + id: "enableSoftwareReportPostOverride", + type: "switch", + name: "启用软件信息上报覆写", + description: + '覆写上报的软件信息, 可自定义集控端 "设备管控" - <设备名> - "软件列表" 下的信息显示', + reactive: true, + reactiveVal: ["root.ruleSettings"], + restart: false, + reload: false, + aikariRequired: true, + restartAikari: false, + warning: true, + warningContent: '此功能与 "弹窗拦截" 等无关', + associateVal: null, + auraIf: () => true, + defaultValue: false, + valueGetter: () => { + if (!global.__HUGO_AURA__.aikariRules) return false; + return global.__HUGO_AURA__.aikariRules.deviceInfo.software + .softwareReportPost.enabled; + }, + callbackFn: (newVal) => { + if (typeof newVal !== "boolean") return; + if (!global.__HUGO_AURA__.aikariRules) return; + + global.__HUGO_AURA__.aikariRules.deviceInfo.software.softwareReportPost.enabled = + newVal; + updateAikariPLSRulesToRemote( + "deviceInfo.software.softwareReportPost.enabled", + newVal, + "deviceInfo.software.softwareReportPost" + ); + return true; + }, + }, + { + index: 1, + id: "enableSoftwareReportPostSetAsEmpty", + type: "switch", + name: "清空软件上报列表", + description: "将上报列表置空, 集控端将无法看到任何已安装应用", + reactive: true, + reactiveVal: ["root.ruleSettings"], + restart: false, + reload: false, + aikariRequired: true, + restartAikari: false, + associateVal: ["deviceInfo.software.softwareReportPost.enabled"], + auraIf: () => true, + auraDisable: () => { + if (!global.__HUGO_AURA__.aikariRules) return { value: true }; + + return { + value: + !global.__HUGO_AURA__.aikariRules.deviceInfo.software + .softwareReportPost.enabled, + }; + }, + defaultValue: true, + valueGetter: () => { + if (!global.__HUGO_AURA__.aikariRules) return true; + return global.__HUGO_AURA__.aikariRules.deviceInfo.software + .softwareReportPost.setAsEmpty; + }, + callbackFn: (newVal) => { + if (typeof newVal !== "boolean") return; + if (!global.__HUGO_AURA__.aikariRules) return; + + global.__HUGO_AURA__.aikariRules.deviceInfo.software.softwareReportPost.setAsEmpty = + newVal; + updateAikariPLSRulesToRemote( + "deviceInfo.software.softwareReportPost.setAsEmpty", + newVal, + "deviceInfo.software.softwareReportPost" + ); + return true; + }, + }, + ], + }, +]; + +module.exports = { deviceInfoPostSettings }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js deleted file mode 100755 index e4b47ce..0000000 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js +++ /dev/null @@ -1,99 +0,0 @@ -const REQUIRE_BASE = "."; - -const { - updateAikariConfigToRemote, -} = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); - -const composables = {}; - -const deviceSecuritySettings = [ - { - id: 0, - categoryName: "冰点管理", - child: [ - { - index: 0, - id: "enableFreezeInfoReportOverride", - type: "switch", - name: "启用冰冻状态篡改", - description: "篡改上报的冰冻数据, 可自定义集控端显示的状态", - reactive: true, - reactiveVal: ["root.ruleSettings"], - restart: false, - reload: false, - AikariRequired: true, - restartAikari: false, - associateVal: null, - auraIf: () => true, - defaultValue: false, - valueGetter: () => { - if (!global.__HUGO_AURA__.aikariRules) return ""; - return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo - .enable; - }, - callbackFn: (newVal) => { - if (typeof newVal !== "boolean") return; - if (!global.__HUGO_AURA__.aikariRules) return; - - global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo.enable = - newVal; - updateAikariConfigToRemote( - "ruleSettings.client.security.uploadFreezeInfo.enable", - newVal - ); - return true; - }, - }, - { - index: 1, - id: "freezeInfoReportOverrideType", - type: "radio", - name: "篡改模式", - description: - "选择一种篡改模式, 选中的磁盘范围会被上报为冻结 (不是实际行为)", - restart: false, - reload: false, - AikariRequired: true, - restartAikari: false, - reactive: true, - reactiveVal: ["root.ruleSettings"], - associateVal: ["ruleSettings.client.security.uploadFreezeInfo.enable"], - auraIf: () => { - if (!global.__HUGO_AURA__.aikariRules) return true; - - return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo - .enable; - }, - defaultValue: "allFreeze", - templates: ["allFreeze", "systemOnly", "exceptSecondDisk"], - templateLabels: ["全部冻结", "仅系统盘", "第二磁盘除外"], - valueGetter: () => { - if (!global.__HUGO_AURA__.aikariRules) return; - - return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo - .rewriteMode; - }, - callbackFn: (newVal) => { - global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo.rewriteMode = - newVal; - updateAikariConfigToRemote( - "ruleSettings.client.security.uploadFreezeInfo.rewriteMode", - newVal - ); - return true; - }, - }, - { - index: 2, - id: "freezeInfoReportOverridePreview", - type: "preview", - loaderTarget: - "Aura.UI.Assistant.Config.BehaviourCtrl.DeviceSecurity.FreezeOverridePreview", - associateVal: ["ruleSettings.client.security.uploadFreezeInfo"], - listenerType: "pls", - }, - ], - }, -]; - -module.exports = { deviceSecuritySettings }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js index ba6e765..5647bc8 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js @@ -36,8 +36,8 @@ resolve({ success: true, data: null, - status: response.status - }) + status: response.status, + }); } const parsedData = await response.json(); @@ -84,7 +84,7 @@ const diskElTemplate = document.createElement("p"); diskElTemplate.classList.add("acs-bc-dsc-fop-disk-el"); - if (!curConfig.enable) { + if (!curConfig.enabled) { for (const disk of curDisks) { const curDiskEl = diskElTemplate.cloneNode(); if (disk.status !== 0) { @@ -95,44 +95,16 @@ diskContainerEl.appendChild(curDiskEl); } } else { - switch (curConfig.rewriteMode) { - case "allFreeze": - { - for (const disk of curDisks) { - const curDiskEl = diskElTemplate.cloneNode(); - // @ts-expect-error - curDiskEl.classList.add("active"); - curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; - diskContainerEl.appendChild(curDiskEl); - } - } - break; - case "systemOnly": - { - let idx = 0; - for (const disk of curDisks) { - const curDiskEl = diskElTemplate.cloneNode(); - // @ts-expect-error - if (idx === 0) curDiskEl.classList.add("active"); - curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; - diskContainerEl.appendChild(curDiskEl); - idx += 1; - } - } - break; - case "exceptSecondDisk": - { - let idx = 0; - for (const disk of curDisks) { - const curDiskEl = diskElTemplate.cloneNode(); - // @ts-expect-error - if (idx === 0) curDiskEl.classList.add("active"); - curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; - diskContainerEl.appendChild(curDiskEl); - idx += 1; - } - } - break; + let idx = 0; + for (const disk of curDisks) { + const curDiskEl = diskElTemplate.cloneNode(); + if (curConfig.frozenDisks.includes(disk.name.toLowerCase())) { + // @ts-expect-error + curDiskEl.classList.add("active"); + } + curDiskEl.textContent = `${disk.name.toUpperCase()} 盘`; + diskContainerEl.appendChild(curDiskEl); + idx += 1; } } @@ -148,10 +120,10 @@ )[0]; const eventListener = (_event) => { - // if (!global.__HUGO_AURA__.plsRules) return; + if (!global.__HUGO_AURA__.aikariRules) return; composables.getAndUpdateDiskInfo( - // global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo - { enable: false } + global.__HUGO_AURA__.aikariRules.ssaFeatures.securityPolicies + .freezeManagement.freezeDiskInfoPost ); }; rootEl.addEventListener("onAssociateValueUpdated", eventListener);