Compare commits
8 Commits
v0.1.0-bet
...
v0.1.1-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6da8348b41 | ||
|
|
839afa79e8 | ||
|
|
7c8d3d4fbc | ||
|
|
fbc5cf1f57 | ||
|
|
a86d13431b | ||
|
|
1320f5397a | ||
|
|
fece9a8805 | ||
|
|
12f1040884 |
67
.github/ISSUE_TEMPLATE/bugReport.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: 反馈异常 / Bug Report
|
||||
description: 反馈应用中的问题, 或预期外的行为
|
||||
labels: ["Bug"]
|
||||
title: "[Bug] "
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 复现步骤 / Reproduce steps
|
||||
placeholder: |
|
||||
1. 首先, 我...
|
||||
2. 然后, 出现了...
|
||||
3. 最终...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 预期行为 / Expected behaviour
|
||||
placeholder: |
|
||||
1. 应用本来应该...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 实际行为 / Actual behaviour
|
||||
placeholder: |
|
||||
1. 事实上, 应用...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: HugoAura 版本 / HugoAura version
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: 希沃管家版本 / Seewo Services version
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: confirms
|
||||
attributes:
|
||||
label: 提交前请确认 / Confirm before submit
|
||||
options:
|
||||
- label: 我已经在 [HugoAura Issues](https://github.com/HugoAura/Seewo-HugoAura/issues) 中查询过相关关键词, 并确定此 Issue 是唯一的。
|
||||
required: true
|
||||
- label: 我已经确认, 我运行的 HugoAura 版本与希沃管家客户端版本相兼容
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 日志 / Logs
|
||||
description: 请前往 `用户文件夹/Documents/HugoAura/logs` 取得日志
|
||||
placeholder: |
|
||||
[LOG] Logger initialized. Log file: C:\...
|
||||
[LOG] [HugoAura / Loaded] Aura is loaded!
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: extraDesc
|
||||
attributes:
|
||||
label: 其他信息 (可选) / Additional info (Optional)
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
53
.github/ISSUE_TEMPLATE/featureRequest.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: 功能请求 / Feature Request
|
||||
description: 提交你想要的新功能
|
||||
labels: ["Feature"]
|
||||
title: "[Feature Request] "
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 概述 / Overview
|
||||
description: 简述你想要的新功能, 需要它做什么
|
||||
placeholder:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 背景 (可选) / Background info (Optional)
|
||||
description: 有哪些因素让你想到了这个新功能? 它为什么对用户体验至关重要?
|
||||
placeholder:
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 具体需求 / Detail Requirements
|
||||
description: 请详细描述具体希望实现哪些目标, 以及提出你认为可能的实现思路
|
||||
placeholder: |
|
||||
我希望能够实现...
|
||||
具体来讲, 包含:
|
||||
1. 实现 XXX
|
||||
2. XXXXXX
|
||||
3. XXXXXX
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: HugoAura 版本 / HugoAura version
|
||||
description: 创建此 Issue 时的最新 HugoAura 版本
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: confirms
|
||||
attributes:
|
||||
label: 提交前请确认 / Confirm before submit
|
||||
options:
|
||||
- label: 我已经在 [HugoAura Issues](https://github.com/HugoAura/Seewo-HugoAura/issues) 中查询过相关关键词, 并确定此功能请求是唯一的。
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: extraDesc
|
||||
attributes:
|
||||
label: 其他信息 (可选) / Additional info (Optional)
|
||||
20
.github/ISSUE_TEMPLATE/other.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: 其他问题 / Any Other
|
||||
description: 其他任何类型的问题
|
||||
labels: []
|
||||
title: "[Question] "
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 你的问题 / Your question
|
||||
placeholder: |
|
||||
开发者能不能 v 我 50
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: confirms
|
||||
attributes:
|
||||
label: 提交前请确认 / Confirm before submit
|
||||
options:
|
||||
- label: 请勿利用此 Issue 类型进行灌水 / 闲聊, 如果您有相关需求, 可留意后续 HugoAura 的论坛 / 用户讨论群开放情况
|
||||
required: true
|
||||
53
.gitignore
vendored
Normal file → Executable file
@@ -1,29 +1,24 @@
|
||||
# Dependencies
|
||||
|
||||
node_modules/
|
||||
.npm
|
||||
.yarn
|
||||
|
||||
# ESLint Cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# NYC Test Output
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Build Artifacts
|
||||
|
||||
/dist
|
||||
/buikd
|
||||
|
||||
# dotEnv Files
|
||||
|
||||
.env
|
||||
.env*
|
||||
|
||||
# Misc
|
||||
|
||||
.DS_Store
|
||||
*.log
|
||||
*.bak
|
||||
# SSA Defaults
|
||||
|
||||
_extraResources
|
||||
addons/
|
||||
app.asar/addons
|
||||
app.asar/assets
|
||||
app.asar/config
|
||||
app.asar/node_modules
|
||||
app.asar/public
|
||||
app.asar/main.js
|
||||
app.asar/package.json
|
||||
assets/
|
||||
|
||||
autoConfiguration.json
|
||||
|
||||
# NPM Packages
|
||||
node_modules/
|
||||
|
||||
# OS Files
|
||||
desktop.ini
|
||||
.DS_Store
|
||||
|
||||
# Editor Files
|
||||
.vscode/
|
||||
|
||||
7
README.md
Normal file → Executable file
@@ -1,18 +1,19 @@
|
||||
<center><img src="https://s2.loli.net/2025/04/18/IpZL7qMw2KFEi8o.png" /></center>
|
||||
|
||||
|
||||
<h1 align="center">HugoAura</h1>
|
||||
<h4 align="center">下一代希沃管家注入式修改方案</h4>
|
||||
<div align="center">
|
||||
<a href="https://github.com/HugoAura/HugoAura">首页</a> · <a href="https://hugoaura.org/about">关于</a> · <a href="https://github.com/HugoAura/HugoAura/wiki">文档</a> · <a href="https://github.com/HugoAura/HugoAura/issues">反馈</a>
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
> [!TIP]
|
||||
> HugoAura 的首个预览版已发布! [查看安装教程](https://github.com/HugoAura/HugoAura/wiki)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 已经过测试的希沃管家版本: v1.5.4.3824
|
||||
|
||||
## ✨ 概览
|
||||
|
||||
[天下](https://www.bilibili.com/video/BV1UN4y1k7bA) [苦希沃管家](https://www.bilibili.com/video/BV18Z421j7Lf) [久矣](https://github.com/255doesnotexist/SeewoAssistantPasswordRecovery), 如此~~好用~~的一款集控软件, 让广大电教委员对它~~爱不释手~~。
|
||||
@@ -29,8 +30,8 @@
|
||||
|
||||
- [x] 修改希沃管家密码认证组件 (自定义密码 / 解除密码 / 重设认证方式 / ...)
|
||||
- [x] 阻止希沃管家前端 Audit 上报行为
|
||||
- [x] 屏蔽屏幕锁 / 自定义屏幕锁行为
|
||||
- [ ] Aura 代理层服务 (篡改上报数据 / 欺骗冰冻状态)
|
||||
- [ ] 屏蔽屏幕锁 / 自定义屏幕锁行为
|
||||
- [ ] 窥屏提醒
|
||||
- [ ] 插件功能
|
||||
|
||||
|
||||
9
jsconfig.json
Executable file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"target": "ES2015",
|
||||
"allowImportingTsExtensions": false,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true
|
||||
}
|
||||
}
|
||||
21
package.json
Executable file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "HugoAura",
|
||||
"version": "0.1.1-pre-III",
|
||||
"description": "Aura for SeewoHugo",
|
||||
"main": "app.asar/main.js",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"electron": "^36.3.2"
|
||||
},
|
||||
"scripts": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/HugoAura/Seewo-HugoAura.git"
|
||||
},
|
||||
"author": "Minoricew",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://github.com/HugoAura/Seewo-HugoAura/issues"
|
||||
},
|
||||
"homepage": "https://github.com/HugoAura/Seewo-HugoAura"
|
||||
}
|
||||
0
scripts/cd.bat
Normal file → Executable file
0
scripts/kad.bat
Normal file → Executable file
0
scripts/kar.bat
Normal file → Executable file
80
src/aura/init/main/ipcHandler.js
Normal file → Executable file
@@ -1,10 +1,88 @@
|
||||
// @ts-check
|
||||
|
||||
const __SCOPE = "main";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("electron")} electron
|
||||
*/
|
||||
const buildIpcMain = (electron) => {
|
||||
const { app, ipcMain } = electron;
|
||||
const { app } = electron;
|
||||
/**
|
||||
* @type {import("../../types/main/electron").AuraIPCMain}
|
||||
*/
|
||||
// @ts-expect-error
|
||||
const ipcMain = electron.ipcMain;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} windowKey
|
||||
* @param {string} channel
|
||||
* @param {any} data
|
||||
* @param {import("electron").WebContents?} grep
|
||||
*/
|
||||
ipcMain.send = (windowKey, channel, data, grep = null) => {
|
||||
/**
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} chan
|
||||
* @param {any} targetData
|
||||
*/
|
||||
if (!global.__HUGO_AURA__.hookedWindows) {
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const sendDataToWebContents = (key, chan, targetData) => {
|
||||
const webContents =
|
||||
// @ts-expect-error
|
||||
global.__HUGO_AURA__.hookedWindows.get(key)?.webContents;
|
||||
|
||||
if (!webContents) {
|
||||
console.error(
|
||||
`[HugoAura / Main / IPC / ERROR] Failed sending data to ${key}: WebContents not found`
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (grep !== webContents) {
|
||||
webContents.send(chan, targetData);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
};
|
||||
|
||||
if (windowKey === "*") {
|
||||
for (const perWindow of global.__HUGO_AURA__.hookedWindows.keys()) {
|
||||
sendDataToWebContents(perWindow, channel, data);
|
||||
}
|
||||
} else {
|
||||
const isWindowValid = global.__HUGO_AURA__.hookedWindows.has(windowKey);
|
||||
if (!isWindowValid) {
|
||||
throw new Error(
|
||||
`[HugoAura / Main / IPC / ERROR] Unknown windowKey: ${windowKey}`
|
||||
);
|
||||
}
|
||||
|
||||
sendDataToWebContents(windowKey, channel, data);
|
||||
}
|
||||
};
|
||||
|
||||
const { applyConfigIpcHandler } = require("./ipcModules/configIpcHandler");
|
||||
const { applyPlsIpcHandler } = require("./ipcModules/plsIpcHandler");
|
||||
|
||||
ipcMain.handle("$aura.base.restartApplication", async () => {
|
||||
app.relaunch();
|
||||
app.exit(0);
|
||||
});
|
||||
|
||||
applyConfigIpcHandler(ipcMain);
|
||||
applyPlsIpcHandler(ipcMain);
|
||||
};
|
||||
|
||||
module.exports = { buildIpcMain };
|
||||
|
||||
79
src/aura/init/main/ipcModules/configIpcHandler.js
Executable file
@@ -0,0 +1,79 @@
|
||||
// @ts-check
|
||||
|
||||
const __SCOPE = "main";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../../../types/main/electron").AuraIPCMain} ipcMain
|
||||
*/
|
||||
const applyConfigIpcHandler = (ipcMain) => {
|
||||
const methodBase = "$aura.config";
|
||||
|
||||
const mainEventBus = global.__HUGO_AURA_EVENT_BUS__;
|
||||
|
||||
const ConfigManager = require("../../shared/configManager");
|
||||
const configManager = global.__HUGO_AURA_CONFIG_MGR__
|
||||
? global.__HUGO_AURA_CONFIG_MGR__
|
||||
: new ConfigManager();
|
||||
|
||||
ipcMain.on(`${methodBase}.refreshMainConfig`, (_event) => {
|
||||
mainEventBus.emit("$aura.config.refreshConfig");
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.setConfigEncSettings`,
|
||||
(
|
||||
/** @type {import("electron").IpcMainInvokeEvent} */ _event,
|
||||
/** @type {{ target: boolean }} */ arg
|
||||
) => {
|
||||
mainEventBus.emit("$aura.config.updateConfigEncSettings", arg.target);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.on(`${methodBase}.getConfigFromMainSync`, (event, _arg) => {
|
||||
if (
|
||||
global.__HUGO_AURA_CONFIG__ &&
|
||||
Object.keys(global.__HUGO_AURA_CONFIG__).length !== 0
|
||||
) {
|
||||
event.returnValue = {
|
||||
success: true,
|
||||
data: global.__HUGO_AURA_CONFIG__,
|
||||
};
|
||||
} else {
|
||||
console.warn(
|
||||
"[HugoAura / Main / IPC / Config / WARN] Global config var not found!"
|
||||
);
|
||||
event.returnValue = {
|
||||
success: false,
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.dispatchConfigFromRenderer`,
|
||||
(_event, /** @type {{data: string, writeConfig?: boolean}} */ arg) => {
|
||||
const parsedData = JSON.parse(arg.data);
|
||||
|
||||
global.__HUGO_AURA_CONFIG__ = parsedData;
|
||||
|
||||
if (arg.writeConfig) {
|
||||
const result = configManager.writeConfig(parsedData);
|
||||
if (!result) {
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = { applyConfigIpcHandler };
|
||||
235
src/aura/init/main/ipcModules/plsIpcHandler.js
Executable file
@@ -0,0 +1,235 @@
|
||||
// @ts-check
|
||||
|
||||
const __SCOPE = "main";
|
||||
|
||||
const os = require("os");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../../../types/main/electron").AuraIPCMain} ipcMain
|
||||
*/
|
||||
const applyPlsIpcHandler = (ipcMain) => {
|
||||
const methodBase = "$aura.pls";
|
||||
|
||||
const isPlsDetached = process.argv.includes("--pls-detach");
|
||||
|
||||
global.__HUGO_AURA__.plsStats = {
|
||||
installed: false,
|
||||
launched: false,
|
||||
detached: isPlsDetached,
|
||||
connected: false,
|
||||
version: "未知",
|
||||
status: "dead",
|
||||
authToken: global.__HUGO_AURA_CONFIG__.plsToken,
|
||||
};
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.getPlsFolderExists`,
|
||||
/**
|
||||
*
|
||||
* @returns {{ success: boolean; data: { isExists: boolean }; error?: Error }}
|
||||
*/
|
||||
(_event, _arg) => {
|
||||
const plsFolderPath = path.join("C:\\Program Files", "HugoAura PLS");
|
||||
try {
|
||||
const result = fs.existsSync(plsFolderPath);
|
||||
return {
|
||||
success: true,
|
||||
data: { isExists: result },
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
success: false,
|
||||
data: { isExists: false },
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.getPlsStats`,
|
||||
/**
|
||||
*
|
||||
* @returns {{ success: boolean; data: import("../../../types/shared/pls/status").PLSStatus | null | undefined; }}
|
||||
*/
|
||||
(_event, _arg) => {
|
||||
return {
|
||||
success: true,
|
||||
data: global.__HUGO_AURA__.plsStats,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.updatePlsStats`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {import("../../../types/shared/pls/status").PLSStatus} arg
|
||||
* @returns
|
||||
*/
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsStats = arg;
|
||||
ipcMain.send("assistant", `${methodBase}.post.onPlsStatsUpdate`, arg);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.getPlsSettings`,
|
||||
/**
|
||||
*
|
||||
* @returns {{ success: boolean; data: Record<any, any> | null | undefined }}
|
||||
*/
|
||||
(_event, _arg) => {
|
||||
return {
|
||||
success: true,
|
||||
data: global.__HUGO_AURA__.plsSettings,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.updatePlsSettings`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {Record<any, any>} arg
|
||||
* @returns
|
||||
*/
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsSettings = arg;
|
||||
ipcMain.send("assistant", `${methodBase}.post.onPlsSettingsUpdate`, arg);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.getPlsRules`,
|
||||
/**
|
||||
*
|
||||
* @returns {{ success: boolean; data: Record<any, any> | null | undefined }}
|
||||
*/
|
||||
(_event, _arg) => {
|
||||
return {
|
||||
success: true,
|
||||
data: global.__HUGO_AURA__.plsRules,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.updatePlsRules`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {Record<any, any>} arg
|
||||
* @returns
|
||||
*/
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsRules = arg;
|
||||
ipcMain.send("assistant", `${methodBase}.post.onPlsRulesUpdate`, arg);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.on(
|
||||
`${methodBase}.ws.broadcastMessageRecv`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainEvent} _event
|
||||
* @param {PLSResponse} arg
|
||||
*/
|
||||
(_event, arg) => {
|
||||
ipcMain.send("assistant", `${methodBase}.ws.post.onNewMsgRecv`, arg);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.ws.sendWsMessage`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {ClientPLSRequest} arg
|
||||
*/
|
||||
(_event, arg) => {
|
||||
ipcMain.send(
|
||||
"desktopAssistant",
|
||||
`${methodBase}.ws.post.onReqSendMsg`,
|
||||
arg
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.syncPlsConfig`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} event
|
||||
* @param {{ basic: Record<any, any>, rules: Record<any, any> }} arg
|
||||
*/
|
||||
(event, arg) => {
|
||||
global.__HUGO_AURA__.plsRules = arg.rules;
|
||||
global.__HUGO_AURA__.plsSettings = arg.basic;
|
||||
|
||||
ipcMain.send("*", `${methodBase}.syncPlsConfig`, arg, event.sender);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.retryPlsConnect`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {any} arg
|
||||
* @returns {{ success: boolean, status: "Already" | "Retrying" }}
|
||||
*/
|
||||
(_event, arg) => {
|
||||
if (global.__HUGO_AURA__.plsStats?.connected) {
|
||||
return {
|
||||
success: true,
|
||||
status: "Already",
|
||||
};
|
||||
} else {
|
||||
ipcMain.send("desktopAssistant", `${methodBase}.retryPlsConnect`, arg);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: "Retrying",
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
`${methodBase}.post.updateRetryStatus`,
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcMainInvokeEvent} _event
|
||||
* @param {{ success: boolean }} arg
|
||||
*/
|
||||
(_event, arg) => {
|
||||
ipcMain.send("assistant", `${methodBase}.post.updateRetryStatus`, arg);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = { applyPlsIpcHandler };
|
||||
79
src/aura/init/main/windowHooksManager.js
Executable file
@@ -0,0 +1,79 @@
|
||||
// @ts-check
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
class WindowHooksManager {
|
||||
loadHooks() {
|
||||
if (
|
||||
global.__HUGO_AURA__.windowHooks &&
|
||||
Object.keys(global.__HUGO_AURA__.windowHooks).length !== 0
|
||||
) {
|
||||
return global.__HUGO_AURA__.windowHooks;
|
||||
}
|
||||
|
||||
const hooksPath = path.join(__dirname, "../../../aura/mainProcess/hooks");
|
||||
|
||||
/** @type {import("../../types/main/core").HooksMap} */
|
||||
const hooks = new Map();
|
||||
|
||||
try {
|
||||
const files = fs.readdirSync(hooksPath);
|
||||
files.forEach((file) => {
|
||||
if (!file.endsWith(".js")) return;
|
||||
|
||||
try {
|
||||
const hook = require(path.join(hooksPath, file));
|
||||
/** @type {import("../../types/main/core").WindowName} */
|
||||
const targetWindow = hook.windowName || path.basename(file, ".js");
|
||||
hooks.set(targetWindow, hook);
|
||||
console.log(
|
||||
`[HugoAura / Init / WDH] Loaded main process hook for window: ${targetWindow}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`[HugoAura / Init / WDH / Error] Failed to load main process hook ${file}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Init / WDH / Error] Failed to read hooks directory:",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
global.__HUGO_AURA__.windowHooks = hooks;
|
||||
return hooks;
|
||||
}
|
||||
|
||||
initHookForWindow(
|
||||
windowName,
|
||||
centralIns,
|
||||
mainProcessAppInstance,
|
||||
browserWindowInstance
|
||||
) {
|
||||
const stripWindowName = windowName.split("_")[0];
|
||||
if (!global.__HUGO_AURA__.windowHooks.has(stripWindowName)) {
|
||||
console.log(
|
||||
`[HugoAura / Init / WDH] Window ${windowName} has no corresponding main process hooks, ignoring...`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const { hookFunc } = global.__HUGO_AURA__.windowHooks.get(stripWindowName);
|
||||
hookFunc(
|
||||
centralIns,
|
||||
mainProcessAppInstance,
|
||||
browserWindowInstance,
|
||||
windowName
|
||||
);
|
||||
|
||||
console.log(
|
||||
`[HugoAura / Init / WDH / Success / ${windowName}] Main process hook initialized.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WindowHooksManager;
|
||||
20
src/aura/init/preload/webpackHook.js
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
const path = require('path');
|
||||
const path = require("path");
|
||||
|
||||
class WebpackHook {
|
||||
#ruleCache = new Map();
|
||||
@@ -19,7 +19,7 @@ class WebpackHook {
|
||||
if (!rule) {
|
||||
rule = require(path.join(
|
||||
__dirname,
|
||||
'../../../aura/jsRewrite/',
|
||||
"../../../aura/jsRewrite/",
|
||||
rulePath
|
||||
));
|
||||
this.#ruleCache.set(rulePath, rule);
|
||||
@@ -49,7 +49,7 @@ class WebpackHook {
|
||||
|
||||
patchModules(modules, rewrites) {
|
||||
modules.forEach((mod, index) => {
|
||||
if (typeof mod !== 'function') return;
|
||||
if (typeof mod !== "function") return;
|
||||
const stringifyFunc = mod.toString();
|
||||
|
||||
rewrites.forEach((rewrite) => {
|
||||
@@ -67,14 +67,14 @@ class WebpackHook {
|
||||
let rewrittenFunction = mod;
|
||||
|
||||
switch (method) {
|
||||
case 'reactComponent':
|
||||
case "reactComponent":
|
||||
window.__HUGO_AURA_HOOK__[ruleId] = {
|
||||
feature: rewrite.feature,
|
||||
newFunction: rewrite.newFunction
|
||||
}
|
||||
newFunction: rewrite.newFunction,
|
||||
};
|
||||
rewrittenFunction = rewrite.preHook(mod);
|
||||
break;
|
||||
case 'legacy':
|
||||
case "legacy":
|
||||
default:
|
||||
rewrittenFunction = rewrite.newFunction;
|
||||
break;
|
||||
@@ -95,7 +95,7 @@ class WebpackHook {
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
if (typeof window !== "undefined") {
|
||||
window.__HUGO_AURA_DEBUG__ = {
|
||||
getRuleCache: () => Array.from(this.#ruleCache.keys()),
|
||||
};
|
||||
@@ -105,7 +105,7 @@ class WebpackHook {
|
||||
installHook(window, config) {
|
||||
let realWebpackJsonp = window.webpackJsonp;
|
||||
|
||||
Object.defineProperty(window, 'webpackJsonp', {
|
||||
Object.defineProperty(window, "webpackJsonp", {
|
||||
get: () => realWebpackJsonp,
|
||||
set: (value) => {
|
||||
console.log(
|
||||
@@ -119,7 +119,7 @@ class WebpackHook {
|
||||
if (args[0] && Array.isArray(args[0][1])) {
|
||||
const [chunkIds, modules] = args[0];
|
||||
console.log(
|
||||
`[HugoAura / AppHook] Intercepting chunk ${chunkIds.join(', ')}`
|
||||
`[HugoAura / AppHook] Intercepting chunk ${chunkIds.join(", ")}`
|
||||
);
|
||||
|
||||
const rewrites = this.loadRewriteRules(config);
|
||||
|
||||
0
src/aura/init/rendererHook/injection.js
Normal file → Executable file
0
src/aura/init/rendererHook/networkHook.js
Normal file → Executable file
66
src/aura/init/rendererHook/hooksManager.js → src/aura/init/rendererHook/uiHooksManager.js
Normal file → Executable file
@@ -1,13 +1,20 @@
|
||||
// @ts-check
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
class HooksManager {
|
||||
class RendererHooksManager {
|
||||
loadHooks() {
|
||||
if (global.__HUGO_AURA__.hooks) {
|
||||
return global.__HUGO_AURA__.hooks;
|
||||
if (
|
||||
global.__HUGO_AURA__.uiHooks &&
|
||||
Object.keys(global.__HUGO_AURA__.uiHooks).length !== 0
|
||||
) {
|
||||
return global.__HUGO_AURA__.uiHooks;
|
||||
}
|
||||
|
||||
const hooksPath = path.join(__dirname, "../../../aura/ui/hooks");
|
||||
const hooksPath = path.join(__dirname, "../../../aura/ui/hookDefinitions");
|
||||
|
||||
/** @type {import("../../types/main/core").HooksMap} */
|
||||
const hooks = new Map();
|
||||
|
||||
try {
|
||||
@@ -17,36 +24,43 @@ class HooksManager {
|
||||
|
||||
try {
|
||||
const hook = require(path.join(hooksPath, file));
|
||||
/** @type {import("../../types/main/core").WindowName} */
|
||||
const targetWindow = hook.windowName || path.basename(file, ".js");
|
||||
hooks.set(targetWindow, hook);
|
||||
console.log(
|
||||
`[HugoAura / Init] Loaded hook for window: ${targetWindow}`
|
||||
`[HugoAura / Init / RDH] Loaded ui hook for window: ${targetWindow}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`[HugoAura / Init / Error] Failed to load hook ${file}:`,
|
||||
`[HugoAura / Init / RDH / Error] Failed to load ui hook ${file}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Init / Error] Failed to read hooks directory:",
|
||||
"[HugoAura / Init / RDH / Error] Failed to ui hooks directory:",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
global.__HUGO_AURA__.hooks = hooks;
|
||||
global.__HUGO_AURA__.uiHooks = hooks;
|
||||
return hooks;
|
||||
}
|
||||
|
||||
cleanupWindow(windowKey, listeners) {
|
||||
/**
|
||||
*
|
||||
* @param {import("../../types/main/core").WindowName} windowKey
|
||||
* @param {import("../../types/main/core").HookedWindow} hookedWindowProps
|
||||
*/
|
||||
cleanupWindow(windowKey, hookedWindowProps) {
|
||||
console.log(
|
||||
`[HugoAura / Cleanup / ${windowKey}] Window destroyed, cleaning up...`
|
||||
`[HugoAura / Cleanup / RDH / ${windowKey}] Window destroyed, cleaning up...`
|
||||
);
|
||||
|
||||
if (listeners) {
|
||||
const { webContents, domReadyListener, destroyedListener } = listeners;
|
||||
if (hookedWindowProps) {
|
||||
const { webContents, domReadyListener, destroyedListener } =
|
||||
hookedWindowProps;
|
||||
webContents.removeListener("dom-ready", domReadyListener);
|
||||
webContents.removeListener("destroyed", destroyedListener);
|
||||
}
|
||||
@@ -54,26 +68,36 @@ class HooksManager {
|
||||
global.__HUGO_AURA__.hookedWindows.delete(windowKey);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").WebContents} webContents
|
||||
* @param {import("../../types/render/uiHook").UIHookConfigFin} hookConfig
|
||||
* @param {import("../../types/main/core").WindowName} windowName
|
||||
* @returns
|
||||
*/
|
||||
handleWindowHook(webContents, hookConfig, windowName) {
|
||||
if (!hookConfig) return;
|
||||
|
||||
/** @type {import("../../types/main/core").WindowName} */
|
||||
const windowKey = `${hookConfig.windowName || windowName}`;
|
||||
if (global.__HUGO_AURA__.hookedWindows.has(windowKey)) {
|
||||
console.log(
|
||||
`[HugoAura / Init] Duplicate hook for ${windowKey}, ignoring...`
|
||||
`[HugoAura / Init / RDH] Duplicate ui hook for ${windowKey}, ignoring...`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[HugoAura / Init] Hook is initializing for ${windowKey}...`);
|
||||
console.log(
|
||||
`[HugoAura / Init] Hook loaded at: ${new Date().toISOString()}`
|
||||
`[HugoAura / Init / RDH] UI Hook is initializing for ${windowKey}...`
|
||||
);
|
||||
console.log(
|
||||
`[HugoAura / Init / RDH] UI Hook loaded at: ${new Date().toISOString()}`
|
||||
);
|
||||
|
||||
const domReadyListener = () => {
|
||||
try {
|
||||
console.log(
|
||||
`[HugoAura / UI / Verb / ${windowKey}] Loading injection script...`
|
||||
`[HugoAura / RDH / Verb / ${windowKey}] Loading injection script...`
|
||||
);
|
||||
|
||||
const injectionScript = fs
|
||||
@@ -93,18 +117,18 @@ class HooksManager {
|
||||
.executeJavaScript(injectionScript, true)
|
||||
.then(() =>
|
||||
console.log(
|
||||
`[HugoAura / UI / Done / ${windowKey}] Injection script executed`
|
||||
`[HugoAura / RDH / Done / ${windowKey}] Injection script executed`
|
||||
)
|
||||
)
|
||||
.catch((err) =>
|
||||
console.error(
|
||||
`[HugoAura / UI / Error / ${windowKey}] Failed to execute injection script:`,
|
||||
`[HugoAura / RDH / Error / ${windowKey}] Failed to execute injection script:`,
|
||||
err
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`[HugoAura / UI / Error / ${windowKey}] Failed to load UI hook:`,
|
||||
`[HugoAura / RDH / Error / ${windowKey}] Failed to load UI hook:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
@@ -127,9 +151,9 @@ class HooksManager {
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[HugoAura / Init / Success / ${windowKey}] Hook initialized successfully!`
|
||||
`[HugoAura / Init / RDH / Success / ${windowKey}] UI Hook initialized.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HooksManager;
|
||||
module.exports = RendererHooksManager;
|
||||
599
src/aura/init/shared/configManager.js
Normal file → Executable file
@@ -1,11 +1,38 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
// @ts-check
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
const crypto = require("crypto");
|
||||
const childProc = require("child_process");
|
||||
|
||||
const RegistryManagerClass = require("./registryManager");
|
||||
const registryManager = new RegistryManagerClass();
|
||||
|
||||
// Constants
|
||||
|
||||
const CRYPTO_SETTINGS_AES = {
|
||||
mode: "aes-256-gcm",
|
||||
keyLength: 32,
|
||||
keyIter: 100000,
|
||||
ivLength: 12,
|
||||
tagLength: 16,
|
||||
saltLength: 16,
|
||||
obfuscateStr: "eCybsseK",
|
||||
hash: "sha256",
|
||||
};
|
||||
const LMAK_SETTINGS_BASE = "EncSettings\\LMAK";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Record<any, any>} target
|
||||
* @param {Record<any, any>} source
|
||||
* @returns
|
||||
*/
|
||||
const deepMerge = (target, source) => {
|
||||
const result = JSON.parse(JSON.stringify(target));
|
||||
|
||||
if (!source || typeof source !== 'object') {
|
||||
if (!source || typeof source !== "object") {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -15,9 +42,9 @@ const deepMerge = (target, source) => {
|
||||
if (!(key in source)) {
|
||||
keysToDelete.push(key);
|
||||
} else if (
|
||||
typeof result[key] === 'object' &&
|
||||
typeof result[key] === "object" &&
|
||||
result[key] !== null &&
|
||||
typeof source[key] === 'object' &&
|
||||
typeof source[key] === "object" &&
|
||||
source[key] !== null
|
||||
) {
|
||||
result[key] = deepMerge(result[key], source[key]);
|
||||
@@ -42,29 +69,48 @@ const deepMerge = (target, source) => {
|
||||
|
||||
class ConfigManager {
|
||||
constructor() {
|
||||
this.configPath = path.join(
|
||||
os.homedir(),
|
||||
'Documents',
|
||||
'HugoAura',
|
||||
'config.json'
|
||||
);
|
||||
this.defaultConfigPath = path.join(__dirname, 'default.json');
|
||||
this.configDir = path.join(os.homedir(), "Documents", "HugoAura");
|
||||
this.configPath = path.join(this.configDir, "config.json");
|
||||
this.encConfigPath = path.join(this.configDir, ".cache_2eafc8d0.dat"); // (雾
|
||||
/* ↑ 不使用 .tmp 扩展名, 不然容易真被清理了 */
|
||||
this.defaultConfigPath = path.join(__dirname, "default.json");
|
||||
this.useEncConfig = false;
|
||||
this.isConfigReadFailed = false;
|
||||
this.side = "unknown";
|
||||
|
||||
if (fs.existsSync(this.configPath)) {
|
||||
this.useEncConfig = false;
|
||||
} else {
|
||||
this.useEncConfig = true;
|
||||
}
|
||||
|
||||
if (global.__HUGO_AURA_EVENT_BUS__) {
|
||||
// Expect always true
|
||||
global.__HUGO_AURA_EVENT_BUS__.on(
|
||||
"$aura.config.updateConfigEncSettings",
|
||||
(/** @type {boolean} */ newVal) => {
|
||||
this.useEncConfig = newVal;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getHugoAuraConfigPath() {
|
||||
return path.dirname(this.configPath);
|
||||
return path.dirname(
|
||||
this.useEncConfig ? this.encConfigPath : this.configPath
|
||||
);
|
||||
}
|
||||
|
||||
getConfigPath() {
|
||||
return this.configPath;
|
||||
return this.useEncConfig ? this.encConfigPath : this.configPath;
|
||||
}
|
||||
|
||||
getDefaultConfig() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(this.defaultConfigPath, 'utf8'));
|
||||
return JSON.parse(fs.readFileSync(this.defaultConfigPath, "utf8"));
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
'[HugoAura / Config] No default config found, using empty config'
|
||||
"[HugoAura / Config] No default config found, using empty config"
|
||||
);
|
||||
return { rewrite: {} };
|
||||
}
|
||||
@@ -74,12 +120,12 @@ class ConfigManager {
|
||||
if (global.__HUGO_AURA__.configInit) return;
|
||||
const hugoAuraPath = this.getHugoAuraConfigPath();
|
||||
if (!fs.existsSync(hugoAuraPath)) {
|
||||
console.log('[HugoAura / Config] Creating HugoAura directory');
|
||||
console.log("[HugoAura / Config] Creating HugoAura directory");
|
||||
fs.mkdirSync(hugoAuraPath, { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(this.configPath)) {
|
||||
console.log('[HugoAura / Config] Creating default config file');
|
||||
if (!fs.existsSync(this.configPath) && !fs.existsSync(this.encConfigPath)) {
|
||||
console.log("[HugoAura / Config] Creating default config file");
|
||||
const defaultConfig = this.getDefaultConfig();
|
||||
this.writeConfig(defaultConfig);
|
||||
}
|
||||
@@ -87,25 +133,66 @@ class ConfigManager {
|
||||
|
||||
readConfig() {
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(this.configPath, 'utf8'));
|
||||
console.log('[HugoAura / Config] Successfully loaded config:', config);
|
||||
let config = {};
|
||||
if (this.useEncConfig) {
|
||||
const hashedPasswdResultObj = this.retrieveEncPassword();
|
||||
if (hashedPasswdResultObj.success && hashedPasswdResultObj.data) {
|
||||
config = this.decryptConfig(hashedPasswdResultObj.data).data;
|
||||
|
||||
if (!config) {
|
||||
this.isConfigReadFailed = true;
|
||||
return this.getDefaultConfig(); // should be changed, too
|
||||
}
|
||||
} else {
|
||||
console.error("[HugoAura / Config / ERROR] Failed to decrypt config");
|
||||
this.isConfigReadFailed = true;
|
||||
return this.getDefaultConfig(); // This behaviour should be changed later
|
||||
}
|
||||
} else {
|
||||
config = JSON.parse(fs.readFileSync(this.configPath, "utf8"));
|
||||
}
|
||||
// console.log("[HugoAura / Config] Successfully loaded config:", config);
|
||||
if (this.isConfigReadFailed) this.isConfigReadFailed = false;
|
||||
return config;
|
||||
} catch (err) {
|
||||
console.error('[HugoAura / Config] Failed to read config:', err);
|
||||
console.error("[HugoAura / Config] Failed to read config:", err);
|
||||
this.isConfigReadFailed = true;
|
||||
return this.getDefaultConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Record<any, any>} config
|
||||
* @returns {boolean}
|
||||
*/
|
||||
writeConfig(config) {
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
this.configPath,
|
||||
JSON.stringify(config, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
if (this.useEncConfig) {
|
||||
const hashedPasswdResultObj = this.retrieveEncPassword();
|
||||
if (hashedPasswdResultObj.success && hashedPasswdResultObj.data) {
|
||||
this.encryptConfig(config, hashedPasswdResultObj.data);
|
||||
} else {
|
||||
console.error(
|
||||
"[HugoAura / Config / Write / ERROR] Failed to write config: Retrieve enc password failed"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(
|
||||
this.configPath,
|
||||
JSON.stringify(config, null, 2),
|
||||
"utf8"
|
||||
);
|
||||
}
|
||||
|
||||
if (this.side === "renderer") {
|
||||
global.ipcRenderer.send("$aura.config.refreshMainConfig");
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('[HugoAura / Config] Failed to write config:', err);
|
||||
console.error("[HugoAura / Config] Failed to write config:", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -114,24 +201,468 @@ class ConfigManager {
|
||||
let defaultConfig = this.getDefaultConfig();
|
||||
let config = {};
|
||||
try {
|
||||
if (fs.existsSync(this.configPath)) {
|
||||
const userConfig = JSON.parse(fs.readFileSync(this.configPath, 'utf8'));
|
||||
if (fs.existsSync(this.configPath) || fs.existsSync(this.encConfigPath)) {
|
||||
const userConfig = this.readConfig();
|
||||
if (global.__HUGO_AURA__.configInit) {
|
||||
config = userConfig;
|
||||
return userConfig;
|
||||
} else {
|
||||
config = deepMerge(userConfig, defaultConfig);
|
||||
console.log('[HugoAura / Config] Merged with user config');
|
||||
console.log("[HugoAura / Config] Merged with user config");
|
||||
this.writeConfig(config);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[HugoAura / Config] Failed to load user config:', err);
|
||||
console.error("[HugoAura / Config] Failed to load user config:", err);
|
||||
this.isConfigReadFailed = true;
|
||||
config = defaultConfig;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
priv_getMacAddr() {
|
||||
const netInf = os.networkInterfaces();
|
||||
const realInfs = Object.keys(netInf).filter(
|
||||
(key) =>
|
||||
!key.includes("Pseudo") &&
|
||||
!key.includes("Loopback") &&
|
||||
!key.includes("Virtual") &&
|
||||
!key.includes("Tunnel") &&
|
||||
!key.includes("Cisco") &&
|
||||
!key.includes("VPN")
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string[]} infNames
|
||||
* @param {Record<string, any>} infObj
|
||||
* @returns
|
||||
*/
|
||||
const getValidInfMac = (infNames, infObj) => {
|
||||
for (const name of infNames) {
|
||||
const target = infObj[name][0];
|
||||
const isValid = !target.internal && target.mac !== "00:00:00:00:00:00";
|
||||
if (isValid) {
|
||||
return target.mac;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const rawInfMac = getValidInfMac(realInfs, netInf);
|
||||
const macAddr = rawInfMac
|
||||
? rawInfMac.replace(/:/g, "").toUpperCase()
|
||||
: null;
|
||||
return macAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {SHA256EncryptedPassword} password
|
||||
*/
|
||||
saveEncPassword(password) {
|
||||
let macAddr = this.priv_getMacAddr();
|
||||
let fallbackToStaticKey = false;
|
||||
|
||||
if (!macAddr) {
|
||||
console.warn(
|
||||
"[HugoAura / Config / LMK] No valid network inf found, fallback to static key."
|
||||
);
|
||||
macAddr = Buffer.from(crypto.randomBytes(6))
|
||||
.toString("hex")
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
const randomSalt = crypto.randomBytes(CRYPTO_SETTINGS_AES.saltLength);
|
||||
const key = crypto.scryptSync(macAddr, randomSalt, 32);
|
||||
const iv = crypto.randomBytes(CRYPTO_SETTINGS_AES.ivLength);
|
||||
|
||||
const cipherIns = crypto.createCipheriv(CRYPTO_SETTINGS_AES.mode, key, iv, {
|
||||
// @ts-expect-error
|
||||
authTagLength: CRYPTO_SETTINGS_AES.tagLength,
|
||||
});
|
||||
|
||||
let encryptedPassword = cipherIns.update(password, "utf-8", "hex");
|
||||
encryptedPassword += cipherIns.final("hex");
|
||||
|
||||
const authTagHex = cipherIns.getAuthTag().toString("hex");
|
||||
const ivHex = iv.toString("hex");
|
||||
const saltHex = randomSalt.toString("hex");
|
||||
|
||||
registryManager.createOrUpdateRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_Value",
|
||||
encryptedPassword,
|
||||
true
|
||||
);
|
||||
registryManager.createOrUpdateRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_IV",
|
||||
ivHex,
|
||||
true
|
||||
);
|
||||
registryManager.createOrUpdateRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_Salt",
|
||||
saltHex,
|
||||
true
|
||||
);
|
||||
registryManager.createOrUpdateRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_AuthTag",
|
||||
authTagHex,
|
||||
true
|
||||
);
|
||||
|
||||
if (fallbackToStaticKey) {
|
||||
registryManager.createOrUpdateRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_FakeMac",
|
||||
macAddr,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
retrieveEncPassword() {
|
||||
try {
|
||||
const authTagHex = registryManager.readRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_AuthTag",
|
||||
true
|
||||
)?.data;
|
||||
const ivHex = registryManager.readRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_IV",
|
||||
true
|
||||
)?.data;
|
||||
const saltHex = registryManager.readRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_Salt",
|
||||
true
|
||||
)?.data;
|
||||
const encPasswdHex = registryManager.readRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_Value",
|
||||
true
|
||||
)?.data;
|
||||
let isStaticKey = false;
|
||||
let macAddr = null;
|
||||
|
||||
try {
|
||||
macAddr = registryManager.readRegKey(
|
||||
LMAK_SETTINGS_BASE,
|
||||
"LMAK_FakeMac",
|
||||
true
|
||||
)?.data;
|
||||
if (!macAddr) {
|
||||
isStaticKey = false;
|
||||
} else {
|
||||
isStaticKey = true;
|
||||
}
|
||||
} catch {
|
||||
isStaticKey = false;
|
||||
}
|
||||
|
||||
if (!isStaticKey) {
|
||||
macAddr = this.priv_getMacAddr();
|
||||
|
||||
if (!macAddr) {
|
||||
console.error(
|
||||
"[HugoAura / Config / ERROR] Failed to retrieve password from reg: MAC Address invalid."
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
error: new Error("Mac is null or undefined"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!saltHex || !ivHex || !authTagHex || !encPasswdHex) {
|
||||
console.error(
|
||||
"[HugoAura / Config / ERROR] Failed to retrieve password from reg: Reg keys invalid."
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
error: new Error("Reg key invalid"),
|
||||
};
|
||||
}
|
||||
const salt = Buffer.from(saltHex, "hex");
|
||||
const iv = Buffer.from(ivHex, "hex");
|
||||
const authTag = Buffer.from(authTagHex, "hex");
|
||||
const encPasswd = Buffer.from(encPasswdHex, "utf-8").toString();
|
||||
|
||||
const key = crypto.scryptSync(macAddr, salt, 32);
|
||||
const decipherIns = crypto.createDecipheriv(
|
||||
CRYPTO_SETTINGS_AES.mode,
|
||||
key,
|
||||
iv,
|
||||
{
|
||||
// @ts-expect-error
|
||||
authTagLength: CRYPTO_SETTINGS_AES.tagLength,
|
||||
}
|
||||
);
|
||||
|
||||
decipherIns.setAuthTag(authTag);
|
||||
|
||||
const result = Buffer.concat([
|
||||
decipherIns.update(encPasswd, "hex"),
|
||||
decipherIns.final(),
|
||||
]).toString();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: result,
|
||||
error: null,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[HugoAura / Config / ERROR] Unexpected error occurred while retrieving password from reg, error:",
|
||||
e
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
clearEncPasswdRegKey() {
|
||||
registryManager.delRegKey(LMAK_SETTINGS_BASE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Record<any, any>} configData
|
||||
* @param {SHA256EncryptedPassword} passwd
|
||||
*/
|
||||
encryptConfig(configData, passwd) {
|
||||
registryManager.initRegistry();
|
||||
const salt = crypto.randomBytes(CRYPTO_SETTINGS_AES.saltLength);
|
||||
const key = crypto.pbkdf2Sync(
|
||||
passwd,
|
||||
salt,
|
||||
CRYPTO_SETTINGS_AES.keyIter,
|
||||
CRYPTO_SETTINGS_AES.keyLength,
|
||||
CRYPTO_SETTINGS_AES.hash
|
||||
);
|
||||
const iv = crypto.randomBytes(CRYPTO_SETTINGS_AES.ivLength);
|
||||
|
||||
const cipherIns = crypto.createCipheriv(CRYPTO_SETTINGS_AES.mode, key, iv, {
|
||||
// @ts-expect-error
|
||||
authTagLength: CRYPTO_SETTINGS_AES.tagLength,
|
||||
});
|
||||
|
||||
const stringifyConfigData = JSON.stringify(configData);
|
||||
let encryptedCfg = cipherIns.update(stringifyConfigData, "utf-8", "hex");
|
||||
encryptedCfg += cipherIns.final("hex");
|
||||
const authTag = cipherIns.getAuthTag();
|
||||
|
||||
/** @type {EncryptedConfig} */
|
||||
const encConfigFinal = {};
|
||||
encConfigFinal.content = encryptedCfg;
|
||||
encConfigFinal.authTag = authTag.toString("base64");
|
||||
encConfigFinal.salt = salt.toString("base64");
|
||||
encConfigFinal.iv = iv.toString("base64");
|
||||
|
||||
const base64EncConfig =
|
||||
CRYPTO_SETTINGS_AES.obfuscateStr +
|
||||
Buffer.from(JSON.stringify(encConfigFinal)).toString("base64");
|
||||
|
||||
try {
|
||||
fs.writeFileSync(this.encConfigPath, base64EncConfig, "utf-8");
|
||||
try {
|
||||
fs.unlinkSync(this.configPath);
|
||||
} catch {
|
||||
console.debug("[HugoAura / Config] Dec config not exists, skipping...");
|
||||
}
|
||||
|
||||
if (!this.useEncConfig) this.useEncConfig = true;
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Failed to write encrypted config:",
|
||||
err
|
||||
);
|
||||
console.error(
|
||||
"[HugoAura / Config] Pending config data:",
|
||||
base64EncConfig
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {SHA256EncryptedPassword} passwd
|
||||
* @returns {{success: boolean, data: AuraConfig}}
|
||||
*/
|
||||
decryptConfig(passwd) {
|
||||
try {
|
||||
const FAILED_RET = {
|
||||
success: false,
|
||||
data: {},
|
||||
};
|
||||
|
||||
let base64EncConfig = null;
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(this.encConfigPath)) {
|
||||
return FAILED_RET;
|
||||
}
|
||||
base64EncConfig = fs.readFileSync(this.encConfigPath, "utf-8");
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Failed to read encrypted config:",
|
||||
err
|
||||
);
|
||||
return FAILED_RET;
|
||||
}
|
||||
|
||||
if (base64EncConfig) {
|
||||
const strip64EncCfg = base64EncConfig.split(
|
||||
CRYPTO_SETTINGS_AES.obfuscateStr
|
||||
)[1];
|
||||
const encryptCfg = Buffer.from(strip64EncCfg, "base64").toString(
|
||||
"utf-8"
|
||||
);
|
||||
/** @type {null | EncryptedConfig} */
|
||||
let parsedEncCfg = null;
|
||||
try {
|
||||
parsedEncCfg = JSON.parse(encryptCfg);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Failed to parse encrypted config:",
|
||||
err
|
||||
);
|
||||
console.error("[HugoAura / Config] Pending data:", encryptCfg);
|
||||
}
|
||||
if (parsedEncCfg === null) return FAILED_RET;
|
||||
|
||||
const salt = Buffer.from(parsedEncCfg.salt, "base64");
|
||||
const iv = Buffer.from(parsedEncCfg.iv, "base64");
|
||||
|
||||
const authTag = Buffer.from(parsedEncCfg.authTag, "base64");
|
||||
|
||||
const key = crypto.pbkdf2Sync(
|
||||
passwd,
|
||||
salt,
|
||||
CRYPTO_SETTINGS_AES.keyIter,
|
||||
CRYPTO_SETTINGS_AES.keyLength,
|
||||
CRYPTO_SETTINGS_AES.hash
|
||||
);
|
||||
|
||||
const decipherIns = crypto.createDecipheriv(
|
||||
CRYPTO_SETTINGS_AES.mode,
|
||||
key,
|
||||
iv,
|
||||
{
|
||||
// @ts-expect-error
|
||||
authTagLength: CRYPTO_SETTINGS_AES.tagLength,
|
||||
}
|
||||
);
|
||||
|
||||
decipherIns.setAuthTag(authTag);
|
||||
|
||||
const stringifyDecCfg = Buffer.concat([
|
||||
decipherIns.update(parsedEncCfg.content, "hex"),
|
||||
decipherIns.final(),
|
||||
]).toString();
|
||||
|
||||
/** @type {null | Record<any, any>} */
|
||||
let decConfig = null;
|
||||
try {
|
||||
decConfig = JSON.parse(stringifyDecCfg);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Failed to parse decrypted config:",
|
||||
err
|
||||
);
|
||||
console.error("[HugoAura / Config] Pending data:", decConfig);
|
||||
return FAILED_RET;
|
||||
}
|
||||
if (decConfig === null) return FAILED_RET;
|
||||
|
||||
// console.debug(decConfig);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: decConfig,
|
||||
};
|
||||
} else {
|
||||
console.error(
|
||||
"[HugoAura / Config] Unexpected error occurred while decrypting config: base64EncConfig is undefined"
|
||||
);
|
||||
return FAILED_RET;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Unexpected error occurred while decrypting config:",
|
||||
e
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Record<any, any> | null} curConfig
|
||||
* @param {SHA256EncryptedPassword | undefined | null} passwd
|
||||
* @returns {{success: boolean}}
|
||||
*/
|
||||
switchToDecConfig(curConfig, passwd = null) {
|
||||
let decConfig = null;
|
||||
if (!curConfig && passwd) {
|
||||
const getDecConfigResult = this.decryptConfig(passwd);
|
||||
if (
|
||||
!getDecConfigResult?.success ||
|
||||
!getDecConfigResult.data ||
|
||||
Object.keys(getDecConfigResult.data).length === 0
|
||||
) {
|
||||
console.error(
|
||||
"[HugoAura / Config] Failed to switch to decrypted config: Error decrypting config"
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
decConfig = getDecConfigResult.data;
|
||||
}
|
||||
|
||||
this.useEncConfig = false;
|
||||
this.clearEncPasswdRegKey();
|
||||
// @ts-expect-error
|
||||
this.writeConfig(curConfig ? curConfig : decConfig);
|
||||
try {
|
||||
fs.unlinkSync(this.encConfigPath);
|
||||
} catch {
|
||||
console.debug("[HugoAura / Config] Enc config not exists, skipping...");
|
||||
}
|
||||
global.__HUGO_AURA_EVENT_BUS__.emit(
|
||||
"$aura.config.updateConfigEncSettings",
|
||||
false
|
||||
);
|
||||
if (this.side === "renderer") {
|
||||
global.ipcRenderer.invoke("$aura.config.setConfigEncSettings", {
|
||||
target: false,
|
||||
});
|
||||
global.ipcRenderer.invoke("$aura.config.dispatchConfigFromRenderer", {
|
||||
data: JSON.stringify(curConfig),
|
||||
});
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new ConfigManager();
|
||||
module.exports = ConfigManager;
|
||||
|
||||
14
src/aura/init/shared/default.json
Normal file → Executable file
@@ -8,6 +8,14 @@
|
||||
"salt": "aura"
|
||||
},
|
||||
"authModeRewrite": "default"
|
||||
},
|
||||
"vendor/screenLock": {
|
||||
"enabled": true,
|
||||
"disableKeyboardHook": false,
|
||||
"authRewriteType": "customActivationCode",
|
||||
"customActivationCode": {
|
||||
"activationCodeWithSalt": "cbbd87c419b1c2dbc412ae238f1f4be3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"networkRewrite": {
|
||||
@@ -18,5 +26,11 @@
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"auraSettings": {
|
||||
"settingsPasswordEnabled": false,
|
||||
"settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965",
|
||||
"encryptConfig": false,
|
||||
"appearance": {}
|
||||
},
|
||||
"devTools": false
|
||||
}
|
||||
|
||||
224
src/aura/init/shared/registryManager.js
Executable file
@@ -0,0 +1,224 @@
|
||||
// @ts-check
|
||||
|
||||
const childProc = require("child_process");
|
||||
|
||||
// Constants
|
||||
|
||||
const LOG_PREFIX = "[HugoAura / Init / Reg";
|
||||
const LOG_PREFIX_FUNC = "[HugoAura / Reg";
|
||||
const AURA_REGISTRY_PATH = ["HKCU", "SOFTWARE", "HugoAura"].join("\\");
|
||||
|
||||
class RegistryManager {
|
||||
/**
|
||||
* @param {string} [path]
|
||||
*/
|
||||
handleCreateReg(path) {
|
||||
try {
|
||||
const createResult = childProc.execSync(["reg", "add", path].join(" "), {
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
if (createResult) {
|
||||
console.log(
|
||||
`${LOG_PREFIX} / SUCCESS] Registry path ${path} successfully created.`
|
||||
);
|
||||
console.debug(
|
||||
`${LOG_PREFIX} / DEBUG] Reg add command stdout:`,
|
||||
createResult
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`${LOG_PREFIX} / ERROR] Failed creating registry path, error:`,
|
||||
e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
initRegistry() {
|
||||
try {
|
||||
const queryResult = childProc.execSync(
|
||||
["reg", "query", AURA_REGISTRY_PATH].join(" "),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
if (queryResult) {
|
||||
console.log(`${LOG_PREFIX}] Registry check up success.`);
|
||||
console.debug(`${LOG_PREFIX}] Command stdout:`, queryResult);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`${LOG_PREFIX} / WARN] Failed to query registry, error:`, e);
|
||||
return this.handleCreateReg(AURA_REGISTRY_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} relativePath
|
||||
* @param {string} keyName
|
||||
* @param {string} keyVal
|
||||
* @param {boolean | undefined} silent
|
||||
*/
|
||||
createOrUpdateRegKey(relativePath, keyName, keyVal, silent = false) {
|
||||
try {
|
||||
const result = childProc.execSync(
|
||||
[
|
||||
"reg",
|
||||
"add",
|
||||
[AURA_REGISTRY_PATH, relativePath].join("\\"),
|
||||
"/v",
|
||||
keyName,
|
||||
"/t",
|
||||
"REG_SZ",
|
||||
"/d",
|
||||
`\"${keyVal}\"`,
|
||||
"/f",
|
||||
].join(" "),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
if (result) {
|
||||
if (!silent) {
|
||||
console.debug(
|
||||
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully created / updated reg key ${relativePath}/${keyName} with data: ${keyVal}`
|
||||
);
|
||||
console.debug(
|
||||
`${LOG_PREFIX_FUNC} / SUCCESS] Add key command stdout:`,
|
||||
result
|
||||
);
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`${LOG_PREFIX_FUNC} / ERROR] Failed to create / update reg key, error:`,
|
||||
silent ? "<Hidden>" : e
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*>>> BUC <<<
|
||||
keyName === null --> delete the whole entry
|
||||
>>> EUC <<<*/
|
||||
/**
|
||||
*
|
||||
* @param {string} relativePath
|
||||
* @param {string | null} keyName
|
||||
* @param {boolean | undefined} silent
|
||||
*/
|
||||
delRegKey(relativePath, keyName, silent = false) {
|
||||
if (keyName === undefined) {
|
||||
throw new Error(
|
||||
`${LOG_PREFIX_FUNC} / CRITICAL] Arg \"keyName\" for function \"delRegKey\" cannot be undefined. Only null or string accepted.`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = childProc.execSync(
|
||||
[
|
||||
"reg",
|
||||
"delete",
|
||||
[AURA_REGISTRY_PATH, relativePath].join("\\"),
|
||||
keyName ? "/v" : "",
|
||||
keyName ? keyName : "",
|
||||
"/f",
|
||||
].join(" "),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
if (result) {
|
||||
if (!silent) {
|
||||
console.debug(
|
||||
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully deleted reg key ${relativePath}/${keyName}`
|
||||
);
|
||||
console.debug(
|
||||
`${LOG_PREFIX_FUNC} / SUCCESS] Delete key command stdout:`,
|
||||
result
|
||||
);
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`${LOG_PREFIX_FUNC} / ERROR] Failed to delete reg key, error:`,
|
||||
silent ? "<Hidden>" : e
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} relativePath
|
||||
* @param {string} keyName
|
||||
* @param {boolean | undefined} silent
|
||||
*/
|
||||
readRegKey(relativePath, keyName, silent = false) {
|
||||
try {
|
||||
const readResult = childProc.execSync(
|
||||
[
|
||||
"reg",
|
||||
"query",
|
||||
[AURA_REGISTRY_PATH, relativePath].join("\\"),
|
||||
"/v",
|
||||
`\"${keyName}\"`,
|
||||
].join(" "),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
if (readResult) {
|
||||
if (!silent) {
|
||||
console.debug(
|
||||
`${LOG_PREFIX}] Successfully read reg key ${relativePath}/${keyName}, stdout:`,
|
||||
readResult
|
||||
);
|
||||
}
|
||||
const match = readResult.match(/REG_SZ\s+(.+)/);
|
||||
|
||||
if (!match) {
|
||||
console.warn(`${LOG_PREFIX_FUNC} / WARN] Data not found in stdout`);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
error: new Error("Data not found"),
|
||||
};
|
||||
}
|
||||
|
||||
const data = match[1].trim();
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`${LOG_PREFIX_FUNC} / ERROR] Failed to read reg key, error:`,
|
||||
silent ? "<Hidden>" : e
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegistryManager;
|
||||
0
src/aura/init/zeron/hookWS.js
Normal file → Executable file
0
src/aura/jsRewrite/network/disableBehaviorAudit.js
Normal file → Executable file
0
src/aura/jsRewrite/network/disableFriday.js
Normal file → Executable file
0
src/aura/jsRewrite/vendor/passwordValidation.js
vendored
Normal file → Executable file
1356
src/aura/jsRewrite/vendor/screenLock.js
vendored
Executable file
17
src/aura/mainProcess/hooks/screenLock.js
Executable file
@@ -0,0 +1,17 @@
|
||||
const hookFn = (central, appIns, browserWindowIns) => {
|
||||
const __config = global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"];
|
||||
|
||||
const removeKeyboardHook = () => {
|
||||
const { dllForHookBoard } = central(29);
|
||||
|
||||
setTimeout(() => {
|
||||
dllForHookBoard.UnHookKeyBoard();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
if (__config.disableKeyboardHook) {
|
||||
removeKeyboardHook();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { hookFunc: hookFn };
|
||||
26
src/aura/types/main/core.d.ts
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
import { WebContents } from "electron";
|
||||
|
||||
type SeewoHugoCentralLambda = any;
|
||||
type SeewoHugoGlobalConfig = Record<any, any>;
|
||||
|
||||
type WindowName = string;
|
||||
|
||||
interface LauncherArgs {
|
||||
central: SeewoHugoCentralLambda;
|
||||
windowName: WindowName;
|
||||
config: SeewoHugoGlobalConfig;
|
||||
}
|
||||
|
||||
interface HookedWindow {
|
||||
webContents: WebContents;
|
||||
domReadyListener: any;
|
||||
destroyedListener: any;
|
||||
}
|
||||
|
||||
type HookedWindowsMap = Map<WindowName, HookedWindow>;
|
||||
|
||||
type HookRequire = any;
|
||||
|
||||
type UIHooksMap = Map<WindowName, HookRequire>;
|
||||
|
||||
type WindowHooksMap = Map<WindowName, HookRequire>;
|
||||
10
src/aura/types/main/electron.d.ts
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
import { IpcMain, WebContents } from "electron";
|
||||
|
||||
interface AuraIPCMain extends IpcMain {
|
||||
send: (
|
||||
windowKey: string,
|
||||
channel: string,
|
||||
data: any,
|
||||
grep?: WebContents
|
||||
) => void;
|
||||
}
|
||||
17
src/aura/types/render/global.d.ts
vendored
Executable file
@@ -0,0 +1,17 @@
|
||||
interface HugoAuraGlobal {
|
||||
utils: Record<any, any>;
|
||||
}
|
||||
|
||||
interface AssistantHugoAuraGlobal extends HugoAuraGlobal {
|
||||
plsStatus: PLSStatus;
|
||||
plsRules: Record<any, any>;
|
||||
plsSettings: Record<any, any>;
|
||||
}
|
||||
|
||||
interface DesktopAssistantHugoAuraGlobal extends HugoAuraGlobal {
|
||||
plsWs: WebSocket | null;
|
||||
plsStats: PLSStatus;
|
||||
}
|
||||
|
||||
type UIFunctionsObject = Record<string, any>;
|
||||
type UIReactivesObject = Record<string, any>;
|
||||
27
src/aura/types/render/uiHook.d.ts
vendored
Executable file
@@ -0,0 +1,27 @@
|
||||
import { WindowName } from "../main/core";
|
||||
|
||||
interface UIHookTarget {
|
||||
active: boolean;
|
||||
pageURI: string;
|
||||
pageScript: string;
|
||||
pageSelector: string;
|
||||
selectorMode: "insertAfter" | "insertBefore" | "appendChild";
|
||||
pageCSS: string;
|
||||
revive?: boolean;
|
||||
}
|
||||
|
||||
type AuraElementUID = string;
|
||||
type OnLoadedEvalJS = string;
|
||||
|
||||
interface UIHookConfig {
|
||||
targets: Record<AuraElementUID, UIHookTarget>;
|
||||
globalStyles: string[];
|
||||
globalJS: string[];
|
||||
onLoaded: OnLoadedEvalJS;
|
||||
}
|
||||
|
||||
interface UIHookConfigFin extends UIHookConfig {
|
||||
windowName: WindowName;
|
||||
}
|
||||
|
||||
type UIHooksObject = Record<AuraElementUID, UIHookConfigFin>;
|
||||
12
src/aura/types/shared/config.d.ts
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
type AES256EncryptedConfig = string;
|
||||
type Base64String = string;
|
||||
type SHA256EncryptedPassword = string;
|
||||
|
||||
interface EncryptedConfig {
|
||||
content: AES256EncryptedConfig;
|
||||
authTag: Base64String;
|
||||
salt: Base64String;
|
||||
iv: Base64String;
|
||||
}
|
||||
|
||||
type AuraConfig = Record<any, any>;
|
||||
39
src/aura/types/shared/global.d.ts
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
import { IpcRenderer } from "electron";
|
||||
import type EventBus from "../../utils/eventBus";
|
||||
import { HookedWindowsMap, UIHooksMap, WindowHooksMap } from "../main/core";
|
||||
import { UIHooksObject } from "../render/uiHook";
|
||||
import ConfigManager from "../../init/shared/configManager";
|
||||
import { PLSStatus } from "./pls/status";
|
||||
|
||||
type MainProcessOnlyVal<T> = T;
|
||||
type RendererProcessOnlyVal<T> = T;
|
||||
|
||||
interface GlobalHugoAuraInfo {
|
||||
central?: MainProcessOnlyVal<(...args: any) => any>;
|
||||
configInit: boolean;
|
||||
hookedWindows?: MainProcessOnlyVal<HookedWindowsMap>;
|
||||
ipcInit?: MainProcessOnlyVal<boolean>;
|
||||
plsRules?: Record<any, any> | null;
|
||||
plsSettings?: Record<any, any> | null;
|
||||
plsStats?: PLSStatus | null;
|
||||
plsWs?: RendererProcessOnlyVal<WebSocket>;
|
||||
uiHooks?: MainProcessOnlyVal<UIHooksMap>;
|
||||
windowHooks?: MainProcessOnlyVal<WindowHooksMap>;
|
||||
version: RendererProcessOnlyVal<string>;
|
||||
}
|
||||
|
||||
type GlobalHugoAuraConfig = AuraConfig;
|
||||
|
||||
declare global {
|
||||
var ipcRenderer: RendererProcessOnlyVal<IpcRenderer>;
|
||||
var __HUGO_AURA__: GlobalHugoAuraInfo;
|
||||
var __HUGO_AURA_CONFIG__: GlobalHugoAuraConfig;
|
||||
var __HUGO_AURA_CONFIG_MGR__: ConfigManager;
|
||||
var __HUGO_AURA_EVENT_BUS__: EventBus;
|
||||
var __HUGO_AURA_DEBUG__: RendererProcessOnlyVal<Record<any, any>>;
|
||||
var __HUGO_AURA_GLOBAL__: RendererProcessOnlyVal<Record<any, any>>;
|
||||
var __HUGO_AURA_HOOK__: RendererProcessOnlyVal<Record<any, any>>;
|
||||
var __HUGO_AURA_LOADER__: RendererProcessOnlyVal<UIHooksObject>;
|
||||
var __HUGO_AURA_UI_FUNCTIONS__: RendererProcessOnlyVal<UIFunctionsObject>;
|
||||
var __HUGO_AURA_UI_REACTIVES__: RendererProcessOnlyVal<UIReactivesObject>;
|
||||
}
|
||||
11
src/aura/types/shared/pls/status.d.ts
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
import { RendererProcessOnlyVal } from "../global";
|
||||
|
||||
interface PLSStatus {
|
||||
installed: boolean;
|
||||
detached: boolean;
|
||||
connected: boolean;
|
||||
launched: boolean;
|
||||
status: string;
|
||||
version: string;
|
||||
authToken: string;
|
||||
}
|
||||
18
src/aura/types/shared/pls/websocket.d.ts
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
interface ClientPLSRequest {
|
||||
method: string;
|
||||
data: Record<any, any>;
|
||||
eventId: string;
|
||||
}
|
||||
|
||||
interface PLSResponse {
|
||||
success: boolean;
|
||||
code: number;
|
||||
data: Record<any, any>;
|
||||
eventId: string;
|
||||
}
|
||||
|
||||
interface PLSPush {
|
||||
success: boolean;
|
||||
type: string;
|
||||
data: Record<any, any>;
|
||||
}
|
||||
0
src/aura/ui/bootstrap/bootstrap.bundle.min.js
vendored
Normal file → Executable file
0
src/aura/ui/bootstrap/bootstrap.min.css
vendored
Normal file → Executable file
94
src/aura/ui/composables/plsConfigManager.js
Executable file
@@ -0,0 +1,94 @@
|
||||
// @ts-check
|
||||
|
||||
const __SCOPE = "assistant / rendererCommon";
|
||||
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
|
||||
const updatePlsStatusFromLocal = async () => {
|
||||
const plsStatus = (
|
||||
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsStats`)
|
||||
).data;
|
||||
global.__HUGO_AURA__.plsStats = plsStatus;
|
||||
return plsStatus;
|
||||
};
|
||||
|
||||
const updatePlsSettingsFromLocal = async () => {
|
||||
const plsSettings = (
|
||||
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsSettings`)
|
||||
).data;
|
||||
global.__HUGO_AURA__.plsSettings = plsSettings;
|
||||
return plsSettings;
|
||||
};
|
||||
|
||||
const updatePlsRulesFromLocal = async () => {
|
||||
const plsRules = (
|
||||
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsRules`)
|
||||
).data;
|
||||
global.__HUGO_AURA__.plsRules = plsRules;
|
||||
return plsRules;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
const genRandomHex = () => {
|
||||
let result = "";
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const randomNum = Math.floor(Math.random() * 0x10000);
|
||||
result += randomNum.toString(16).padStart(4, "0");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} configKey
|
||||
* @param {any} configValue
|
||||
*/
|
||||
const updatePlsConfigToRemote = async (configKey, configValue) => {
|
||||
const configLevels = configKey.split(".");
|
||||
/** @type {Record<any, any>} */
|
||||
// @ts-expect-error
|
||||
let localUpdateTarget =
|
||||
configLevels[0] === "ruleSettings"
|
||||
? global.__HUGO_AURA__.plsRules
|
||||
: global.__HUGO_AURA__.plsSettings;
|
||||
for (const level of configLevels.slice(0, -1)) {
|
||||
localUpdateTarget = localUpdateTarget[level];
|
||||
}
|
||||
localUpdateTarget[configLevels.slice(-1)[0]] = configValue;
|
||||
|
||||
const plsConfigUpdateEvent = new CustomEvent("onPLSConfigUpdate", {
|
||||
detail: {
|
||||
path: configKey,
|
||||
value: configValue,
|
||||
},
|
||||
});
|
||||
document.dispatchEvent(plsConfigUpdateEvent);
|
||||
|
||||
/**
|
||||
* @type {ClientPLSRequest}
|
||||
*/
|
||||
const data = {
|
||||
method: "config.action.updateConfig",
|
||||
data: {
|
||||
key: configKey,
|
||||
value: configValue,
|
||||
},
|
||||
eventId: genRandomHex(), // 不用 crypto, 因为会带来不必要的性能开销
|
||||
};
|
||||
|
||||
global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data);
|
||||
global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncPlsConfig`, {
|
||||
basic: global.__HUGO_AURA__.plsSettings,
|
||||
rules: global.__HUGO_AURA__.plsRules,
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
updatePlsRulesFromLocal,
|
||||
updatePlsStatusFromLocal,
|
||||
updatePlsSettingsFromLocal,
|
||||
updatePlsConfigToRemote,
|
||||
};
|
||||
126
src/aura/ui/composables/settingsRenderer.js
Normal file → Executable file
@@ -18,15 +18,30 @@ const showRelaunchToast = () => {
|
||||
if (!toastBs.isShown()) toastBs.show();
|
||||
};
|
||||
|
||||
const showRelaunchPLSToast = () => {
|
||||
const toast = document.getElementById("relaunchPlsNotifyToast");
|
||||
const toastBs = bootstrap.Toast.getOrCreateInstance(toast);
|
||||
|
||||
if (global.__HUGO_AURA__.plsStats.detached) {
|
||||
const relaunchBtn = document.getElementById("plsRelaunchBtn");
|
||||
relaunchBtn.disabled = true;
|
||||
relaunchBtn.textContent = "分离模式下无法执行";
|
||||
}
|
||||
|
||||
if (!toastBs.isShown()) toastBs.show();
|
||||
};
|
||||
|
||||
const showToast = (entry) => {
|
||||
if (entry.reload) {
|
||||
showReloadToast();
|
||||
} else if (entry.restart) {
|
||||
showRelaunchToast();
|
||||
} else if (entry.restartPLS) {
|
||||
showRelaunchPLSToast();
|
||||
}
|
||||
};
|
||||
|
||||
const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
const settingsRenderer = (pendingEl, settingsObj, isPls = false) => {
|
||||
const formEl = document.createElement("form");
|
||||
formEl.classList.add("aura-settings-form");
|
||||
for (const category of settingsObj) {
|
||||
@@ -56,6 +71,30 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
powerIcon.setAttribute("data-bs-title", "需要重启 Electron 进程");
|
||||
entryTitle.appendChild(powerIcon);
|
||||
}
|
||||
if (entry.PLSRequired) {
|
||||
const plsIcon = document.createElement("i");
|
||||
plsIcon.classList.add(
|
||||
"layui-icon",
|
||||
"layui-icon-component",
|
||||
"aura-settings-entry-property-icon"
|
||||
);
|
||||
plsIcon.setAttribute("data-bs-toggle", "tooltip");
|
||||
plsIcon.setAttribute("data-bs-placement", "top");
|
||||
plsIcon.setAttribute("data-bs-title", "需要 PLS 支持");
|
||||
entryTitle.appendChild(plsIcon);
|
||||
}
|
||||
if (entry.restartPLS) {
|
||||
const plsIcon = document.createElement("i");
|
||||
plsIcon.classList.add(
|
||||
"layui-icon",
|
||||
"layui-icon-logout",
|
||||
"aura-settings-entry-property-icon"
|
||||
);
|
||||
plsIcon.setAttribute("data-bs-toggle", "tooltip");
|
||||
plsIcon.setAttribute("data-bs-placement", "top");
|
||||
plsIcon.setAttribute("data-bs-title", "需要重启 PLS 进程");
|
||||
entryTitle.appendChild(plsIcon);
|
||||
}
|
||||
if (entry.reload) {
|
||||
const reloadIcon = document.createElement("i");
|
||||
reloadIcon.classList.add(
|
||||
@@ -68,18 +107,31 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
reloadIcon.setAttribute("data-bs-title", "需要重载页面");
|
||||
entryTitle.appendChild(reloadIcon);
|
||||
}
|
||||
if (entry.tip) {
|
||||
|
||||
const createToolTipIcon = (type, content) => {
|
||||
const tipIcon = document.createElement("i");
|
||||
tipIcon.classList.add(
|
||||
"layui-icon",
|
||||
"layui-icon-tips",
|
||||
"aura-settings-entry-property-icon"
|
||||
);
|
||||
if (type === "warning") {
|
||||
tipIcon.classList.add("aura-settings-entry-warning-icon");
|
||||
}
|
||||
tipIcon.setAttribute("data-bs-toggle", "tooltip");
|
||||
tipIcon.setAttribute("data-bs-placement", "top");
|
||||
tipIcon.setAttribute("data-bs-title", entry.tipTitle);
|
||||
tipIcon.setAttribute("data-bs-title", content);
|
||||
entryTitle.appendChild(tipIcon);
|
||||
};
|
||||
|
||||
if (entry.tip) {
|
||||
createToolTipIcon("tip", entry.tipTitle);
|
||||
}
|
||||
|
||||
if (entry.warning) {
|
||||
createToolTipIcon("warning", entry.warningContent);
|
||||
}
|
||||
|
||||
const entryDescription = document.createElement("p");
|
||||
entryDescription.classList.add("aura-settings-entry-desc");
|
||||
entryDescription.textContent = entry.description;
|
||||
@@ -101,9 +153,9 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
const elValue = entry.valueGetter();
|
||||
switchEl.value = elValue;
|
||||
switchEl.checked = elValue;
|
||||
switchEl.addEventListener("change", (event) => {
|
||||
switchEl.addEventListener("change", async (event) => {
|
||||
showToast(entry);
|
||||
entry.callbackFn(event.target.checked);
|
||||
await entry.callbackFn(event.target.checked);
|
||||
});
|
||||
entryOperationArea.classList.add("form-check", "form-switch");
|
||||
entryOperationArea.appendChild(switchEl);
|
||||
@@ -127,10 +179,10 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
template
|
||||
)}`;
|
||||
radioEl.checked = template === elValue ? true : false;
|
||||
radioEl.addEventListener("change", (event) => {
|
||||
radioEl.addEventListener("change", async (event) => {
|
||||
if (event.target.checked) {
|
||||
showToast(entry);
|
||||
entry.callbackFn(event.target.value);
|
||||
await entry.callbackFn(event.target.value);
|
||||
}
|
||||
});
|
||||
inlineContainerEl.appendChild(radioEl);
|
||||
@@ -152,8 +204,8 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
inputEl.value = entry.valueGetter();
|
||||
inputEl.placeholder = entry.placeHolder;
|
||||
inputEl.id = entry.id;
|
||||
inputEl.addEventListener("change", (event) => {
|
||||
const result = entry.callbackFn(event.target.value);
|
||||
inputEl.addEventListener("change", async (event) => {
|
||||
const result = await entry.callbackFn(event.target.value);
|
||||
const success = result.valid;
|
||||
if (success) {
|
||||
showToast(entry);
|
||||
@@ -177,19 +229,52 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
break;
|
||||
}
|
||||
|
||||
const setDisableStatus = (el, isDisable, hint = null) => {
|
||||
if (isDisable) {
|
||||
el.classList.add("ase-operation-area-disabled");
|
||||
if (hint) {
|
||||
el.setAttribute("data-bs-toggle", "tooltip");
|
||||
el.setAttribute("data-bs-placement", "top");
|
||||
el.setAttribute("data-bs-title", hint);
|
||||
}
|
||||
} else {
|
||||
el.setAttribute("data-bs-toggle", "");
|
||||
el.setAttribute("data-bs-placement", "");
|
||||
el.setAttribute("data-bs-title", "");
|
||||
el.classList.remove("ase-operation-area-disabled");
|
||||
}
|
||||
};
|
||||
|
||||
if (entry.PLSRequired) {
|
||||
if (!global.__HUGO_AURA__.plsStats.connected) {
|
||||
setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续");
|
||||
}
|
||||
|
||||
document.addEventListener("onPLSStatsUpdate", (event) => {
|
||||
if (event.detail.connected) {
|
||||
setDisableStatus(entryOperationArea, false);
|
||||
} else {
|
||||
setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续");
|
||||
}
|
||||
});
|
||||
}
|
||||
entryContainerEl.appendChild(entryOperationArea);
|
||||
const isShow = entry.auraIf();
|
||||
if (!isShow) entryContainerEl.classList.add("aura-settings-entry-hidden");
|
||||
|
||||
if (entry.associateVal) {
|
||||
document.addEventListener("onHugoAuraConfigUpdate", (event) => {
|
||||
if (!entry.associateVal.includes(event.detail.path.join("."))) return;
|
||||
const cls = entryContainerEl.classList;
|
||||
const isShow = entry.auraIf();
|
||||
isShow
|
||||
? cls.remove("aura-settings-entry-hidden")
|
||||
: cls.add("aura-settings-entry-hidden");
|
||||
});
|
||||
document.addEventListener(
|
||||
isPls ? "onPLSConfigUpdate" : "onHugoAuraConfigUpdate",
|
||||
(event) => {
|
||||
if (!entry.associateVal.includes(event.detail.path.join(".")))
|
||||
return;
|
||||
const cls = entryContainerEl.classList;
|
||||
const isShow = entry.auraIf();
|
||||
isShow
|
||||
? cls.remove("aura-settings-entry-hidden")
|
||||
: cls.add("aura-settings-entry-hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
formEl.appendChild(entryContainerEl);
|
||||
@@ -201,12 +286,7 @@ const settingsRenderer = (pendingEl, settingsObj) => {
|
||||
}
|
||||
pendingEl.appendChild(formEl);
|
||||
|
||||
const tooltipTriggerList = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]'
|
||||
);
|
||||
[...tooltipTriggerList].map(
|
||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
);
|
||||
global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip();
|
||||
};
|
||||
|
||||
module.exports = { settingsRenderer };
|
||||
|
||||
0
src/aura/ui/css/assistant.css
Normal file → Executable file
41
src/aura/ui/css/form.css
Normal file → Executable file
@@ -46,6 +46,15 @@
|
||||
flex: 0.75;
|
||||
}
|
||||
|
||||
.aura-settings-entry-operation-area.ase-operation-area-disabled {
|
||||
opacity: 0.25;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.aura-settings-entry-operation-area.ase-operation-area-disabled * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.aura-settings-entry-operation-area.form-switch {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
@@ -68,3 +77,35 @@
|
||||
.aura-settings-entry-property-icon.layui-icon-refresh {
|
||||
color: rgb(0, 106, 188);
|
||||
}
|
||||
|
||||
.aura-settings-entry-warning-icon {
|
||||
transform: rotate(180deg);
|
||||
display: inline-block;
|
||||
color: rgb(241, 155, 0);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
||||
@keyframes invalidShake {
|
||||
0% {
|
||||
margin-left: calc(-10px * 2);
|
||||
}
|
||||
16% {
|
||||
margin-left: calc(9px * 2);
|
||||
}
|
||||
33% {
|
||||
margin-left: calc(-6px * 2);
|
||||
}
|
||||
50% {
|
||||
margin-left: calc(5px * 2);
|
||||
}
|
||||
66% {
|
||||
margin-left: calc(-2px * 2);
|
||||
}
|
||||
83% {
|
||||
margin-left: calc(1px * 2);
|
||||
}
|
||||
100% {
|
||||
margin-left: calc(0px * 2);
|
||||
}
|
||||
}
|
||||
|
||||
0
src/aura/ui/css/global.css
Normal file → Executable file
74
src/aura/ui/hookDefinitions/assistant.js
Executable file
@@ -0,0 +1,74 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @type {import("../../types/render/uiHook").UIHookConfig}
|
||||
*/
|
||||
const def = {
|
||||
targets: {
|
||||
"Aura.UI.Assistant.HeaderEntry": {
|
||||
active: true,
|
||||
pageURI: "ui/pages/headerIcon/headerIcon.html",
|
||||
pageScript: "ui/pages/headerIcon/headerIcon.js",
|
||||
pageSelector: ".index__feedback__2XvUK2qe",
|
||||
selectorMode: "insertAfter",
|
||||
pageCSS: "ui/pages/headerIcon/headerIcon.css",
|
||||
revive: true,
|
||||
},
|
||||
"Aura.UI.Assistant.Config": {
|
||||
active: false,
|
||||
pageURI: "ui/pages/config/config.html",
|
||||
pageScript: "ui/pages/config/config.js",
|
||||
pageSelector: "#root",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS: "ui/pages/config/config.css",
|
||||
},
|
||||
"Aura.UI.Assistant.Config.DisableLimitations": {
|
||||
active: false,
|
||||
pageURI:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.html",
|
||||
pageScript:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.js",
|
||||
pageSelector: ".aura-config-page-subpage-container",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.css",
|
||||
},
|
||||
"Aura.UI.Assistant.Config.BehaviourCtrl": {
|
||||
active: false,
|
||||
pageURI: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html",
|
||||
pageScript: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js",
|
||||
pageSelector: ".aura-config-page-subpage-container",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.css",
|
||||
},
|
||||
"Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus": {
|
||||
active: false,
|
||||
pageURI: "ui/pages/configSubPages/behaviourCtrl/plsStatus.html",
|
||||
pageScript: "ui/pages/configSubPages/behaviourCtrl/plsStatus.js",
|
||||
pageSelector: "#status-subpage",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS: "ui/pages/configSubPages/behaviourCtrl/plsStatus.css",
|
||||
},
|
||||
"Aura.UI.Assistant.Config.Preferences": {
|
||||
active: false,
|
||||
pageURI: "ui/pages/configSubPages/preferences/preferences.html",
|
||||
pageScript: "ui/pages/configSubPages/preferences/preferences.js",
|
||||
pageSelector: ".aura-config-page-subpage-container",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS: "ui/pages/configSubPages/preferences/preferences.css",
|
||||
},
|
||||
},
|
||||
globalStyles: [
|
||||
"ui/css/global.css",
|
||||
"ui/css/assistant.css",
|
||||
"ui/css/form.css",
|
||||
"ui/layui/css/layui.css",
|
||||
"ui/bootstrap/bootstrap.min.css",
|
||||
],
|
||||
globalJS: ["ui/js/global.js", "ui/js/plsListener.js", "ui/bootstrap/bootstrap.bundle.min.js"],
|
||||
onLoaded: `
|
||||
console.log('[HugoAura / UI / Hooks / Assistant] Page loaded.');
|
||||
`,
|
||||
};
|
||||
|
||||
module.exports = def;
|
||||
15
src/aura/ui/hookDefinitions/desktopAssistant.js
Executable file
@@ -0,0 +1,15 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @type {import("../../types/render/uiHook").UIHookConfig}
|
||||
*/
|
||||
const def = {
|
||||
targets: {},
|
||||
globalStyles: ["ui/css/global.css"],
|
||||
globalJS: ["ui/js/global.js", "ui/js/plsConnectionManager.js"],
|
||||
onLoaded: `
|
||||
console.log('[HugoAura / UI / Hooks / Desktop Assistant] Page loaded.');
|
||||
`,
|
||||
};
|
||||
|
||||
module.exports = def;
|
||||
@@ -1,43 +0,0 @@
|
||||
module.exports = {
|
||||
targets: {
|
||||
"Aura.UI.Assistant.HeaderEntry": {
|
||||
active: true,
|
||||
pageURI: "ui/pages/headerIcon/headerIcon.html",
|
||||
pageScript: "ui/pages/headerIcon/headerIcon.js",
|
||||
pageSelector: ".index__feedback__2XvUK2qe",
|
||||
selectorMode: "insertAfter",
|
||||
pageCSS: "ui/pages/headerIcon/headerIcon.css",
|
||||
revive: true,
|
||||
},
|
||||
"Aura.UI.Assistant.Config": {
|
||||
active: false,
|
||||
pageURI: "ui/pages/config/config.html",
|
||||
pageScript: "ui/pages/config/config.js",
|
||||
pageSelector: "#root",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS: "ui/pages/config/config.css",
|
||||
},
|
||||
"Aura.UI.Assistant.Config.DisableLimitations": {
|
||||
active: false,
|
||||
pageURI:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.html",
|
||||
pageScript:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.js",
|
||||
pageSelector: ".aura-config-page-subpage-container",
|
||||
selectorMode: "appendChild",
|
||||
pageCSS:
|
||||
"ui/pages/configSubPages/disableLimitations/disableLimitations.css",
|
||||
},
|
||||
},
|
||||
globalStyles: [
|
||||
"ui/css/global.css",
|
||||
"ui/css/assistant.css",
|
||||
"ui/css/form.css",
|
||||
"ui/layui/css/layui.css",
|
||||
"ui/bootstrap/bootstrap.min.css",
|
||||
],
|
||||
globalJS: ["ui/js/global.js", "ui/bootstrap/bootstrap.bundle.min.js"],
|
||||
onLoaded: `
|
||||
console.log('[HugoAura / UI / Hooks / Assistant] Page loaded.');
|
||||
`,
|
||||
};
|
||||
20
src/aura/ui/js/global.js
Normal file → Executable file
@@ -1,9 +1,29 @@
|
||||
(() => {
|
||||
/* Util: Sleep */
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
/* Util: BootStrap Tooltip Ctrl */
|
||||
let tooltipTriggerCache = null;
|
||||
const refreshBsTooltip = () => {
|
||||
if (tooltipTriggerCache) {
|
||||
[...tooltipTriggerCache].map((el) =>
|
||||
bootstrap.Tooltip.getInstance(el).disable()
|
||||
);
|
||||
}
|
||||
|
||||
const tooltipTriggerList = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]'
|
||||
);
|
||||
tooltipTriggerCache = tooltipTriggerList;
|
||||
[...tooltipTriggerList].map(
|
||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
);
|
||||
};
|
||||
|
||||
if (!window.__HUGO_AURA_GLOBAL__) window.__HUGO_AURA_GLOBAL__ = {};
|
||||
|
||||
window.__HUGO_AURA_GLOBAL__.utils = {
|
||||
sleep,
|
||||
refreshBsTooltip,
|
||||
};
|
||||
})();
|
||||
|
||||
233
src/aura/ui/js/plsConnectionManager.js
Executable file
@@ -0,0 +1,233 @@
|
||||
// @ts-check
|
||||
(() => {
|
||||
if (!global.__HUGO_AURA__.plsStats)
|
||||
global.__HUGO_AURA__.plsStats = {
|
||||
installed: false,
|
||||
detached: false,
|
||||
connected: false,
|
||||
launched: false,
|
||||
status: "unknown",
|
||||
version: "未知",
|
||||
authToken: "",
|
||||
};
|
||||
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
const REQUIRE_BASE = "../../aura/ui";
|
||||
const __SCOPE = "desktopAssistant";
|
||||
|
||||
const { pushMsgHandler } = require(`${REQUIRE_BASE}/pls/pushHandler`);
|
||||
|
||||
/** @type {number} */
|
||||
let failedCounter = 0;
|
||||
/** @type {boolean} */
|
||||
let isErrorOccurred = false;
|
||||
|
||||
const sendRetryStatusToMain = (/** @type {Boolean} */ status) => {
|
||||
global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.post.updateRetryStatus`, {
|
||||
success: status,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} authToken
|
||||
* @param {any} callback
|
||||
* @returns
|
||||
*/
|
||||
const createPlsConnection = (authToken, callback) => {
|
||||
if (failedCounter >= 3) {
|
||||
console.error(
|
||||
`[HugoAura / UI / PLS Manager / ERROR] Failed connecting to PLS WebSocket server, please check the status of PLS process.`
|
||||
);
|
||||
sendRetryStatusToMain(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {WebSocket} */
|
||||
const plsWs = new WebSocket(
|
||||
`wss://pls.hugoaura.local:22077/?auth=${authToken}`
|
||||
);
|
||||
|
||||
plsWs.onopen = () => {
|
||||
callback(true, plsWs);
|
||||
};
|
||||
|
||||
plsWs.onerror = () => {
|
||||
isErrorOccurred = true;
|
||||
failedCounter += 1;
|
||||
callback(false, plsWs);
|
||||
};
|
||||
|
||||
plsWs.onclose = () => {
|
||||
console.error(
|
||||
"[HugoAura / UI / PLS Manager / ERROR] WebSocket connection closed."
|
||||
);
|
||||
if (isErrorOccurred) return;
|
||||
failedCounter += 1;
|
||||
callback(false, plsWs);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {WebSocket} wsObj
|
||||
*/
|
||||
const registerSendReqListener = (wsObj) => {
|
||||
global.ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.ws.post.onReqSendMsg`,
|
||||
/**
|
||||
*
|
||||
* @param {import("electron").IpcRendererEvent} _evt
|
||||
* @param {any} arg
|
||||
*/
|
||||
(_evt, arg) => {
|
||||
wsObj.send(JSON.stringify(arg));
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} result
|
||||
* @param {WebSocket} wsObj
|
||||
* @returns
|
||||
*/
|
||||
const connectionResultCallback = (result, wsObj) => {
|
||||
if (!global.__HUGO_AURA__.plsStats) return; // 😅 typescript
|
||||
|
||||
global.__HUGO_AURA__.plsStats.launched = result;
|
||||
global.__HUGO_AURA__.plsStats.connected = result;
|
||||
global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.updatePlsStats`,
|
||||
global.__HUGO_AURA__.plsStats
|
||||
);
|
||||
if (!result) {
|
||||
console.error(
|
||||
`[HugoAura / UI / PLS Manager / ERROR] Failed connecting to PLS WebSocket server, retrying ...`
|
||||
);
|
||||
createPlsConnection(
|
||||
global.__HUGO_AURA__.plsStats.authToken,
|
||||
connectionResultCallback
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
sendRetryStatusToMain(true);
|
||||
|
||||
global.__HUGO_AURA__.plsWs = wsObj;
|
||||
registerSendReqListener(wsObj);
|
||||
wsObj.onmessage = plsPushHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MessageEvent} event
|
||||
*/
|
||||
const plsPushHandler = (event) => {
|
||||
try {
|
||||
/** @type {Record<any, any>} */
|
||||
const parsedEvent = JSON.parse(event.data);
|
||||
console.debug(
|
||||
"[HugoAura / UI / PLS Manager / DEBUG] Received new server message: "
|
||||
);
|
||||
if (!parsedEvent.eventId) {
|
||||
// Push
|
||||
pushMsgHandler(parsedEvent);
|
||||
} else {
|
||||
// Not push
|
||||
global.ipcRenderer.send(
|
||||
`${IPC_METHOD_BASE}.ws.broadcastMessageRecv`,
|
||||
parsedEvent
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
console.error(
|
||||
"[HugoAura / UI / PLS Manager / ERROR] Failed to resolve server message: ",
|
||||
event.data
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const initPlsConnection = async () => {
|
||||
if (!global.__HUGO_AURA__.plsStats) return;
|
||||
|
||||
failedCounter = 0;
|
||||
isErrorOccurred = false;
|
||||
|
||||
const curPlsStats = await global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.getPlsStats`
|
||||
);
|
||||
let updatedPlsStats = {};
|
||||
if (curPlsStats === null || !curPlsStats.success) {
|
||||
updatedPlsStats = {
|
||||
installed: false,
|
||||
launched: false,
|
||||
detached: false,
|
||||
connected: false,
|
||||
version: "未知",
|
||||
status: "dead",
|
||||
authToken: "66ccff0d000721114514191981023333",
|
||||
};
|
||||
} else {
|
||||
updatedPlsStats = curPlsStats.data;
|
||||
}
|
||||
|
||||
const isPlsFolderExists = (
|
||||
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsFolderExists`)
|
||||
).data.isExists;
|
||||
updatedPlsStats.installed = isPlsFolderExists;
|
||||
|
||||
// @ts-expect-error
|
||||
global.__HUGO_AURA__.plsStats = updatedPlsStats;
|
||||
console.debug(
|
||||
"[HugoAura / UI / PLS Manager / DEBUG] Updated early plsStats:",
|
||||
global.__HUGO_AURA__.plsStats
|
||||
);
|
||||
|
||||
global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.updatePlsStats`,
|
||||
updatedPlsStats
|
||||
);
|
||||
|
||||
const startConnPls = () => {
|
||||
createPlsConnection(updatedPlsStats.authToken, connectionResultCallback);
|
||||
};
|
||||
|
||||
/*
|
||||
if (updatedPlsStats.detached && updatedPlsStats.installed) {
|
||||
*/
|
||||
if (updatedPlsStats.installed) {
|
||||
startConnPls();
|
||||
} else {
|
||||
sendRetryStatusToMain(false);
|
||||
}
|
||||
|
||||
/*
|
||||
global.ipcRenderer.on(`${IPC_METHOD_BASE}.post.onPlsLaunched`, (_event) => {
|
||||
setTimeout(() => {
|
||||
startConnPls();
|
||||
}, 5000);
|
||||
});
|
||||
*/
|
||||
};
|
||||
|
||||
const onSetup = () => {
|
||||
if (!global.ipcRenderer) {
|
||||
// @ts-ignore
|
||||
global.ipcRenderer = require("electron").global.ipcRenderer;
|
||||
}
|
||||
|
||||
initPlsConnection();
|
||||
|
||||
global.ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.retryPlsConnect`,
|
||||
(_evt, _arg) => {
|
||||
if (!global.__HUGO_AURA__.plsStats) return;
|
||||
if (global.__HUGO_AURA__.plsStats.connected) return;
|
||||
initPlsConnection();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
onSetup();
|
||||
})();
|
||||
58
src/aura/ui/js/plsListener.js
Executable file
@@ -0,0 +1,58 @@
|
||||
(() => {
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
const REQUIRE_BASE = "../../aura/ui";
|
||||
const __SCOPE = "assistant";
|
||||
const {
|
||||
updatePlsStatusFromLocal,
|
||||
} = require(`${REQUIRE_BASE}/composables/plsConfigManager`);
|
||||
|
||||
const setupListeners = () => {
|
||||
if (!global.ipcRenderer)
|
||||
global.ipcRenderer = require("electron").ipcRenderer;
|
||||
|
||||
ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.post.onPlsStatsUpdate`,
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsStats = arg;
|
||||
}
|
||||
);
|
||||
|
||||
ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.post.onPlsSettingsUpdate`,
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsSettings = arg;
|
||||
}
|
||||
);
|
||||
|
||||
ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.post.onPlsRulesUpdate`,
|
||||
(_event, arg) => {
|
||||
global.__HUGO_AURA__.plsRules = arg;
|
||||
}
|
||||
);
|
||||
|
||||
ipcRenderer.on(
|
||||
`${IPC_METHOD_BASE}.post.updateRetryStatus`,
|
||||
(_event, arg) => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("onPLSStatsUpdate", {
|
||||
detail: {
|
||||
connected: arg.success,
|
||||
},
|
||||
})
|
||||
);
|
||||
if (
|
||||
global.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config.BehaviourCtrl"]
|
||||
.active
|
||||
) {
|
||||
setTimeout(() => {
|
||||
global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
updatePlsStatusFromLocal();
|
||||
setupListeners();
|
||||
})();
|
||||
0
src/aura/ui/layui/css/layui.css
Normal file → Executable file
0
src/aura/ui/layui/font/iconfont.eot
Normal file → Executable file
0
src/aura/ui/layui/font/iconfont.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB |
0
src/aura/ui/layui/font/iconfont.ttf
Normal file → Executable file
0
src/aura/ui/layui/font/iconfont.woff
Normal file → Executable file
0
src/aura/ui/layui/font/iconfont.woff2
Normal file → Executable file
400
src/aura/ui/pages/config/config.css
Normal file → Executable file
@@ -1,409 +1,27 @@
|
||||
/* General */
|
||||
|
||||
#aura-container-Aura-UI-Assistant-Config {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.aura-config-page-root {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("../../../../app.asar/public/ae247697b4639c92bd008d0ea7d13b53.png");
|
||||
/* 这里不用 background-size: cover; 的效果反而更舒服一些... */
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-root-inactive {
|
||||
opacity: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
@import url("./css/general.css");
|
||||
|
||||
/* Header */
|
||||
|
||||
.aura-config-page-header-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
color: white;
|
||||
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont {
|
||||
font-size: 24px;
|
||||
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont:hover {
|
||||
opacity: 0.75;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont:active {
|
||||
opacity: 0.375;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area p {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area.header-collapsed {
|
||||
transform: translateY(-1rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-app-bar {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
@import url("./css/header.css");
|
||||
|
||||
/* Status */
|
||||
|
||||
.aura-config-page-status-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
align-self: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-container-hidden {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-main,
|
||||
.aura-config-page-status-description {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description {
|
||||
margin-top: 0.5rem;
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description.status-description-hidden {
|
||||
transform: translateY(-2rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description p {
|
||||
font-size: 18px;
|
||||
margin-left: 15px;
|
||||
margin-top: -2px;
|
||||
color: white;
|
||||
font-family: "Consolas", "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aura-config-page-central-aura-logo {
|
||||
margin: 0.5rem 3rem;
|
||||
width: 17.5%;
|
||||
}
|
||||
|
||||
.aura-config-hr-vertical {
|
||||
height: 3.75rem;
|
||||
width: 1px;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
margin-left: 30px;
|
||||
margin-right: 30px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Consolas", monospace;
|
||||
color: white;
|
||||
|
||||
/*
|
||||
.version-type {
|
||||
content: "I want to use scss plz 😇"
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
.aura-config-page-status-side {
|
||||
height: 30%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
|
||||
transition: transform 0.5s, opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.left-side {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.left-side.status-side-hidden {
|
||||
transform: translateX(5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.right-side {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.right-side.status-side-hidden {
|
||||
transform: translateX(-5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el .version-type {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el .version-content {
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
opacity: 0.625;
|
||||
}
|
||||
@import url("./css/status.css");
|
||||
|
||||
/* Operation */
|
||||
|
||||
.aura-config-page-operation-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@import url("./css/operation.css");
|
||||
|
||||
.aura-config-page-operation-area::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
/* Config Status Notify */
|
||||
|
||||
.aura-config-page-operation-area.subpage-expanded {
|
||||
flex: 15;
|
||||
}
|
||||
@import url("./css/configStatusNotify.css");
|
||||
|
||||
.aura-config-page-subpage-container {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background-color: rgba(255, 255, 255, 0.825);
|
||||
z-index: 6000;
|
||||
overflow-y: scroll;
|
||||
/* Auth Dialog */
|
||||
|
||||
opacity: 0;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-subpage-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-area.subpage-expanded
|
||||
.aura-config-page-subpage-container {
|
||||
height: calc(100% - 40px - 4rem);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container.hide-other-operations
|
||||
.aura-config-page-operation-el:not(.preserve-operation) {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container.hide-other-operations
|
||||
.aura-config-page-operation-el.preserve-operation {
|
||||
flex: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
max-width: 25%;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
||||
transition: opacity 0.5s, transform 0.5s,
|
||||
max-width cubic-bezier(0, 0.42, 0.18, 1) 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-hidden {
|
||||
transform: translateY(2rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]
|
||||
.aura-config-page-operation-body {
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:not(.preserve-operation):hover
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.625;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:not(.preserve-operation):active
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]::after {
|
||||
content: "别急嘛, 还在开发呢...";
|
||||
font-size: 16px;
|
||||
opacity: 0;
|
||||
color: white;
|
||||
position: absolute;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover::after,
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:active::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el img {
|
||||
max-width: 40px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el .config-operation-title {
|
||||
color: white;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el .config-operation-description {
|
||||
color: white;
|
||||
opacity: 0.75;
|
||||
font-size: small;
|
||||
}
|
||||
@import url("./css/authDialog.css");
|
||||
|
||||
/* Toast */
|
||||
|
||||
.aura-config-page-toast-area {
|
||||
z-index: 9000;
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast {
|
||||
--bs-toast-border-width: 0 !important;
|
||||
--bs-toast-bg: #fff !important;
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header {
|
||||
background-color: rgb(255, 234, 202);
|
||||
|
||||
border-top-left-radius: var(--bs-toast-border-radius);
|
||||
border-top-right-radius: var(--bs-toast-border-radius);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast.acp-toast-emerg .toast-header {
|
||||
background-color: rgb(255, 202, 202);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header * {
|
||||
color: rgba(234, 126, 14, 0.85);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast.acp-toast-emerg .toast-header * {
|
||||
color: rgba(234, 65, 14, 0.85);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-body p {
|
||||
margin-bottom: var(--bs-toast-padding-x);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header .layui-icon {
|
||||
font-weight: bolder;
|
||||
margin-right: 0.5rem;
|
||||
font-size: 18px;
|
||||
}
|
||||
@import url("./css/toast.css");
|
||||
|
||||
114
src/aura/ui/pages/config/config.html
Normal file → Executable file
@@ -1,4 +1,8 @@
|
||||
<div class="aura-config-page-root-inactive aura-config-page-root">
|
||||
<div
|
||||
class="aura-config-page-root-inactive aura-config-page-root"
|
||||
style="display: none"
|
||||
>
|
||||
<!-- display: none 用于防止 CSS 还未加载完成时, 用户看到错乱的样式 -->
|
||||
<div class="header-collapsed aura-config-page-header-area">
|
||||
<div class="aura-config-page-app-bar" style="-webkit-app-region: drag">
|
||||
<div
|
||||
@@ -66,6 +70,28 @@
|
||||
<div class="aura-config-page-operation-area">
|
||||
<div class="aura-config-page-subpage-container"></div>
|
||||
<div class="aura-config-page-operation-container">
|
||||
<div class="acp-config-status-notify hidden fully-hidden">
|
||||
<div class="acp-config-status-notify-area">
|
||||
<div class="acp-config-status-notify-main-content">
|
||||
<i class="layui-icon layui-icon-component acsn-main-icon"></i>
|
||||
<p class="acsn-main-title">修改的配置暂未保存</p>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-primary btn-sm acsn-save-btn"
|
||||
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.handleSaveConfig()"
|
||||
>
|
||||
保存配置
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="acp-config-status-notify-success acsn-success-hidden acsn-success-fully-hidden"
|
||||
>
|
||||
<i class="layui-icon layui-icon-release"></i>
|
||||
<p>保存成功</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="operation-el-hidden aura-config-page-operation-el"
|
||||
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('disableLimitations', true)"
|
||||
@@ -74,14 +100,15 @@
|
||||
<img src="../../aura/ui/static/config/no_limitations.svg" />
|
||||
<div>
|
||||
<p class="config-operation-title">限制解除</p>
|
||||
<p class="config-operation-description">禁用密码、关闭冰点</p>
|
||||
<p class="config-operation-description">禁用密码、关闭功能</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="operation-el-hidden aura-config-page-operation-el"
|
||||
aura-disabled="true"
|
||||
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('behaviourCtrl', true)"
|
||||
>
|
||||
<!-- Still WIP -->
|
||||
<div class="aura-config-page-operation-body">
|
||||
<img src="../../aura/ui/static/config/behaviour_mon.svg" />
|
||||
<div>
|
||||
@@ -102,18 +129,55 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="operation-el-hidden aura-config-page-operation-el">
|
||||
<div
|
||||
class="operation-el-hidden aura-config-page-operation-el"
|
||||
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('preferences', true)"
|
||||
>
|
||||
<div class="aura-config-page-operation-body">
|
||||
<img src="../../aura/ui/static/config/about.svg" />
|
||||
<div>
|
||||
<p class="config-operation-title">关于项目</p>
|
||||
<p class="config-operation-description">使用文档、获取帮助</p>
|
||||
<p class="config-operation-title">偏好设置</p>
|
||||
<p class="config-operation-description">Aura 设置、关于项目</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="aura-config-page-auth-dialog-area acp-ada-hidden"
|
||||
style="display: none"
|
||||
aura-cancel="true"
|
||||
>
|
||||
<div class="aura-config-page-auth-dialog">
|
||||
<p class="acp-auth-dialog-title">验证您的身份</p>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="请输入密码..."
|
||||
aria-label="Aura Password"
|
||||
id="acp-auth-user-input"
|
||||
/>
|
||||
|
||||
<div class="acp-auth-btns-container">
|
||||
<button
|
||||
class="acp-auth-cancel-btn"
|
||||
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.handleNavBack()"
|
||||
>
|
||||
<i class="layui-icon layui-icon-return"></i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="acp-auth-confirm-btn"
|
||||
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.verifyAuthPassword()"
|
||||
>
|
||||
<i class="layui-icon layui-icon-ok"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aura-config-page-toast-area">
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div
|
||||
@@ -128,10 +192,14 @@
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
<p>请重载当前窗口以应用修改的设置</p>
|
||||
<p>已修改的配置将自动保存</p>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="window.location.reload()"
|
||||
onclick="(() => {
|
||||
global.__HUGO_AURA_CONFIG_MGR__.writeConfig(global.__HUGO_AURA_CONFIG__);
|
||||
window.location.reload();
|
||||
})()"
|
||||
>
|
||||
重载页面
|
||||
</button>
|
||||
@@ -152,10 +220,40 @@
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
<p>请重启 Electron 进程以应用修改的设置</p>
|
||||
<p>已修改的配置将自动保存</p>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="ipcRenderer.invoke('$aura.base.restartApplication')"
|
||||
onclick="(() => {
|
||||
global.__HUGO_AURA_CONFIG_MGR__.writeConfig(global.__HUGO_AURA_CONFIG__);
|
||||
ipcRenderer.invoke('$aura.base.restartApplication')
|
||||
})()"
|
||||
>
|
||||
重启进程
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div
|
||||
id="relaunchPlsNotifyToast"
|
||||
class="toast acp-toast-emerg"
|
||||
aria-atomic="true"
|
||||
data-bs-autohide="false"
|
||||
>
|
||||
<div class="toast-header">
|
||||
<i class="layui-icon layui-icon-tips"></i>
|
||||
<strong class="me-auto">重启 PLS 进程以应用设置</strong>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
<p>请重启 PLS 进程以应用修改的设置</p>
|
||||
<p>已修改的配置将自动保存</p>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
id="plsRelaunchBtn"
|
||||
onclick="ipcRenderer.invoke('$aura.pls.relaunchPls')"
|
||||
>
|
||||
重启进程
|
||||
</button>
|
||||
|
||||
205
src/aura/ui/pages/config/config.js
Normal file → Executable file
@@ -1,11 +1,24 @@
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config = {
|
||||
isInSubPage: false,
|
||||
currentActiveSubPage: "",
|
||||
authenticated: false,
|
||||
isConfigPendingWrite: false,
|
||||
};
|
||||
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config = {
|
||||
handleNavBack: () => {
|
||||
if (global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage) {
|
||||
const acsDialogAreaEl = document.getElementsByClassName(
|
||||
"aura-config-page-auth-dialog-area"
|
||||
)[0];
|
||||
if (!Array.from(acsDialogAreaEl.classList).includes("acp-ada-hidden")) {
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.hideAndResetAuthDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (global.__HUGO_AURA_UI_REACTIVES__.config.isConfigPendingWrite) {
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.handleSaveConfig();
|
||||
}
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig(
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.currentActiveSubPage,
|
||||
false
|
||||
@@ -34,6 +47,7 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
|
||||
|
||||
toggleSubConfig: (subPage, side) => {
|
||||
if (side === global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage) return;
|
||||
if (!global.__HUGO_AURA_UI_REACTIVES__.config.authenticated) return;
|
||||
if (!side) {
|
||||
side = !global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage;
|
||||
}
|
||||
@@ -49,17 +63,42 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
|
||||
"aura-config-page-operation-el"
|
||||
);
|
||||
let pendingSubPageId = "";
|
||||
let preserveOperationIdx = 0;
|
||||
switch (subPage) {
|
||||
case "disableLimitations":
|
||||
side
|
||||
? operationElArr[0].classList.add("preserve-operation")
|
||||
: operationElArr[0].classList.remove("preserve-operation");
|
||||
preserveOperationIdx = 0;
|
||||
pendingSubPageId = "Aura.UI.Assistant.Config.DisableLimitations";
|
||||
break;
|
||||
case "behaviourCtrl":
|
||||
preserveOperationIdx = 1;
|
||||
pendingSubPageId = "Aura.UI.Assistant.Config.BehaviourCtrl";
|
||||
if (!side) {
|
||||
setTimeout(() => {
|
||||
global.__HUGO_AURA_LOADER__[
|
||||
"Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus"
|
||||
].active = false;
|
||||
}, 500);
|
||||
}
|
||||
break;
|
||||
case "plugins":
|
||||
// To Be Done
|
||||
preserveOperationIdx = 2;
|
||||
pendingSubPageId = "Aura.UI.Assistant.Config.Plugins";
|
||||
break;
|
||||
case "preferences":
|
||||
preserveOperationIdx = 3;
|
||||
pendingSubPageId = "Aura.UI.Assistant.Config.Preferences";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
side
|
||||
? operationElArr[preserveOperationIdx].classList.add("preserve-operation")
|
||||
: operationElArr[preserveOperationIdx].classList.remove(
|
||||
"preserve-operation"
|
||||
);
|
||||
|
||||
const operationAreaEl = document.getElementsByClassName(
|
||||
"aura-config-page-operation-area"
|
||||
)[0];
|
||||
@@ -101,6 +140,129 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
|
||||
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage = side;
|
||||
},
|
||||
|
||||
verifyAuthPassword: async () => {
|
||||
const showFailedAnimation = async (el) => {
|
||||
el.classList.remove("invalid");
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
el.classList.add("invalid"); // Custom Anim
|
||||
el.classList.add("is-invalid"); // Bootstrap
|
||||
};
|
||||
|
||||
const inputEl = document.getElementById("acp-auth-user-input");
|
||||
const userPasswdInput = inputEl.value;
|
||||
|
||||
if (!userPasswdInput || userPasswdInput.length < 8) {
|
||||
showFailedAnimation(inputEl);
|
||||
return false;
|
||||
}
|
||||
|
||||
const crypto = require("crypto");
|
||||
const encPasswd = crypto
|
||||
.createHash("sha512")
|
||||
.update(userPasswdInput + "EndlessX")
|
||||
.digest("hex")
|
||||
.toUpperCase();
|
||||
|
||||
if (
|
||||
encPasswd ===
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt
|
||||
) {
|
||||
await global.__HUGO_AURA_UI_FUNCTIONS__.config.hideAndResetAuthDialog();
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(250);
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.authenticated = true;
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.showSecondPhaseAnim();
|
||||
return true;
|
||||
} else {
|
||||
showFailedAnimation(inputEl);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
hideAndResetAuthDialog: async () => {
|
||||
const acsDialogAreaEl = document.getElementsByClassName(
|
||||
"aura-config-page-auth-dialog-area"
|
||||
)[0];
|
||||
const acpAppBarEl = document.getElementsByClassName(
|
||||
"aura-config-page-header-area"
|
||||
)[0];
|
||||
const acpDialogTitleEl = document.getElementsByClassName(
|
||||
"acp-auth-dialog-title"
|
||||
)[0];
|
||||
const acpDialogConfirmBtnEl = document.getElementsByClassName(
|
||||
"acp-auth-confirm-btn"
|
||||
)[0];
|
||||
const acpDialogCancelBtnEl = document.getElementsByClassName(
|
||||
"acp-auth-cancel-btn"
|
||||
)[0];
|
||||
const inputEl = document.getElementById("acp-auth-user-input");
|
||||
acsDialogAreaEl.classList.add("acp-ada-hidden");
|
||||
acpAppBarEl.classList.remove("color-reverse");
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
|
||||
acsDialogAreaEl.style = "display: none;";
|
||||
acpDialogTitleEl.textContent = "验证您的身份";
|
||||
inputEl.value = "";
|
||||
inputEl.classList.remove("invalid");
|
||||
inputEl.classList.remove("is-invalid");
|
||||
acpDialogConfirmBtnEl.onclick = (_evt) => {
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.verifyAuthPassword();
|
||||
};
|
||||
acpDialogCancelBtnEl.onclick = (_evt) => {
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.handleNavBack();
|
||||
};
|
||||
},
|
||||
|
||||
handleACSNShow: async () => {
|
||||
const acsnRootEl = document.getElementsByClassName(
|
||||
"acp-config-status-notify"
|
||||
)[0];
|
||||
acsnRootEl.classList.remove("fully-hidden");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(10);
|
||||
acsnRootEl.classList.remove("hidden");
|
||||
return true;
|
||||
},
|
||||
|
||||
handleSaveConfig: async () => {
|
||||
const result = global.__HUGO_AURA_CONFIG_MGR__.writeConfig(
|
||||
global.__HUGO_AURA_CONFIG__
|
||||
);
|
||||
|
||||
if (result) {
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.isConfigPendingWrite = false;
|
||||
const acsnRootEl = document.getElementsByClassName(
|
||||
"acp-config-status-notify"
|
||||
)[0];
|
||||
const acsnMainContentEl = document.getElementsByClassName(
|
||||
"acp-config-status-notify-main-content"
|
||||
)[0];
|
||||
const acsnSuccessEl = document.getElementsByClassName(
|
||||
"acp-config-status-notify-success"
|
||||
)[0];
|
||||
const acsnAreaEl = document.getElementsByClassName(
|
||||
"acp-config-status-notify-area"
|
||||
)[0];
|
||||
acsnMainContentEl.classList.add("acsn-main-content-hidden");
|
||||
acsnAreaEl.classList.add("transparent");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(250);
|
||||
acsnMainContentEl.classList.add("acsn-main-content-fully-hidden");
|
||||
acsnSuccessEl.classList.remove("acsn-success-fully-hidden");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
acsnSuccessEl.classList.remove("acsn-success-hidden");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(1500);
|
||||
acsnRootEl.classList.add("hidden");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(500);
|
||||
acsnRootEl.classList.add("fully-hidden");
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(10);
|
||||
// Reset class
|
||||
acsnMainContentEl.className = "acp-config-status-notify-main-content";
|
||||
acsnAreaEl.className = "acp-config-status-notify-area";
|
||||
acsnSuccessEl.className =
|
||||
"acp-config-status-notify-success acsn-success-hidden acsn-success-fully-hidden";
|
||||
return true;
|
||||
} else {
|
||||
// TODO: Error handling
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
(() => {
|
||||
@@ -151,23 +313,50 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
|
||||
});
|
||||
};
|
||||
|
||||
const showAnimation = async () => {
|
||||
const defaultHeader = document.getElementsByClassName(
|
||||
"index__header__16DmR2a5"
|
||||
)[0];
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.showSecondPhaseAnim = () => {
|
||||
showOperationsAnimation();
|
||||
};
|
||||
|
||||
const handleSettingsAuth = async () => {
|
||||
const isAuthEnabled =
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordEnabled;
|
||||
|
||||
if (!isAuthEnabled) {
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.authenticated = true;
|
||||
showOperationsAnimation();
|
||||
} else {
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
const acsDialogAreaEl = document.getElementsByClassName(
|
||||
"aura-config-page-auth-dialog-area"
|
||||
)[0];
|
||||
const acpAppBarEl = document.getElementsByClassName(
|
||||
"aura-config-page-header-area"
|
||||
)[0];
|
||||
acsDialogAreaEl.style = "";
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
|
||||
acsDialogAreaEl.classList.remove("acp-ada-hidden");
|
||||
acpAppBarEl.classList.add("color-reverse");
|
||||
}
|
||||
};
|
||||
|
||||
const showAnimation = async () => {
|
||||
const auraConfigPageRoot = document.getElementsByClassName(
|
||||
"aura-config-page-root"
|
||||
)[0];
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(200);
|
||||
auraConfigPageRoot.className = "aura-config-page-root";
|
||||
|
||||
const defaultHeader = document.getElementsByClassName(
|
||||
"index__header__16DmR2a5"
|
||||
)[0];
|
||||
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
|
||||
defaultHeader.style = "display: none;";
|
||||
showVersionContainerAnimation();
|
||||
showHeaderAnimation();
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
|
||||
showOperationsAnimation();
|
||||
|
||||
await handleSettingsAuth();
|
||||
};
|
||||
|
||||
const onMounted = () => {
|
||||
|
||||
95
src/aura/ui/pages/config/css/authDialog.css
Executable file
@@ -0,0 +1,95 @@
|
||||
.aura-config-page-auth-dialog-area {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10000;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
|
||||
opacity: 1;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.acp-ada-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-auth-dialog {
|
||||
height: 40%;
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.acp-auth-dialog-title {
|
||||
font-size: x-large;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#acp-auth-user-input {
|
||||
max-width: 50%;
|
||||
/* background-color: rgba(255, 255, 255, 0.5); */
|
||||
border-radius: 35px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
#acp-auth-user-input.invalid {
|
||||
animation: invalidShake 0.6s linear;
|
||||
}
|
||||
|
||||
.acp-auth-btns-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.acp-auth-btns-container button {
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.acp-auth-btns-container button:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.acp-auth-btns-container button:active {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.acp-auth-confirm-btn,
|
||||
.acp-auth-cancel-btn {
|
||||
border-radius: 35px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.acp-auth-confirm-btn {
|
||||
background: linear-gradient(135deg, #218fff 0%, #3fbaff 100%);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.acp-auth-confirm-btn .layui-icon {
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.acp-auth-cancel-btn .layui-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.acp-auth-cancel-btn {
|
||||
background-color: transparent;
|
||||
margin-right: 3rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.aura-config-page-auth-dialog-area[aura-cancel="false"] .acp-auth-cancel-btn {
|
||||
display: none;
|
||||
}
|
||||
114
src/aura/ui/pages/config/css/configStatusNotify.css
Executable file
@@ -0,0 +1,114 @@
|
||||
.acp-config-status-notify {
|
||||
position: absolute;
|
||||
height: calc(40px + 4rem);
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
filter: blur(0.1px);
|
||||
z-index: 15000;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.acp-config-status-notify.hidden {
|
||||
backdrop-filter: blur(0.1px);
|
||||
filter: unset;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.acp-config-status-notify.fully-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
transition: background-color 0.25s;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area.transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-main-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* margin-bottom: 0.75rem; */
|
||||
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-main-content.acsn-main-content-hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-main-content.acsn-main-content-fully-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area .acsn-main-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area .acsn-main-title {
|
||||
font-size: large;
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 2.25rem;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area .acsn-save-btn {
|
||||
margin-top: 2px; /* 可能是中文导致的 */
|
||||
|
||||
opacity: 1;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-area .acsn-save-btn:active {
|
||||
opacity: 0.625;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-success {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
|
||||
color: white;
|
||||
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-success.acsn-success-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-success.acsn-success-fully-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-success .layui-icon {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.acp-config-status-notify-success p {
|
||||
font-size: large;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
33
src/aura/ui/pages/config/css/general.css
Executable file
@@ -0,0 +1,33 @@
|
||||
#aura-container-Aura-UI-Assistant-Config {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.aura-config-page-root {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("../../../../../app.asar/public/ae247697b4639c92bd008d0ea7d13b53.png");
|
||||
/* 这里不用 background-size: cover; 的效果反而更舒服一些... */
|
||||
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-root-inactive {
|
||||
opacity: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
50
src/aura/ui/pages/config/css/header.css
Executable file
@@ -0,0 +1,50 @@
|
||||
.aura-config-page-header-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
color: white;
|
||||
z-index: 12000;
|
||||
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area.color-reverse {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont:hover {
|
||||
opacity: 0.75;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area .iconfont:active {
|
||||
opacity: 0.375;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area p {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.aura-config-page-header-area.header-collapsed {
|
||||
transform: translateY(-1rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-app-bar {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
155
src/aura/ui/pages/config/css/operation.css
Executable file
@@ -0,0 +1,155 @@
|
||||
.aura-config-page-operation-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-area::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-area.subpage-expanded {
|
||||
flex: 15;
|
||||
}
|
||||
|
||||
.aura-config-page-subpage-container {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background-color: rgba(255, 255, 255, 0.825);
|
||||
z-index: 6000;
|
||||
overflow-y: scroll;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-subpage-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-area.subpage-expanded
|
||||
.aura-config-page-subpage-container {
|
||||
height: calc(100% - 40px - 4rem);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container.hide-other-operations
|
||||
.aura-config-page-operation-el:not(.preserve-operation) {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-container.hide-other-operations
|
||||
.aura-config-page-operation-el.preserve-operation {
|
||||
flex: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
max-width: 25%;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
|
||||
transition: opacity 0.5s, transform 0.5s,
|
||||
max-width cubic-bezier(0, 0.42, 0.18, 1) 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-hidden {
|
||||
transform: translateY(2rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]
|
||||
.aura-config-page-operation-body {
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:not(.preserve-operation):hover
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.625;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show:not(.preserve-operation):active
|
||||
.aura-config-page-operation-body {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]::after {
|
||||
content: "别急嘛, 还在开发呢...";
|
||||
font-size: 16px;
|
||||
opacity: 0;
|
||||
color: white;
|
||||
position: absolute;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:hover::after,
|
||||
.aura-config-page-operation-el.operation-el-show[aura-disabled="true"]:active::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el img {
|
||||
max-width: 40px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el .config-operation-title {
|
||||
color: white;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.aura-config-page-operation-el .config-operation-description {
|
||||
color: white;
|
||||
opacity: 0.75;
|
||||
font-size: small;
|
||||
}
|
||||
123
src/aura/ui/pages/config/css/status.css
Executable file
@@ -0,0 +1,123 @@
|
||||
.aura-config-page-status-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
align-self: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-container-hidden {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-main,
|
||||
.aura-config-page-status-description {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description {
|
||||
margin-top: 0.5rem;
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description.status-description-hidden {
|
||||
transform: translateY(-2rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description p {
|
||||
font-size: 18px;
|
||||
margin-left: 15px;
|
||||
margin-top: -2px;
|
||||
color: white;
|
||||
font-family: "Consolas", "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
|
||||
.aura-config-page-status-description i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aura-config-page-central-aura-logo {
|
||||
margin: 0.5rem 3rem;
|
||||
width: 17.5%;
|
||||
}
|
||||
|
||||
.aura-config-hr-vertical {
|
||||
height: 3.75rem;
|
||||
width: 1px;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
margin-left: 30px;
|
||||
margin-right: 30px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Consolas", monospace;
|
||||
color: white;
|
||||
|
||||
/*
|
||||
.version-type {
|
||||
content: "I want to use scss plz 😇"
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
.aura-config-page-status-side {
|
||||
height: 30%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
|
||||
transition: transform 0.5s, opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.left-side {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.left-side.status-side-hidden {
|
||||
transform: translateX(5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.right-side {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.aura-config-page-status-side.right-side.status-side-hidden {
|
||||
transform: translateX(-5rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el .version-type {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.aura-config-page-status-el .version-content {
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
opacity: 0.625;
|
||||
}
|
||||
37
src/aura/ui/pages/config/css/toast.css
Executable file
@@ -0,0 +1,37 @@
|
||||
.aura-config-page-toast-area {
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast {
|
||||
--bs-toast-border-width: 0 !important;
|
||||
--bs-toast-bg: #fff !important;
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header {
|
||||
background-color: rgb(255, 234, 202);
|
||||
|
||||
border-top-left-radius: var(--bs-toast-border-radius);
|
||||
border-top-right-radius: var(--bs-toast-border-radius);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast.acp-toast-emerg .toast-header {
|
||||
background-color: rgb(255, 202, 202);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header * {
|
||||
color: rgba(234, 126, 14, 0.85);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast.acp-toast-emerg .toast-header * {
|
||||
color: rgba(234, 65, 14, 0.85);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-body p {
|
||||
margin-bottom: var(--bs-toast-padding-x);
|
||||
}
|
||||
|
||||
.aura-config-page-toast-area .toast-header .layui-icon {
|
||||
font-weight: bolder;
|
||||
margin-right: 0.5rem;
|
||||
font-size: 18px;
|
||||
}
|
||||
8
src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.css
Executable file
@@ -0,0 +1,8 @@
|
||||
.aura-config-subpage-behaviour-control {
|
||||
opacity: 1;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-subpage-behaviour-control.acs-behaviour-control-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
69
src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.html
Executable file
@@ -0,0 +1,69 @@
|
||||
<div
|
||||
id="acs-behaviour-control-el"
|
||||
class="aura-config-subpage-behaviour-control acs-behaviour-control-hidden"
|
||||
>
|
||||
<ul class="nav nav-underline mb-3" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link active"
|
||||
id="status-subpage-tab"
|
||||
data-bs-toggle="pill"
|
||||
data-bs-target="#status-subpage"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="status-subpage"
|
||||
aria-selected="true"
|
||||
>
|
||||
状态
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link"
|
||||
id="basic-config-tab"
|
||||
data-bs-toggle="pill"
|
||||
data-bs-target="#basic-config-subpage"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="basic-config-subpage"
|
||||
aria-selected="false"
|
||||
>
|
||||
基本设置
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link"
|
||||
id="security-config-tab"
|
||||
data-bs-toggle="pill"
|
||||
data-bs-target="#security-config-subpage"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="security-config-subpage"
|
||||
aria-selected="false"
|
||||
>
|
||||
设备安全
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div
|
||||
class="tab-pane fade show active"
|
||||
id="status-subpage"
|
||||
role="tabpanel"
|
||||
aria-labelledby="status-subpage-tab"
|
||||
></div>
|
||||
<div
|
||||
class="tab-pane fade"
|
||||
id="basic-config-subpage"
|
||||
role="tabpanel"
|
||||
aria-labelledby="basic-config-tab"
|
||||
></div>
|
||||
<div
|
||||
class="tab-pane fade"
|
||||
id="security-config-subpage"
|
||||
role="tabpanel"
|
||||
aria-labelledby="security-config-tab"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
44
src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js
Executable file
@@ -0,0 +1,44 @@
|
||||
(() => {
|
||||
const REQUIRE_BASE =
|
||||
"../../aura/ui/pages/configSubPages/behaviourCtrl/settings";
|
||||
|
||||
const {
|
||||
settingsRenderer,
|
||||
} = require(`${REQUIRE_BASE}/../../../../composables/settingsRenderer`);
|
||||
|
||||
const { basicSettings } = require(`${REQUIRE_BASE}/basic`);
|
||||
|
||||
const {
|
||||
updatePlsSettingsFromLocal,
|
||||
updatePlsRulesFromLocal,
|
||||
} = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`);
|
||||
|
||||
const initStatusPage = () => {
|
||||
global.__HUGO_AURA_LOADER__[
|
||||
"Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus"
|
||||
].active = true;
|
||||
};
|
||||
|
||||
const initBasicSettingsPage = () => {
|
||||
const basicSubPageEl = document.getElementById("basic-config-subpage");
|
||||
settingsRenderer(basicSubPageEl, basicSettings);
|
||||
};
|
||||
|
||||
const renderSubPages = async () => {
|
||||
await updatePlsSettingsFromLocal();
|
||||
await updatePlsRulesFromLocal();
|
||||
|
||||
initBasicSettingsPage();
|
||||
};
|
||||
|
||||
const onMounted = () => {
|
||||
const rootEl = document.getElementById("acs-behaviour-control-el");
|
||||
initStatusPage();
|
||||
renderSubPages();
|
||||
setTimeout(() => {
|
||||
rootEl.classList.remove("acs-behaviour-control-hidden");
|
||||
}, 500);
|
||||
};
|
||||
|
||||
onMounted();
|
||||
})();
|
||||
139
src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css
Executable file
@@ -0,0 +1,139 @@
|
||||
.acs-behaviour-control-pls-status-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.acs-behaviour-control-pls-status-page p {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-pls-description {
|
||||
margin-top: 0.5rem;
|
||||
max-width: 80%;
|
||||
opacity: 0.35;
|
||||
font-size: small;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-main-logo {
|
||||
max-width: 11%;
|
||||
opacity: 0.45;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operations-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn {
|
||||
--svg-color: rgb(17, 140, 255);
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: 0.75rem;
|
||||
margin-right: 0.75rem;
|
||||
|
||||
transition: opacity 0.25s, color 0.5s;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn p {
|
||||
font-size: normal;
|
||||
margin-left: 5px;
|
||||
margin-top: -1px;
|
||||
color: var(--svg-color);
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn svg {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn.acs-bc-psp-o-btn-dangerous {
|
||||
--svg-color: rgb(244, 8, 8);
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn[aura-disabled="true"] {
|
||||
--svg-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn[aura-disabled="true"]:hover,
|
||||
.acs-bc-psp-operation-btn[aura-disabled="true"]:active {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn:hover,
|
||||
.acs-bc-psp-operation-btn:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.acs-bc-psp-operation-btn:active {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-el {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 40%;
|
||||
padding: 0.625rem 0.25rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-el div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area {
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area-circle {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
border-radius: 100%;
|
||||
margin-right: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.pending
|
||||
.acs-bc-pls-status-page-status-area-circle {
|
||||
background-color: rgba(0, 0, 0, 0.375);
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.pending p {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.success
|
||||
.acs-bc-pls-status-page-status-area-circle {
|
||||
background-color: rgb(0, 175, 38);
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.success p {
|
||||
color: rgb(0, 150, 33);
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.failed
|
||||
.acs-bc-pls-status-page-status-area-circle {
|
||||
background-color: rgb(175, 0, 0);
|
||||
}
|
||||
|
||||
.acs-bc-pls-status-page-status-area.failed p {
|
||||
color: rgb(175, 0, 0);
|
||||
}
|
||||
136
src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html
Executable file
@@ -0,0 +1,136 @@
|
||||
<div class="acs-behaviour-control-pls-status-page">
|
||||
<p class="acs-bc-pls-status-page-pls-description">
|
||||
HugoAura ProxyLayerServices (Aura-PLS) 是基于 Python + MITMProxy
|
||||
实现的代理服务, 用于解密并修改希沃基础服务 (SeewoCore) 的 MQTT 数据包,
|
||||
实现行为监控、伪造上报等功能
|
||||
</p>
|
||||
<img
|
||||
src="../../aura/ui/static/aura_pls.png"
|
||||
class="acs-bc-pls-status-page-main-logo"
|
||||
/>
|
||||
|
||||
<div class="acs-bc-psp-operations-container">
|
||||
<div class="acs-bc-psp-operation-btn" id="acsBcPsp-operBtn-Refresh">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M26 18A10 10 0 1 1 16 8h6.182l-3.584 3.585L20 13l6-6l-6-6l-1.402 1.414L22.185 6H16a12 12 0 1 0 12 12Z"
|
||||
/>
|
||||
</svg>
|
||||
<p>刷新状态</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="acs-bc-psp-operation-btn"
|
||||
aura-disabled="true"
|
||||
id="acsBcPsp-operBtn-Download"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M23.5 22H23v-2h.5a4.5 4.5 0 0 0 .36-9H23l-.1-.82a7 7 0 0 0-13.88 0L9 11h-.86a4.5 4.5 0 0 0 .36 9H9v2h-.5A6.5 6.5 0 0 1 7.2 9.14a9 9 0 0 1 17.6 0A6.5 6.5 0 0 1 23.5 22"
|
||||
/>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M17 26.17V14h-2v12.17l-2.59-2.58L11 25l5 5l5-5l-1.41-1.41z"
|
||||
/>
|
||||
</svg>
|
||||
<p>下载内核</p>
|
||||
</div>
|
||||
|
||||
<div class="acs-bc-psp-operation-btn" id="acsBcPsp-operBtn-Install">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="m10 6l1.414-1.414L15 8.172V0h2v8.172l3.586-3.586L22 6l-6 6z"
|
||||
/>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M22 16a5.98 5.98 0 0 0-1.757-4.243L16 16l-4.243-4.243A6 6 0 1 0 22 16"
|
||||
/>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M30 16a13.96 13.96 0 0 0-4.105-9.895l-1.414 1.414a12 12 0 1 1-16.962 0L6.105 6.105A13.997 13.997 0 1 0 30 16"
|
||||
/>
|
||||
</svg>
|
||||
<p>安装服务</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="acs-bc-psp-operation-btn acs-bc-psp-o-btn-dangerous"
|
||||
id="acsBcPsp-operBtn-Uninstall"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M30 21.4L28.6 20L25 23.6L21.4 20L20 21.4l3.6 3.6l-3.6 3.6l1.4 1.4l3.6-3.6l3.6 3.6l1.4-1.4l-3.6-3.6z"
|
||||
/>
|
||||
<path
|
||||
fill="var(--svg-color)"
|
||||
d="M15.4 30L5 23.8c-.6-.4-1-1-1-1.7V9.9c0-.7.4-1.4 1-1.7l10-5.9c.3-.2.6-.3 1-.3s.7.1 1 .3l10 5.9c.6.4 1 1 1 1.7V16h-2V9.9L16 4L6 9.9v12.2l10.5 6.2z"
|
||||
/>
|
||||
</svg>
|
||||
<p>卸载服务</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="acs-bc-pls-status-page-status-el">
|
||||
<p>安装状态</p>
|
||||
<div
|
||||
class="acs-bc-pls-status-page-status-area pending"
|
||||
id="acs-bc-psp-installStatus-container"
|
||||
>
|
||||
<span class="acs-bc-pls-status-page-status-area-circle"></span>
|
||||
<p id="acs-bc-psp-installStatus-text">未安装</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="acs-bc-pls-status-page-status-el">
|
||||
<p>启动状态</p>
|
||||
<div
|
||||
class="acs-bc-pls-status-page-status-area pending"
|
||||
id="acs-bc-psp-launchStatus-container"
|
||||
>
|
||||
<span class="acs-bc-pls-status-page-status-area-circle"></span>
|
||||
<p id="acs-bc-psp-launchStatus-text">未启动</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="acs-bc-pls-status-page-status-el">
|
||||
<p>连接状态</p>
|
||||
<div
|
||||
class="acs-bc-pls-status-page-status-area pending"
|
||||
id="acs-bc-psp-connStatus-container"
|
||||
>
|
||||
<span class="acs-bc-pls-status-page-status-area-circle"></span>
|
||||
<p id="acs-bc-psp-connStatus-text">已断开</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="acs-bc-pls-status-page-status-el" style="border-bottom: none">
|
||||
<p>版本</p>
|
||||
<div class="acs-bc-pls-status-page-status-area">
|
||||
<p id="acs-bc-psp-version-text">不可用</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
167
src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js
Executable file
@@ -0,0 +1,167 @@
|
||||
if (!global.__HUGO_AURA_UI_FUNCTIONS__.subConfig)
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig = {};
|
||||
|
||||
(() => {
|
||||
const REQUIRE_BASE = "../../aura/ui/pages/configSubPages/behaviourCtrl";
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus = {
|
||||
updateOperationBtnStatus: async (btnName, side, btnContent = null) => {
|
||||
const btnEl = document.getElementById(`acsBcPsp-operBtn-${btnName}`);
|
||||
if (!btnEl) return false;
|
||||
btnEl.setAttribute("aura-disabled", side ? "true" : "false");
|
||||
if (btnContent) {
|
||||
const btnPEl = btnEl.getElementsByTagName("p")[0];
|
||||
btnPEl.textContent = btnContent;
|
||||
}
|
||||
if (side) {
|
||||
btnEl.onclick = () => {};
|
||||
} else {
|
||||
switch (btnName) {
|
||||
case "Refresh":
|
||||
btnEl.onclick = () =>
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.refreshPlsStatus();
|
||||
break;
|
||||
case "Download":
|
||||
break;
|
||||
case "Install":
|
||||
break;
|
||||
case "Uninstall":
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
updateStatus: async () => {
|
||||
const curPlsStats = await updatePlsStatusFromLocal();
|
||||
|
||||
const acIdInst = "acs-bc-psp-installStatus-container";
|
||||
const atIdInst = "acs-bc-psp-installStatus-text";
|
||||
switch (curPlsStats.installed) {
|
||||
case true:
|
||||
updateStatusEl(acIdInst, atIdInst, "SUCCESS", "已安装");
|
||||
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", false);
|
||||
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Uninstall", false);
|
||||
break;
|
||||
case false:
|
||||
updateStatusEl(acIdInst, atIdInst, "PENDING", "未安装");
|
||||
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true);
|
||||
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Uninstall", true);
|
||||
}
|
||||
|
||||
const acIdLaunch = "acs-bc-psp-launchStatus-container";
|
||||
const atIdLaunch = "acs-bc-psp-launchStatus-text";
|
||||
switch (curPlsStats.launched) {
|
||||
case true:
|
||||
updateStatusEl(acIdLaunch, atIdLaunch, "SUCCESS", "已启动");
|
||||
break;
|
||||
case false:
|
||||
updateStatusEl(acIdLaunch, atIdLaunch, "PENDING", "未启动");
|
||||
break;
|
||||
}
|
||||
|
||||
const acIdConn = "acs-bc-psp-connStatus-container";
|
||||
const atIdConn = "acs-bc-psp-connStatus-text";
|
||||
switch (curPlsStats.connected) {
|
||||
case true:
|
||||
updateStatusEl(acIdConn, atIdConn, "SUCCESS", "已连接");
|
||||
break;
|
||||
case false:
|
||||
updateStatusEl(acIdConn, atIdConn, "FAILED", "连接失败");
|
||||
break;
|
||||
}
|
||||
|
||||
if (curPlsStats.version && curPlsStats.version !== "未知") {
|
||||
const versionTextEl = document.getElementById(
|
||||
"acs-bc-psp-version-text"
|
||||
);
|
||||
versionTextEl.textContent = "v" + curPlsStats.version;
|
||||
}
|
||||
},
|
||||
|
||||
refreshPlsStatus: async () => {
|
||||
const updateOperationBtnStatus =
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus
|
||||
.updateOperationBtnStatus;
|
||||
updateOperationBtnStatus("Refresh", true);
|
||||
const result = await ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.retryPlsConnect`
|
||||
);
|
||||
if (result.success && result.status === "Retrying") {
|
||||
updateOperationBtnStatus("Refresh", true, "正在重连");
|
||||
|
||||
ipcRenderer.once(
|
||||
`${IPC_METHOD_BASE}.post.updateRetryStatus`,
|
||||
async (_evt, _arg) => {
|
||||
await global.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
updateOperationBtnStatus("Refresh", false, "刷新状态");
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatus();
|
||||
}
|
||||
);
|
||||
} else if (result.success && result.status === "Already") {
|
||||
updateOperationBtnStatus("Refresh", false, "刷新状态");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const GLOBAL_FUNCTIONS =
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus;
|
||||
|
||||
const {
|
||||
updatePlsStatusFromLocal,
|
||||
} = require(`${REQUIRE_BASE}/../../../composables/plsConfigManager`);
|
||||
|
||||
const initBsTooltip = () => {
|
||||
const tooltipTriggerList = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]'
|
||||
);
|
||||
const _tooltipList = [...tooltipTriggerList].map(
|
||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
);
|
||||
};
|
||||
|
||||
const updateStatusEl = (
|
||||
areaContainerId,
|
||||
areaTextId,
|
||||
target,
|
||||
text = false
|
||||
) => {
|
||||
const areaContainerEl = document.getElementById(areaContainerId);
|
||||
const areaContainerText = document.getElementById(areaTextId);
|
||||
switch (target) {
|
||||
case "PENDING":
|
||||
areaContainerEl.className =
|
||||
"acs-bc-pls-status-page-status-area pending";
|
||||
break;
|
||||
case "SUCCESS":
|
||||
areaContainerEl.className =
|
||||
"acs-bc-pls-status-page-status-area success";
|
||||
break;
|
||||
case "FAILED":
|
||||
areaContainerEl.className = "acs-bc-pls-status-page-status-area failed";
|
||||
break;
|
||||
case "WARNING":
|
||||
areaContainerEl.className =
|
||||
"acs-bc-pls-status-page-status-area warning";
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
areaContainerText.textContent = text ? text : "";
|
||||
return true;
|
||||
};
|
||||
|
||||
const onMounted = () => {
|
||||
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
|
||||
initBsTooltip();
|
||||
GLOBAL_FUNCTIONS.updateStatus();
|
||||
document.addEventListener("onPLSStatsUpdate", () => {
|
||||
GLOBAL_FUNCTIONS.updateStatus();
|
||||
});
|
||||
};
|
||||
|
||||
onMounted();
|
||||
})();
|
||||
79
src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js
Executable file
@@ -0,0 +1,79 @@
|
||||
const REQUIRE_BASE = ".";
|
||||
|
||||
const {
|
||||
updatePlsConfigToRemote,
|
||||
} = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`);
|
||||
|
||||
const basicSettings = [
|
||||
{
|
||||
id: 0,
|
||||
categoryName: "可访问性",
|
||||
child: [
|
||||
/*
|
||||
{
|
||||
index: 0,
|
||||
id: "authToken",
|
||||
type: "input",
|
||||
subType: "text",
|
||||
name: "WebSocket 认证密钥",
|
||||
description: "选择一个安全的密钥, 用于 PLS 侧验证 Aura 前端身份",
|
||||
restart: true,
|
||||
reload: false,
|
||||
restartPLS: true,
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: "",
|
||||
placeHolder: "输入一个密钥",
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.plsToken;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (newVal === "" || !newVal)
|
||||
return { valid: false, hint: "请输入认证密钥" };
|
||||
|
||||
if (newVal.length < 8) {
|
||||
return { valid: false, hint: "至少输入 8 位字符" };
|
||||
}
|
||||
|
||||
global.__HUGO_AURA_CONFIG__.plsToken = newVal;
|
||||
return { valid: true };
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
index: 0,
|
||||
id: "plsListenPort",
|
||||
type: "input",
|
||||
subType: "text",
|
||||
name: "PLS WS 监听端口",
|
||||
description: "PLS 的 WebSocket 服务器将监听指定的端口",
|
||||
restart: false,
|
||||
reload: false,
|
||||
PLSRequired: true,
|
||||
restartPLS: true,
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: "",
|
||||
placeHolder: "输入端口号 (10000 ~ 65535)",
|
||||
valueGetter: () => {
|
||||
if (!global.__HUGO_AURA__.plsSettings) return "";
|
||||
return global.__HUGO_AURA__.plsSettings.wsPort;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (newVal === "" || !newVal)
|
||||
return { valid: false, hint: "请输入端口号" };
|
||||
|
||||
const numberNewVal = Number(newVal);
|
||||
if (numberNewVal === NaN || !(10000 <= numberNewVal <= 65535)) {
|
||||
return { valid: false, hint: "请输入合法的端口号 (10000 ~ 65535)" };
|
||||
}
|
||||
|
||||
global.__HUGO_AURA__.plsSettings.wsPort = numberNewVal;
|
||||
return { valid: true };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = { basicSettings };
|
||||
1
src/aura/ui/pages/configSubPages/disableLimitations/disableLimitations.css
Normal file → Executable file
@@ -1,6 +1,5 @@
|
||||
.aura-config-subpage-disable-limit-root {
|
||||
opacity: 1;
|
||||
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
|
||||
2
src/aura/ui/pages/configSubPages/disableLimitations/disableLimitations.html
Normal file → Executable file
@@ -14,7 +14,7 @@
|
||||
aria-controls="auth-subpage"
|
||||
aria-selected="true"
|
||||
>
|
||||
认证与基础设施
|
||||
认证与环境
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
|
||||
0
src/aura/ui/pages/configSubPages/disableLimitations/disableLimitations.js
Normal file → Executable file
6
src/aura/ui/pages/configSubPages/disableLimitations/settings/audit.js
Normal file → Executable file
@@ -8,7 +8,8 @@ const banAuditSettings = [
|
||||
id: "disableFridayReport",
|
||||
type: "switch",
|
||||
name: "禁用 Friday 错误统计",
|
||||
description: "重置 CVTE 的 Friday 错误收集服务载入 URL, 避免意外的信息上传",
|
||||
description:
|
||||
"重置 CVTE 的 Friday 错误收集服务载入 URL, 避免意外的信息上传",
|
||||
restart: true,
|
||||
reload: false,
|
||||
associateVal: null,
|
||||
@@ -39,7 +40,8 @@ const banAuditSettings = [
|
||||
restart: true,
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: '启用后, 可能造成部分操作出现较长延迟 (如冰点操作)。希沃管家会尝试五次上报, 均失败后才会进行下一步操作',
|
||||
tipTitle:
|
||||
"启用后, 可能造成部分操作出现较长延迟 (如冰点操作)。希沃管家会尝试五次上报, 均失败后才会进行下一步操作",
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: false,
|
||||
|
||||
134
src/aura/ui/pages/configSubPages/disableLimitations/settings/auth.js
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
const authSettings = [
|
||||
{
|
||||
id: 0,
|
||||
categoryName: "身份验证",
|
||||
categoryName: "管家身份验证",
|
||||
child: [
|
||||
{
|
||||
index: 0,
|
||||
@@ -114,8 +114,8 @@ const authSettings = [
|
||||
].enabled;
|
||||
},
|
||||
defaultValue: "hybrid",
|
||||
templates: ["hybrid", "remoteOnly", "passwordOnly"],
|
||||
templateLabels: ["混合", "仅二维码", "仅密码"],
|
||||
templates: ["default", "hybrid", "remoteOnly", "passwordOnly"],
|
||||
templateLabels: ["默认", "混合", "仅二维码", "仅密码"],
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite[
|
||||
"vendor/passwordValidation"
|
||||
@@ -131,6 +131,131 @@ const authSettings = [
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
categoryName: "屏幕锁",
|
||||
child: [
|
||||
{
|
||||
index: 0,
|
||||
id: "enableScreenLockOverride",
|
||||
type: "switch",
|
||||
name: "启用屏幕锁覆写功能",
|
||||
description: "覆写希沃管家的屏幕锁组件, 绕过限制",
|
||||
restart: false,
|
||||
reload: false,
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: true,
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.enabled;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (typeof newVal !== "boolean") return;
|
||||
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"].enabled =
|
||||
newVal;
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
id: "disableKeyboardHook",
|
||||
type: "switch",
|
||||
name: "允许快捷键操作",
|
||||
description: "屏蔽键盘 DLL Hook, 允许在屏幕锁中操作快捷键",
|
||||
restart: false,
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: "此功能正在测试中, 可能并不稳定",
|
||||
associateVal: ["rewrite.vendor/screenLock.enabled"],
|
||||
auraIf: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.enabled;
|
||||
},
|
||||
defaultValue: false,
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.disableKeyboardHook;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (typeof newVal !== "boolean") return;
|
||||
global.__HUGO_AURA_CONFIG__.rewrite[
|
||||
"vendor/screenLock"
|
||||
].disableKeyboardHook = newVal;
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
id: "screenLockAuthOverrideType",
|
||||
type: "radio",
|
||||
name: "覆写模式",
|
||||
description: "选择一个认证覆写模式",
|
||||
restart: false,
|
||||
reload: false,
|
||||
associateVal: ["rewrite.vendor/screenLock.enabled"],
|
||||
auraIf: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.enabled;
|
||||
},
|
||||
defaultValue: "none",
|
||||
templates: ["customActivationCode", "none"],
|
||||
templateLabels: ["自定义激活码", "不修改"],
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.authRewriteType;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
global.__HUGO_AURA_CONFIG__.rewrite[
|
||||
"vendor/screenLock"
|
||||
].authRewriteType = newVal;
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
id: "customActivationCode",
|
||||
type: "input",
|
||||
subType: "password",
|
||||
name: "自定义激活码",
|
||||
description: '请在屏幕锁页面下方选择 "激活码解锁" 以使用',
|
||||
restart: false,
|
||||
reload: false,
|
||||
warning: true,
|
||||
warningContent: "密码为 6 位纯数字",
|
||||
associateVal: [
|
||||
"rewrite.vendor/screenLock.enabled",
|
||||
"rewrite.vendor/screenLock.authRewriteType",
|
||||
],
|
||||
auraIf: () => {
|
||||
return (
|
||||
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"].enabled &&
|
||||
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
|
||||
.authRewriteType === "customActivationCode"
|
||||
);
|
||||
},
|
||||
defaultValue: "",
|
||||
placeHolder: "留空表示不修改, 保留已设置值",
|
||||
valueGetter: () => {
|
||||
return "";
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (newVal === "" || !newVal) return { valid: true };
|
||||
if (newVal.length !== 6)
|
||||
return { valid: false, hint: "仅可输入 6 位密码" };
|
||||
if (!/^\d+$/.test(newVal)) {
|
||||
return { valid: false, hint: "仅允许纯数字密码" };
|
||||
}
|
||||
const __config =
|
||||
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"];
|
||||
const crypto = require("crypto");
|
||||
const result = crypto
|
||||
.createHash("md5")
|
||||
.update(newVal + "auraScreenLockCrack")
|
||||
.digest("hex");
|
||||
__config.customActivationCode.activationCodeWithSalt = result;
|
||||
return { valid: true };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
categoryName: "基础设施",
|
||||
child: [
|
||||
{
|
||||
@@ -143,6 +268,9 @@ const authSettings = [
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: "启用后, 按下 Ctrl + Shift + I 即可打开 DevTools",
|
||||
warning: true,
|
||||
warningContent:
|
||||
"在操作不当的情况下, 有可能造成 DevTools 永久无法激活 (Electron 的 Bug), 此时请使用 Chrome 远程调试",
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: false,
|
||||
|
||||
8
src/aura/ui/pages/configSubPages/preferences/preferences.css
Executable file
@@ -0,0 +1,8 @@
|
||||
.aura-config-subpage-preferences-root {
|
||||
opacity: 1;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.aura-config-subpage-preferences-root.acs-preferences-root-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
49
src/aura/ui/pages/configSubPages/preferences/preferences.html
Executable file
@@ -0,0 +1,49 @@
|
||||
<div
|
||||
id="acs-preferences-root-el"
|
||||
class="aura-config-subpage-preferences-root acs-preferences-root-hidden"
|
||||
>
|
||||
<ul class="nav nav-underline mb-3" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link active"
|
||||
id="aura-subpage-tab"
|
||||
data-bs-toggle="pill"
|
||||
data-bs-target="#aura-subpage"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="aura-subpage"
|
||||
aria-selected="true"
|
||||
>
|
||||
Aura 设置
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class="nav-link"
|
||||
id="about-subpage-tab"
|
||||
data-bs-toggle="pill"
|
||||
data-bs-target="#about-subpage"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="about-subpage"
|
||||
aria-selected="true"
|
||||
>
|
||||
关于项目
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div
|
||||
class="tab-pane fade show active"
|
||||
id="aura-subpage"
|
||||
role="tabpanel"
|
||||
aria-labelledby="aura-subpage-tab"
|
||||
></div>
|
||||
<div
|
||||
class="tab-pane fade"
|
||||
id="about-subpage"
|
||||
role="tabpanel"
|
||||
aria-labelledby="about-subpage-tab"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
23
src/aura/ui/pages/configSubPages/preferences/preferences.js
Executable file
@@ -0,0 +1,23 @@
|
||||
(() => {
|
||||
const pathBase = "../../aura/ui/pages/configSubPages/preferences/settings";
|
||||
|
||||
const {
|
||||
settingsRenderer,
|
||||
} = require("../../aura/ui/composables/settingsRenderer");
|
||||
const { auraSettings } = require(`${pathBase}/aura`);
|
||||
|
||||
const initAuraSubPage = () => {
|
||||
const auraSettingsSubPageEl = document.getElementById("aura-subpage");
|
||||
settingsRenderer(auraSettingsSubPageEl, auraSettings);
|
||||
};
|
||||
const onMounted = () => {
|
||||
initAuraSubPage();
|
||||
|
||||
const rootEl = document.getElementById("acs-preferences-root-el");
|
||||
setTimeout(() => {
|
||||
rootEl.classList.remove("acs-preferences-root-hidden");
|
||||
}, 500);
|
||||
};
|
||||
|
||||
onMounted();
|
||||
})();
|
||||
296
src/aura/ui/pages/configSubPages/preferences/settings/aura.js
Executable file
@@ -0,0 +1,296 @@
|
||||
// @ts-check
|
||||
|
||||
const functions = {
|
||||
/**
|
||||
*
|
||||
* @param {"enc" | "update"} mode
|
||||
* @param {SHA256EncryptedPassword | null} password
|
||||
*/
|
||||
handleEnableConfigEncryption: async (mode, password) => {
|
||||
let exiPassword = "";
|
||||
if (!password) {
|
||||
exiPassword =
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case "enc":
|
||||
ipcRenderer.invoke("$aura.config.setConfigEncSettings", {
|
||||
target: true,
|
||||
});
|
||||
global.ipcRenderer.invoke("$aura.config.dispatchConfigFromRenderer", {
|
||||
data: JSON.stringify(global.__HUGO_AURA_CONFIG__),
|
||||
});
|
||||
global.__HUGO_AURA_CONFIG_MGR__.encryptConfig(
|
||||
global.__HUGO_AURA_CONFIG__,
|
||||
password ? password : exiPassword
|
||||
);
|
||||
global.__HUGO_AURA_CONFIG_MGR__.saveEncPassword(
|
||||
password ? password : exiPassword
|
||||
);
|
||||
break;
|
||||
case "update":
|
||||
const result = global.__HUGO_AURA_CONFIG_MGR__.switchToDecConfig(
|
||||
global.__HUGO_AURA_CONFIG__,
|
||||
null
|
||||
);
|
||||
if (result.success) {
|
||||
ipcRenderer.invoke("$aura.config.setConfigEncSettings", {
|
||||
target: true,
|
||||
});
|
||||
global.ipcRenderer.invoke("$aura.config.dispatchConfigFromRenderer", {
|
||||
data: JSON.stringify(global.__HUGO_AURA_CONFIG__),
|
||||
});
|
||||
global.__HUGO_AURA_CONFIG_MGR__.encryptConfig(
|
||||
global.__HUGO_AURA_CONFIG__,
|
||||
password ? password : exiPassword
|
||||
);
|
||||
global.__HUGO_AURA_CONFIG_MGR__.saveEncPassword(
|
||||
password ? password : exiPassword
|
||||
);
|
||||
} else {
|
||||
// TODO: Error handling
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {SHA256EncryptedPassword} password
|
||||
*/
|
||||
handle2ndPasswordPrompt: async (password) => {
|
||||
const acsDialogAreaEl = document.getElementsByClassName(
|
||||
"aura-config-page-auth-dialog-area"
|
||||
)[0];
|
||||
const acpAppBarEl = document.getElementsByClassName(
|
||||
"aura-config-page-header-area"
|
||||
)[0];
|
||||
const acpDialogTitleEl = document.getElementsByClassName(
|
||||
"acp-auth-dialog-title"
|
||||
)[0];
|
||||
const acpDialogConfirmBtnEl = document.getElementsByClassName(
|
||||
"acp-auth-confirm-btn"
|
||||
)[0];
|
||||
const acpDialogCancelBtnEl = document.getElementsByClassName(
|
||||
"acp-auth-cancel-btn"
|
||||
)[0];
|
||||
// @ts-expect-error
|
||||
acsDialogAreaEl.style = "";
|
||||
acpDialogTitleEl.textContent = "请再次输入密码";
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
acpAppBarEl.classList.add("color-reverse");
|
||||
acsDialogAreaEl.classList.remove("acp-ada-hidden");
|
||||
|
||||
const showFailedAnimation = async (el) => {
|
||||
el.classList.remove("invalid");
|
||||
await window.__HUGO_AURA_GLOBAL__.utils.sleep(50);
|
||||
el.classList.add("invalid"); // Custom Anim
|
||||
el.classList.add("is-invalid"); // Bootstrap
|
||||
};
|
||||
|
||||
let resolveFn = null;
|
||||
const awaitCompletePromise = new Promise((resolve) => {
|
||||
resolveFn = resolve;
|
||||
});
|
||||
|
||||
const handleExit = async () => {
|
||||
const result = await awaitCompletePromise;
|
||||
console.debug(result);
|
||||
if (result) {
|
||||
console.debug("ret true");
|
||||
return { valid: true };
|
||||
} else {
|
||||
console.debug("ret false");
|
||||
const inputEl = document.getElementById("auraSettingsPasswd");
|
||||
// @ts-expect-error
|
||||
inputEl.value = "";
|
||||
return { valid: false, hint: "未能验证密码, 请重试" };
|
||||
}
|
||||
};
|
||||
|
||||
const verifyPassword = async (_clickEvt) => {
|
||||
const inputEl = document.getElementById("acp-auth-user-input");
|
||||
const acpDialogTitleEl = document.getElementsByClassName(
|
||||
"acp-auth-dialog-title"
|
||||
)[0];
|
||||
// @ts-expect-error
|
||||
const userPasswdInput = inputEl.value;
|
||||
if (!userPasswdInput) {
|
||||
showFailedAnimation(inputEl);
|
||||
acpDialogTitleEl.textContent = "密码不能为空";
|
||||
}
|
||||
|
||||
const crypto = require("crypto");
|
||||
const encPasswd = crypto
|
||||
.createHash("sha512")
|
||||
.update(userPasswdInput + "EndlessX")
|
||||
.digest("hex")
|
||||
.toUpperCase();
|
||||
|
||||
if (encPasswd === password) {
|
||||
await global.__HUGO_AURA_UI_FUNCTIONS__.config.hideAndResetAuthDialog();
|
||||
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt =
|
||||
password;
|
||||
if (global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig) {
|
||||
functions.handleEnableConfigEncryption("update", password);
|
||||
}
|
||||
if (resolveFn) resolveFn(true);
|
||||
return;
|
||||
} else {
|
||||
showFailedAnimation(inputEl);
|
||||
acpDialogTitleEl.textContent = "请再试一次";
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// @ts-expect-error
|
||||
acpDialogConfirmBtnEl.onclick = verifyPassword;
|
||||
// @ts-expect-error
|
||||
acpDialogCancelBtnEl.onclick = (_evt) => {
|
||||
if (resolveFn) resolveFn(false);
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.handleNavBack();
|
||||
};
|
||||
|
||||
return await handleExit();
|
||||
},
|
||||
};
|
||||
|
||||
const auraSettings = [
|
||||
{
|
||||
id: 0,
|
||||
categoryName: "安全性",
|
||||
child: [
|
||||
{
|
||||
index: 0,
|
||||
id: "enableAuraSettingsPasswd",
|
||||
type: "switch",
|
||||
name: "启用访问密码",
|
||||
description: "启用后, Aura 设置 UI 需要输入密码才可访问",
|
||||
restart: false,
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: "启用访问密码将自动加密配置文件",
|
||||
associateVal: null,
|
||||
auraIf: () => true,
|
||||
defaultValue: false,
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.auraSettings
|
||||
.settingsPasswordEnabled;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (typeof newVal !== "boolean") return;
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordEnabled =
|
||||
newVal;
|
||||
if (
|
||||
newVal &&
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig
|
||||
) {
|
||||
functions.handleEnableConfigEncryption("enc", null);
|
||||
} else if (
|
||||
!newVal &&
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig
|
||||
) {
|
||||
global.__HUGO_AURA_CONFIG_MGR__.switchToDecConfig(
|
||||
global.__HUGO_AURA_CONFIG__,
|
||||
null
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
id: "enableConfigEncryption",
|
||||
type: "switch",
|
||||
name: "加密配置文件",
|
||||
description: "启用后, 本地配置文件将加密保存",
|
||||
restart: false,
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: "配置文件将以 AES-256-GCM 加密算法在本地保存",
|
||||
warning: true,
|
||||
warningContent: "这可能导致性能问题",
|
||||
associateVal: ["auraSettings.settingsPasswordEnabled"],
|
||||
auraIf: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.auraSettings
|
||||
.settingsPasswordEnabled;
|
||||
},
|
||||
defaultValue: false,
|
||||
valueGetter: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig;
|
||||
},
|
||||
callbackFn: (newVal) => {
|
||||
if (typeof newVal !== "boolean") return;
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig = newVal;
|
||||
if (newVal) {
|
||||
functions.handleEnableConfigEncryption("enc", null);
|
||||
} else {
|
||||
global.__HUGO_AURA_CONFIG_MGR__.switchToDecConfig(
|
||||
global.__HUGO_AURA_CONFIG__,
|
||||
null
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
id: "auraSettingsPasswd",
|
||||
type: "input",
|
||||
subType: "password",
|
||||
name: "访问密码",
|
||||
description: "此密码将用于访问 Aura 设置 UI",
|
||||
restart: false,
|
||||
reload: false,
|
||||
tip: true,
|
||||
tipTitle: "密码将在本地使用 SHA512 加盐存储",
|
||||
associateVal: ["auraSettings.settingsPasswordEnabled"],
|
||||
auraIf: () => {
|
||||
return global.__HUGO_AURA_CONFIG__.auraSettings
|
||||
.settingsPasswordEnabled;
|
||||
},
|
||||
defaultValue: "",
|
||||
placeHolder: "留空表示不修改, 保留已设置值",
|
||||
valueGetter: () => {
|
||||
return "";
|
||||
},
|
||||
callbackFn: async (newVal) => {
|
||||
if (newVal === "" || !newVal) return { valid: true };
|
||||
if (newVal.length < 8)
|
||||
return { valid: false, hint: "请输入至少 8 位密码" };
|
||||
|
||||
const hasNumber = /[0-9]/.test(newVal);
|
||||
const hasLetter = /[a-zA-Z]/.test(newVal);
|
||||
const hasSpecial = /[^a-zA-Z0-9]/.test(newVal);
|
||||
|
||||
const typeCount = [hasNumber, hasLetter, hasSpecial].filter(
|
||||
Boolean
|
||||
).length;
|
||||
|
||||
if (typeCount < 2) {
|
||||
return {
|
||||
valid: false,
|
||||
hint: "请包含数字 / 字母 / 特殊字符中的至少 2 种",
|
||||
};
|
||||
}
|
||||
|
||||
const crypto = require("crypto");
|
||||
const result = crypto
|
||||
.createHash("sha512")
|
||||
.update(newVal + "EndlessX")
|
||||
.digest("hex")
|
||||
.toUpperCase();
|
||||
|
||||
return await functions.handle2ndPasswordPrompt(result);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
categoryName: "外观",
|
||||
child: [],
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = { auraSettings };
|
||||
0
src/aura/ui/pages/headerIcon/headerIcon.css
Normal file → Executable file
0
src/aura/ui/pages/headerIcon/headerIcon.html
Normal file → Executable file
0
src/aura/ui/pages/headerIcon/headerIcon.js
Normal file → Executable file
30
src/aura/ui/pls/pushHandler.js
Executable file
@@ -0,0 +1,30 @@
|
||||
// @ts-check
|
||||
|
||||
const REQUIRE_BASE = ".";
|
||||
|
||||
const { basicRouteHandler } = require(`${REQUIRE_BASE}/routes/basic`);
|
||||
const { configRouteHandler } = require(`${REQUIRE_BASE}/routes/config`);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {PLSPush} parsedWsMsg
|
||||
* @returns
|
||||
*/
|
||||
const pushMsgHandler = (parsedWsMsg) => {
|
||||
if (!parsedWsMsg.type) return false;
|
||||
|
||||
const msgCategory = parsedWsMsg.type.split(".")[0];
|
||||
|
||||
switch (msgCategory) {
|
||||
case "basic":
|
||||
basicRouteHandler(parsedWsMsg);
|
||||
break;
|
||||
case "config":
|
||||
configRouteHandler(parsedWsMsg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { pushMsgHandler };
|
||||
33
src/aura/ui/pls/routes/basic.js
Executable file
@@ -0,0 +1,33 @@
|
||||
// @ts-check
|
||||
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {PLSPush} parsedWsMsg
|
||||
* @returns
|
||||
*/
|
||||
const basicRouteHandler = (parsedWsMsg) => {
|
||||
const target = parsedWsMsg.type.split(".").slice(-1)[0];
|
||||
switch (target) {
|
||||
case "pushPlsInfo":
|
||||
global.__HUGO_AURA__.plsStats.status = parsedWsMsg.data.status;
|
||||
global.__HUGO_AURA__.plsStats.version = parsedWsMsg.data.version;
|
||||
|
||||
global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.updatePlsStats`,
|
||||
global.__HUGO_AURA__.plsStats
|
||||
);
|
||||
|
||||
console.debug(
|
||||
"[HugoAura / UI / PLS Routes / DEBUG] Updated plsStats basic info:",
|
||||
global.__HUGO_AURA__.plsStats
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = { basicRouteHandler };
|
||||
32
src/aura/ui/pls/routes/config.js
Executable file
@@ -0,0 +1,32 @@
|
||||
// @ts-check
|
||||
|
||||
const IPC_METHOD_BASE = "$aura.pls";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {PLSPush} parsedWsMsg
|
||||
* @returns
|
||||
*/
|
||||
const configRouteHandler = (parsedWsMsg) => {
|
||||
const target = parsedWsMsg.type.split(".").slice(-1)[0];
|
||||
switch (target) {
|
||||
case "pushBasicConfig":
|
||||
global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.updatePlsSettings`,
|
||||
parsedWsMsg.data
|
||||
);
|
||||
break;
|
||||
case "pushRuleSettings":
|
||||
global.ipcRenderer.invoke(
|
||||
`${IPC_METHOD_BASE}.updatePlsRules`,
|
||||
parsedWsMsg.data
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = { configRouteHandler };
|
||||
0
src/aura/ui/static/aura.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B |
BIN
src/aura/ui/static/aura_pls.png
Executable file
|
After Width: | Height: | Size: 21 KiB |
0
src/aura/ui/static/config/about.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
0
src/aura/ui/static/config/behaviour_mon.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
0
src/aura/ui/static/config/no_limitations.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
0
src/aura/ui/static/config/plugin.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
47
src/aura/utils/eventBus.js
Executable file
@@ -0,0 +1,47 @@
|
||||
class EventBus {
|
||||
constructor() {
|
||||
this.listeners = new Map();
|
||||
}
|
||||
|
||||
on(eventName, callback) {
|
||||
if (!this.listeners.has(eventName)) {
|
||||
this.listeners.set(eventName, new Set());
|
||||
}
|
||||
this.listeners.get(eventName).add(callback);
|
||||
return () => this.off(eventName, callback);
|
||||
}
|
||||
|
||||
off(eventName, callback) {
|
||||
if (this.listeners.has(eventName)) {
|
||||
this.listeners.get(eventName).delete(callback);
|
||||
if (this.listeners.get(eventName).size === 0) {
|
||||
this.listeners.delete(eventName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit(eventName, ...args) {
|
||||
if (this.listeners.has(eventName)) {
|
||||
this.listeners.get(eventName).forEach((callback) => {
|
||||
try {
|
||||
callback(...args);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[HugoAura / EventBus] Error in ${eventName} callback:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
once(eventName, callback) {
|
||||
const onceCallback = (...args) => {
|
||||
callback(...args);
|
||||
this.off(eventName, onceCallback);
|
||||
};
|
||||
return this.on(eventName, onceCallback);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EventBus;
|
||||
358
src/core/hook.js
Normal file → Executable file
@@ -1,139 +1,219 @@
|
||||
if (!global.__HUGO_AURA__) {
|
||||
global.__HUGO_AURA__ = {
|
||||
hookedWindows: new Map(),
|
||||
hooks: null,
|
||||
configInit: false,
|
||||
};
|
||||
}
|
||||
|
||||
const fs = require("fs");
|
||||
const util = require("util");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
const HooksManager = require("../aura/init/rendererHook/hooksManager");
|
||||
const NetworkHook = require("../aura/init/rendererHook/networkHook");
|
||||
const configManager = require("../aura/init/shared/configManager");
|
||||
const { buildIpcMain } = require("../aura/init/main/ipcHandler");
|
||||
|
||||
const initLogger = () => {
|
||||
const logDir = path.join(os.homedir(), "Documents", "HugoAura", "logs");
|
||||
if (!fs.existsSync(logDir)) {
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
}
|
||||
|
||||
const logFile = path.join(
|
||||
logDir,
|
||||
`main-process-${new Date().toISOString().replace(/:/g, "-")}.log`
|
||||
);
|
||||
const logStream = fs.createWriteStream(logFile, { flags: "a" });
|
||||
|
||||
const originalConsole = {
|
||||
log: console.log,
|
||||
error: console.error,
|
||||
warn: console.warn,
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
};
|
||||
|
||||
console.log = function (...args) {
|
||||
const msg = util.format("[LOG] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.log.apply(console, args);
|
||||
};
|
||||
|
||||
console.error = function (...args) {
|
||||
const msg = util.format("[ERROR] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.error.apply(console, args);
|
||||
};
|
||||
|
||||
console.warn = function (...args) {
|
||||
const msg = util.format("[WARN] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.warn.apply(console, args);
|
||||
};
|
||||
|
||||
console.info = function (...args) {
|
||||
const msg = util.format("[INFO] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.info.apply(console, args);
|
||||
};
|
||||
|
||||
console.debug = function (...args) {
|
||||
if (!process.argv.includes("--aura-debug")) return;
|
||||
const msg = util.format("[DEBUG] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.debug.apply(console, args);
|
||||
};
|
||||
|
||||
process.on("uncaughtException", (err) => {
|
||||
console.error("UNCAUGHT EXCEPTION:", err);
|
||||
});
|
||||
|
||||
console.log("Logger initialized. Log file:", logFile);
|
||||
};
|
||||
|
||||
module.exports = function ({ central, windowName, config }) {
|
||||
process.stdout.isTTY = true;
|
||||
process.stderr.isTTY = true;
|
||||
|
||||
const electron = central(1);
|
||||
const app = electron.app;
|
||||
if (!global.__HUGO_AURA__.central) global.__HUGO_AURA__.central = central;
|
||||
|
||||
global.reloadApp = () => {
|
||||
app.relaunch({ args: process.argv.slice(1).concat(["--inspect 5858"]) });
|
||||
app.exit(0);
|
||||
};
|
||||
|
||||
initLogger();
|
||||
|
||||
console.log("[HugoAura / Loaded] Aura is loaded!");
|
||||
|
||||
if (!global.__HUGO_AURA__.ipcInit) {
|
||||
buildIpcMain(electron);
|
||||
global.__HUGO_AURA__.ipcInit = true;
|
||||
}
|
||||
|
||||
const hooksManager = new HooksManager();
|
||||
|
||||
configManager.ensureConfigExists();
|
||||
const loadedConfig = configManager.loadConfig();
|
||||
if (!global.__HUGO_AURA__.configInit) global.__HUGO_AURA__.configInit = true;
|
||||
|
||||
const hooks = hooksManager.loadHooks();
|
||||
|
||||
if (loadedConfig.devTools && !config.canOpenDevTool) {
|
||||
config.canOpenDevTool = true;
|
||||
}
|
||||
|
||||
const webContentsCreatedListener = (_event, webContents) => {
|
||||
const hookConfig = hooks.get(windowName);
|
||||
|
||||
const initNetworkHook = () => {
|
||||
const networkHook = new NetworkHook();
|
||||
networkHook.installHook(webContents.session, loadedConfig);
|
||||
|
||||
console.debug(
|
||||
`[HugoAura / Init / Done / NetworkHook] Network Hook for ${windowName} installed.`
|
||||
);
|
||||
};
|
||||
|
||||
initNetworkHook();
|
||||
|
||||
if (hookConfig) {
|
||||
hooksManager.handleWindowHook(webContents, hookConfig, windowName);
|
||||
} else {
|
||||
console.debug(
|
||||
`[HugoAura / Init] Window ${windowName} has no corresponding hook, ignoring...`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
app.once("web-contents-created", webContentsCreatedListener);
|
||||
|
||||
return () => {
|
||||
app.removeListener("web-contents-created", webContentsCreatedListener);
|
||||
};
|
||||
};
|
||||
// @ts-check
|
||||
|
||||
if (!global.__HUGO_AURA__) {
|
||||
const __HUGO_AURA__ = {
|
||||
hookedWindows: new Map(),
|
||||
configInit: false,
|
||||
central: () => {},
|
||||
ipcInit: false,
|
||||
plsStats: null,
|
||||
plsSettings: null,
|
||||
plsRules: null,
|
||||
uiHooks: new Map(),
|
||||
windowHooks: new Map(),
|
||||
version: require("./preload").__AURA_VERSION__,
|
||||
};
|
||||
global.__HUGO_AURA__ = __HUGO_AURA__;
|
||||
}
|
||||
|
||||
if (!global.__HUGO_AURA_CONFIG__) {
|
||||
global.__HUGO_AURA_CONFIG__ = {};
|
||||
}
|
||||
|
||||
const fs = require("fs");
|
||||
const util = require("util");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
const MainProcessHooksManager = require("../aura/init/main/windowHooksManager");
|
||||
const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager");
|
||||
const EventBus = require("../aura/utils/eventBus");
|
||||
const NetworkHook = require("../aura/init/rendererHook/networkHook");
|
||||
const ConfigManager = require("../aura/init/shared/configManager");
|
||||
const { buildIpcMain } = require("../aura/init/main/ipcHandler");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../aura/types/main/core").WindowName} windowName
|
||||
*/
|
||||
const initLogger = (windowName) => {
|
||||
const logDir = path.join(os.homedir(), "Documents", "HugoAura", "logs");
|
||||
if (!fs.existsSync(logDir)) {
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
}
|
||||
|
||||
const logFile = path.join(
|
||||
logDir,
|
||||
`main-${windowName}-${new Date().toISOString().replace(/:/g, "-")}.log`
|
||||
);
|
||||
const logStream = fs.createWriteStream(logFile, { flags: "a" });
|
||||
|
||||
const originalConsole = {
|
||||
log: console.log,
|
||||
error: console.error,
|
||||
warn: console.warn,
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
};
|
||||
|
||||
console.log = function (...args) {
|
||||
const msg = util.format("[LOG] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.log.apply(console, args);
|
||||
};
|
||||
|
||||
console.error = function (...args) {
|
||||
const msg = util.format("[ERROR] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.error.apply(console, args);
|
||||
};
|
||||
|
||||
console.warn = function (...args) {
|
||||
const msg = util.format("[WARN] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.warn.apply(console, args);
|
||||
};
|
||||
|
||||
console.info = function (...args) {
|
||||
const msg = util.format("[INFO] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.info.apply(console, args);
|
||||
};
|
||||
|
||||
console.debug = function (...args) {
|
||||
if (!process.argv.includes("--aura-debug")) return;
|
||||
const msg = util.format("[DEBUG] ", ...args) + "\n";
|
||||
logStream.write(msg);
|
||||
originalConsole.debug.apply(console, args);
|
||||
};
|
||||
|
||||
process.on("uncaughtException", (err) => {
|
||||
console.error("UNCAUGHT EXCEPTION:", err);
|
||||
});
|
||||
|
||||
console.log(
|
||||
"[HugoAura / Init / Logger] Logger initialized. Log file:",
|
||||
logFile
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../aura/types/main/core").LauncherArgs} param0
|
||||
* @returns
|
||||
*/
|
||||
const launcher = ({ central, windowName, config }) => {
|
||||
// >>> Init STD <<< //
|
||||
process.stdout.isTTY = true;
|
||||
process.stderr.isTTY = true;
|
||||
|
||||
// >>> Basic Config <<< //
|
||||
/** @type {Electron} */
|
||||
const electron = central(1);
|
||||
const app = electron.app;
|
||||
if (!global.__HUGO_AURA__.central) global.__HUGO_AURA__.central = central;
|
||||
|
||||
global.reloadApp = () => {
|
||||
app.relaunch({ args: process.argv.slice(1).concat(["--inspect 5858"]) });
|
||||
app.exit(0);
|
||||
};
|
||||
|
||||
// >>> Init Logger <<< //
|
||||
initLogger(windowName);
|
||||
|
||||
console.log("[HugoAura / Loaded] Aura is loaded!");
|
||||
console.debug(`[HugoAura / Debug] curWindowName: ${windowName}`);
|
||||
|
||||
// >>> Init EventBus <<< //
|
||||
if (!global.__HUGO_AURA_EVENT_BUS__)
|
||||
global.__HUGO_AURA_EVENT_BUS__ = new EventBus();
|
||||
|
||||
// >>> Init Config <<< //
|
||||
const configManager = new ConfigManager();
|
||||
configManager.side = "main";
|
||||
configManager.ensureConfigExists();
|
||||
const loadedConfig = configManager.loadConfig();
|
||||
if (!global.__HUGO_AURA__.configInit) global.__HUGO_AURA__.configInit = true;
|
||||
if (!global.__HUGO_AURA_CONFIG_MGR__) global.__HUGO_AURA_CONFIG_MGR__ = configManager;
|
||||
|
||||
global.__HUGO_AURA_CONFIG__ = loadedConfig;
|
||||
|
||||
global.__HUGO_AURA_EVENT_BUS__.on("$aura.config.refreshConfig", () => {
|
||||
global.__HUGO_AURA_CONFIG__ = configManager.loadConfig();
|
||||
});
|
||||
|
||||
// >>> Init IPC Main <<< //
|
||||
if (!global.__HUGO_AURA__.ipcInit) {
|
||||
buildIpcMain(electron);
|
||||
global.__HUGO_AURA__.ipcInit = true;
|
||||
}
|
||||
|
||||
// >>> Init Main Process Hooks <<< //
|
||||
const mainProcessHooksManager = new MainProcessHooksManager();
|
||||
|
||||
const _windowHooks = mainProcessHooksManager.loadHooks();
|
||||
|
||||
// >>> Init Renderer Process Hooks <<< //
|
||||
const uiHooksManager = new RendererHooksManager();
|
||||
|
||||
const uiHooks = uiHooksManager.loadHooks();
|
||||
|
||||
// >>> Activate DevTools <<< //
|
||||
if (loadedConfig.devTools && !config.canOpenDevTool) {
|
||||
config.canOpenDevTool = true;
|
||||
}
|
||||
|
||||
// >>> Listeners <<< //
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} _event
|
||||
* @param {import("electron").BrowserWindow} browserWindow
|
||||
*/
|
||||
const browserWindowCreatedListener = (_event, browserWindow) => {
|
||||
mainProcessHooksManager.initHookForWindow(
|
||||
windowName,
|
||||
central,
|
||||
app,
|
||||
browserWindow
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} _event
|
||||
* @param {import("electron").WebContents} webContents
|
||||
*/
|
||||
const webContentsCreatedListener = (_event, webContents) => {
|
||||
const hookConfig = uiHooks.get(windowName.split("_")[0]);
|
||||
|
||||
const initNetworkHook = () => {
|
||||
const networkHook = new NetworkHook();
|
||||
networkHook.installHook(webContents.session, loadedConfig);
|
||||
|
||||
console.debug(
|
||||
`[HugoAura / Init / Done / NetworkHook] Network Hook for ${windowName} installed.`
|
||||
);
|
||||
};
|
||||
|
||||
initNetworkHook();
|
||||
|
||||
if (hookConfig) {
|
||||
uiHooksManager.handleWindowHook(webContents, hookConfig, windowName);
|
||||
} else {
|
||||
console.log(
|
||||
`[HugoAura / Init / RDH] Window ${windowName} has no corresponding ui hooks, ignoring...`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
app.once("browser-window-created", browserWindowCreatedListener);
|
||||
app.once("web-contents-created", webContentsCreatedListener);
|
||||
|
||||
return () => {
|
||||
app.removeListener("browser-window-created", browserWindowCreatedListener);
|
||||
app.removeListener("web-contents-created", webContentsCreatedListener);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = launcher;
|
||||
|
||||
86
src/core/preload.js
Normal file → Executable file
@@ -1,9 +1,15 @@
|
||||
const __AURA_VERSION__ = "0.1.0-beta";
|
||||
// @ts-check
|
||||
|
||||
const __AURA_VERSION__ = "0.1.1-pre-III";
|
||||
|
||||
(() => {
|
||||
if (require.main) return; // 如果只是导入 Aura Version, 不运行闭包逻辑
|
||||
|
||||
// >>> Init Global Vars <<< //
|
||||
if (!global.__HUGO_AURA__) {
|
||||
global.__HUGO_AURA__ = {
|
||||
configInit: true, // preload 始终比 hook 晚, 默认 config 已初始化
|
||||
// ↑ 保留此参数的目的 -> 用于 configManager 中, configManager 的行为在 Renderer 和 Main 中是一致的
|
||||
version: __AURA_VERSION__,
|
||||
};
|
||||
}
|
||||
@@ -16,11 +22,29 @@ const __AURA_VERSION__ = "0.1.0-beta";
|
||||
global.__HUGO_AURA_UI_REACTIVES__ = {};
|
||||
}
|
||||
|
||||
const configManager = require("../aura/init/shared/configManager");
|
||||
// >>> Init EventBus <<< //
|
||||
const EventBus = require("../aura/utils/eventBus");
|
||||
if (!global.__HUGO_AURA_EVENT_BUS__) {
|
||||
global.__HUGO_AURA_EVENT_BUS__ = new EventBus();
|
||||
}
|
||||
|
||||
// >>> Load Modules <<< //
|
||||
const ConfigManager = require("../aura/init/shared/configManager");
|
||||
const WebpackHook = require("../aura/init/preload/webpackHook");
|
||||
|
||||
console.log(`[HugoAura / AppHook / Preload] Preparing...`);
|
||||
const configManager = new ConfigManager();
|
||||
configManager.side = "renderer";
|
||||
if (!global.__HUGO_AURA_CONFIG_MGR__)
|
||||
global.__HUGO_AURA_CONFIG_MGR__ = configManager;
|
||||
|
||||
console.log(`[HugoAura / Preload] Preparing...`);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} baseObj
|
||||
* @param {(string | symbol)[]} path
|
||||
* @returns
|
||||
*/
|
||||
const createConfigProxy = (baseObj, path = []) => {
|
||||
return new Proxy(baseObj, {
|
||||
get(target, prop) {
|
||||
@@ -37,24 +61,76 @@ const __AURA_VERSION__ = "0.1.0-beta";
|
||||
value,
|
||||
},
|
||||
});
|
||||
const pathName = [...path, prop].join(".");
|
||||
document.dispatchEvent(configUpdateEvent);
|
||||
console.log(
|
||||
`[HugoAura / Config] Config changed at path: ${[...path, prop].join(
|
||||
"."
|
||||
)}, new value: ${value}`
|
||||
);
|
||||
configManager.writeConfig(window.__HUGO_AURA_CONFIG__);
|
||||
|
||||
const isEditingEncSettings = pathName.includes(
|
||||
"auraSettings.settingsPassword"
|
||||
);
|
||||
|
||||
if (
|
||||
isEditingEncSettings &&
|
||||
global.__HUGO_AURA_CONFIG__.auraSettings.encryptConfig
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!configManager.useEncConfig) {
|
||||
configManager.writeConfig(window.__HUGO_AURA_CONFIG__); // 仅非加密 Config 使用即时写入, 否则会导致性能问题
|
||||
} else {
|
||||
if (global.__HUGO_AURA_UI_REACTIVES__.config) {
|
||||
global.__HUGO_AURA_UI_REACTIVES__.config.isConfigPendingWrite = true;
|
||||
}
|
||||
if (global.__HUGO_AURA_UI_FUNCTIONS__.config?.handleACSNShow) {
|
||||
global.__HUGO_AURA_UI_FUNCTIONS__.config.handleACSNShow();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const initialConfig = configManager.readConfig();
|
||||
const getConfig = () => {
|
||||
/*
|
||||
if (configManager.useEncConfig) {
|
||||
if (!ipcRenderer) ipcRenderer = require("electron").ipcRenderer;
|
||||
const result = ipcRenderer.sendSync("$aura.config.getConfigFromMainSync");
|
||||
if (result.success) {
|
||||
configManager.isConfigReadFailed = false;
|
||||
return result.data;
|
||||
} else {
|
||||
configManager.isConfigReadFailed = true;
|
||||
return configManager.getDefaultConfig();
|
||||
}
|
||||
} else {
|
||||
const result = configManager.readConfig();
|
||||
configManager.isConfigReadFailed = false;
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
// ↑ IPC Renderer 在 Preload 时无法访问, 因此无法从主进程拉取配置
|
||||
const result = configManager.readConfig();
|
||||
configManager.isConfigReadFailed = false;
|
||||
return result;
|
||||
};
|
||||
|
||||
// >>> Init Config <<< //
|
||||
const initialConfig = getConfig();
|
||||
window.__HUGO_AURA_CONFIG__ = createConfigProxy(initialConfig);
|
||||
|
||||
// >>> Init Renderer Hooks <<< //
|
||||
window.__HUGO_AURA_HOOK__ = {};
|
||||
const webpackHook = new WebpackHook();
|
||||
webpackHook.installHook(window, initialConfig);
|
||||
|
||||
// >>> Done <<< //
|
||||
console.log(`[HugoAura / AppHook / DONE] Hooks installed`);
|
||||
console.log(`[HugoAura / Preload / DONE] Preload done`);
|
||||
})();
|
||||
|
||||
module.exports = { __AURA_VERSION__ };
|
||||
|
||||
54
src/core/zeron.js
Normal file → Executable file
@@ -1,23 +1,31 @@
|
||||
// Ex-Early Load Pro Plus Max ++
|
||||
|
||||
console.debug("[HugoAura / Zeron] Early load script loaded.");
|
||||
|
||||
module.exports = function (central) {
|
||||
const originalCentral = { ...central };
|
||||
const genHookedWS = require("../aura/init/zeron/hookWS");
|
||||
|
||||
console.debug(
|
||||
"[HugoAura / Zeron / WebSocket Hook] WebSocket hooked class generated."
|
||||
);
|
||||
|
||||
return new Proxy(central, {
|
||||
apply(target, thisArg, args) {
|
||||
switch (args[0]) {
|
||||
case 18:
|
||||
return genHookedWS(central);
|
||||
default:
|
||||
return Reflect.apply(target, thisArg, args);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
// Ex-Early Load Pro Plus Max ++
|
||||
|
||||
console.debug("[HugoAura / Zeron] Early load script loaded.");
|
||||
|
||||
const appendSwitch = () => {
|
||||
const { app } = require("electron");
|
||||
app.commandLine.appendSwitch("host-rules", "MAP *.hugoaura.local 127.0.0.1");
|
||||
};
|
||||
|
||||
module.exports = function (central) {
|
||||
const originalCentral = { ...central };
|
||||
|
||||
appendSwitch();
|
||||
|
||||
const genHookedWS = require("../aura/init/zeron/hookWS");
|
||||
|
||||
console.debug(
|
||||
"[HugoAura / Zeron / WebSocket Hook] WebSocket hooked class generated."
|
||||
);
|
||||
|
||||
return new Proxy(central, {
|
||||
apply(target, thisArg, args) {
|
||||
switch (args[0]) {
|
||||
case 18:
|
||||
return genHookedWS(central);
|
||||
default:
|
||||
return Reflect.apply(target, thisArg, args);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||