[Feat] New settings passwd UX & Config enc support

This commit is contained in:
Minoricew
2025-06-05 00:35:50 +08:00
parent fbc5cf1f57
commit 7c8d3d4fbc
33 changed files with 2006 additions and 675 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "HugoAura", "name": "HugoAura",
"version": "0.1.1-pre-II", "version": "0.1.1-pre-III",
"description": "Aura for SeewoHugo", "description": "Aura for SeewoHugo",
"main": "app.asar/main.js", "main": "app.asar/main.js",
"dependencies": {}, "dependencies": {},

View File

@@ -11,7 +11,7 @@ const buildIpcMain = (electron) => {
/** /**
* @type {import("../../types/main/electron").AuraIPCMain} * @type {import("../../types/main/electron").AuraIPCMain}
*/ */
// @ts-ignore // @ts-expect-error
const ipcMain = electron.ipcMain; const ipcMain = electron.ipcMain;
/** /**
@@ -28,11 +28,33 @@ const buildIpcMain = (electron) => {
* @param {string} chan * @param {string} chan
* @param {any} targetData * @param {any} targetData
*/ */
if (!global.__HUGO_AURA__.hookedWindows) {
return {
success: false,
};
}
const sendDataToWebContents = (key, chan, targetData) => { const sendDataToWebContents = (key, chan, targetData) => {
const webContents = const webContents =
global.__HUGO_AURA__.hookedWindows.get(key).webContents; // @ts-expect-error
global.__HUGO_AURA__.hookedWindows.get(key)?.webContents;
if (grep !== webContents) webContents.send(chan, targetData); 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 === "*") { if (windowKey === "*") {
@@ -51,6 +73,7 @@ const buildIpcMain = (electron) => {
} }
}; };
const { applyConfigIpcHandler } = require("./ipcModules/configIpcHandler");
const { applyPlsIpcHandler } = require("./ipcModules/plsIpcHandler"); const { applyPlsIpcHandler } = require("./ipcModules/plsIpcHandler");
ipcMain.handle("$aura.base.restartApplication", async () => { ipcMain.handle("$aura.base.restartApplication", async () => {
@@ -58,6 +81,7 @@ const buildIpcMain = (electron) => {
app.exit(0); app.exit(0);
}); });
applyConfigIpcHandler(ipcMain);
applyPlsIpcHandler(ipcMain); applyPlsIpcHandler(ipcMain);
}; };

View 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 };

View File

@@ -52,7 +52,7 @@ const applyPlsIpcHandler = (ipcMain) => {
`${methodBase}.getPlsStats`, `${methodBase}.getPlsStats`,
/** /**
* *
* @returns {{ success: boolean; data: PLSStatus; }} * @returns {{ success: boolean; data: PLSStatus | null | undefined; }}
*/ */
(_event, _arg) => { (_event, _arg) => {
return { return {
@@ -83,7 +83,7 @@ const applyPlsIpcHandler = (ipcMain) => {
`${methodBase}.getPlsSettings`, `${methodBase}.getPlsSettings`,
/** /**
* *
* @returns {{ success: boolean; data: Record<any, any> }} * @returns {{ success: boolean; data: Record<any, any> | null | undefined }}
*/ */
(_event, _arg) => { (_event, _arg) => {
return { return {
@@ -113,7 +113,7 @@ const applyPlsIpcHandler = (ipcMain) => {
`${methodBase}.getPlsRules`, `${methodBase}.getPlsRules`,
/** /**
* *
* @returns {{ success: boolean; data: Record<any, any> }} * @returns {{ success: boolean; data: Record<any, any> | null | undefined }}
*/ */
(_event, _arg) => { (_event, _arg) => {
return { return {

View File

@@ -1,4 +1,4 @@
const path = require('path'); const path = require("path");
class WebpackHook { class WebpackHook {
#ruleCache = new Map(); #ruleCache = new Map();
@@ -19,7 +19,7 @@ class WebpackHook {
if (!rule) { if (!rule) {
rule = require(path.join( rule = require(path.join(
__dirname, __dirname,
'../../../aura/jsRewrite/', "../../../aura/jsRewrite/",
rulePath rulePath
)); ));
this.#ruleCache.set(rulePath, rule); this.#ruleCache.set(rulePath, rule);
@@ -49,7 +49,7 @@ class WebpackHook {
patchModules(modules, rewrites) { patchModules(modules, rewrites) {
modules.forEach((mod, index) => { modules.forEach((mod, index) => {
if (typeof mod !== 'function') return; if (typeof mod !== "function") return;
const stringifyFunc = mod.toString(); const stringifyFunc = mod.toString();
rewrites.forEach((rewrite) => { rewrites.forEach((rewrite) => {
@@ -67,14 +67,14 @@ class WebpackHook {
let rewrittenFunction = mod; let rewrittenFunction = mod;
switch (method) { switch (method) {
case 'reactComponent': case "reactComponent":
window.__HUGO_AURA_HOOK__[ruleId] = { window.__HUGO_AURA_HOOK__[ruleId] = {
feature: rewrite.feature, feature: rewrite.feature,
newFunction: rewrite.newFunction newFunction: rewrite.newFunction,
} };
rewrittenFunction = rewrite.preHook(mod); rewrittenFunction = rewrite.preHook(mod);
break; break;
case 'legacy': case "legacy":
default: default:
rewrittenFunction = rewrite.newFunction; rewrittenFunction = rewrite.newFunction;
break; break;
@@ -95,7 +95,7 @@ class WebpackHook {
}); });
}); });
if (typeof window !== 'undefined') { if (typeof window !== "undefined") {
window.__HUGO_AURA_DEBUG__ = { window.__HUGO_AURA_DEBUG__ = {
getRuleCache: () => Array.from(this.#ruleCache.keys()), getRuleCache: () => Array.from(this.#ruleCache.keys()),
}; };
@@ -105,7 +105,7 @@ class WebpackHook {
installHook(window, config) { installHook(window, config) {
let realWebpackJsonp = window.webpackJsonp; let realWebpackJsonp = window.webpackJsonp;
Object.defineProperty(window, 'webpackJsonp', { Object.defineProperty(window, "webpackJsonp", {
get: () => realWebpackJsonp, get: () => realWebpackJsonp,
set: (value) => { set: (value) => {
console.log( console.log(
@@ -119,7 +119,7 @@ class WebpackHook {
if (args[0] && Array.isArray(args[0][1])) { if (args[0] && Array.isArray(args[0][1])) {
const [chunkIds, modules] = args[0]; const [chunkIds, modules] = args[0];
console.log( console.log(
`[HugoAura / AppHook] Intercepting chunk ${chunkIds.join(', ')}` `[HugoAura / AppHook] Intercepting chunk ${chunkIds.join(", ")}`
); );
const rewrites = this.loadRewriteRules(config); const rewrites = this.loadRewriteRules(config);

View File

@@ -87,7 +87,9 @@ class RendererHooksManager {
return; return;
} }
console.log(`[HugoAura / Init / RDH] UI Hook is initializing for ${windowKey}...`); console.log(
`[HugoAura / Init / RDH] UI Hook is initializing for ${windowKey}...`
);
console.log( console.log(
`[HugoAura / Init / RDH] UI Hook loaded at: ${new Date().toISOString()}` `[HugoAura / Init / RDH] UI Hook loaded at: ${new Date().toISOString()}`
); );

View File

@@ -6,6 +6,9 @@ const os = require("os");
const crypto = require("crypto"); const crypto = require("crypto");
const childProc = require("child_process"); const childProc = require("child_process");
const RegistryManagerClass = require("./registryManager");
const registryManager = new RegistryManagerClass();
// Constants // Constants
const CRYPTO_SETTINGS_AES = { const CRYPTO_SETTINGS_AES = {
@@ -18,6 +21,7 @@ const CRYPTO_SETTINGS_AES = {
obfuscateStr: "eCybsseK", obfuscateStr: "eCybsseK",
hash: "sha256", hash: "sha256",
}; };
const LMAK_SETTINGS_BASE = "EncSettings\\LMAK";
/** /**
* *
@@ -70,14 +74,35 @@ class ConfigManager {
this.encConfigPath = path.join(this.configDir, ".cache_2eafc8d0.dat"); // (雾 this.encConfigPath = path.join(this.configDir, ".cache_2eafc8d0.dat"); // (雾
/* ↑ 不使用 .tmp 扩展名, 不然容易真被清理了 */ /* ↑ 不使用 .tmp 扩展名, 不然容易真被清理了 */
this.defaultConfigPath = path.join(__dirname, "default.json"); 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() { getHugoAuraConfigPath() {
return path.dirname(this.configPath); return path.dirname(
this.useEncConfig ? this.encConfigPath : this.configPath
);
} }
getConfigPath() { getConfigPath() {
return this.configPath; return this.useEncConfig ? this.encConfigPath : this.configPath;
} }
getDefaultConfig() { getDefaultConfig() {
@@ -99,7 +124,7 @@ class ConfigManager {
fs.mkdirSync(hugoAuraPath, { recursive: true }); fs.mkdirSync(hugoAuraPath, { recursive: true });
} }
if (!fs.existsSync(this.configPath)) { if (!fs.existsSync(this.configPath) && !fs.existsSync(this.encConfigPath)) {
console.log("[HugoAura / Config] Creating default config file"); console.log("[HugoAura / Config] Creating default config file");
const defaultConfig = this.getDefaultConfig(); const defaultConfig = this.getDefaultConfig();
this.writeConfig(defaultConfig); this.writeConfig(defaultConfig);
@@ -108,11 +133,30 @@ class ConfigManager {
readConfig() { readConfig() {
try { try {
const config = JSON.parse(fs.readFileSync(this.configPath, "utf8")); let config = {};
console.log("[HugoAura / Config] Successfully loaded config:", 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; return config;
} catch (err) { } 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(); return this.getDefaultConfig();
} }
} }
@@ -120,15 +164,32 @@ class ConfigManager {
/** /**
* *
* @param {Record<any, any>} config * @param {Record<any, any>} config
* @returns * @returns {boolean}
*/ */
writeConfig(config) { writeConfig(config) {
try { try {
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( fs.writeFileSync(
this.configPath, this.configPath,
JSON.stringify(config, null, 2), JSON.stringify(config, null, 2),
"utf8" "utf8"
); );
}
if (this.side === "renderer") {
global.ipcRenderer.send("$aura.config.refreshMainConfig");
}
return true; return true;
} catch (err) { } catch (err) {
console.error("[HugoAura / Config] Failed to write config:", err); console.error("[HugoAura / Config] Failed to write config:", err);
@@ -140,8 +201,8 @@ class ConfigManager {
let defaultConfig = this.getDefaultConfig(); let defaultConfig = this.getDefaultConfig();
let config = {}; let config = {};
try { try {
if (fs.existsSync(this.configPath)) { if (fs.existsSync(this.configPath) || fs.existsSync(this.encConfigPath)) {
const userConfig = JSON.parse(fs.readFileSync(this.configPath, "utf8")); const userConfig = this.readConfig();
if (global.__HUGO_AURA__.configInit) { if (global.__HUGO_AURA__.configInit) {
config = userConfig; config = userConfig;
return userConfig; return userConfig;
@@ -153,18 +214,236 @@ class ConfigManager {
} }
} catch (err) { } 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; config = defaultConfig;
} }
return config; 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 {Record<any, any>} configData
* @param {string} passwd * @param {SHA256EncryptedPassword} passwd
*/ */
encryptConfig(configData, passwd) { encryptConfig(configData, passwd) {
registryManager.initRegistry();
const salt = crypto.randomBytes(CRYPTO_SETTINGS_AES.saltLength); const salt = crypto.randomBytes(CRYPTO_SETTINGS_AES.saltLength);
const key = crypto.pbkdf2Sync( const key = crypto.pbkdf2Sync(
passwd, passwd,
@@ -198,15 +477,13 @@ class ConfigManager {
try { try {
fs.writeFileSync(this.encConfigPath, base64EncConfig, "utf-8"); fs.writeFileSync(this.encConfigPath, base64EncConfig, "utf-8");
// fs.rmSync(this.configPath); try {
fs.unlinkSync(this.configPath);
const _hideFileProc = childProc.spawnSync( } catch {
"cmd.exe", console.debug("[HugoAura / Config] Dec config not exists, skipping...");
["/c", "attrib", "+h", this.encConfigPath],
{
stdio: "inherit",
} }
);
if (!this.useEncConfig) this.useEncConfig = true;
return true; return true;
} catch (err) { } catch (err) {
console.error( console.error(
@@ -223,10 +500,11 @@ class ConfigManager {
/** /**
* *
* @param {string} passwd * @param {SHA256EncryptedPassword} passwd
* @returns * @returns {{success: boolean, data: AuraConfig}}
*/ */
decryptConfig(passwd) { decryptConfig(passwd) {
try {
const FAILED_RET = { const FAILED_RET = {
success: false, success: false,
data: {}, data: {},
@@ -251,7 +529,9 @@ class ConfigManager {
const strip64EncCfg = base64EncConfig.split( const strip64EncCfg = base64EncConfig.split(
CRYPTO_SETTINGS_AES.obfuscateStr CRYPTO_SETTINGS_AES.obfuscateStr
)[1]; )[1];
const encryptCfg = Buffer.from(strip64EncCfg, "base64").toString("utf-8"); const encryptCfg = Buffer.from(strip64EncCfg, "base64").toString(
"utf-8"
);
/** @type {null | EncryptedConfig} */ /** @type {null | EncryptedConfig} */
let parsedEncCfg = null; let parsedEncCfg = null;
try { try {
@@ -290,7 +570,7 @@ class ConfigManager {
decipherIns.setAuthTag(authTag); decipherIns.setAuthTag(authTag);
let stringifyDecCfg = Buffer.concat([ const stringifyDecCfg = Buffer.concat([
decipherIns.update(parsedEncCfg.content, "hex"), decipherIns.update(parsedEncCfg.content, "hex"),
decipherIns.final(), decipherIns.final(),
]).toString(); ]).toString();
@@ -309,9 +589,80 @@ class ConfigManager {
} }
if (decConfig === null) return FAILED_RET; if (decConfig === null) return FAILED_RET;
console.debug(decConfig); // 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;

View File

@@ -7,7 +7,7 @@
"passwordWithSalt": "89f6c4d57d0202a05c32d37cc6a2c6a0", "passwordWithSalt": "89f6c4d57d0202a05c32d37cc6a2c6a0",
"salt": "aura" "salt": "aura"
}, },
"authModeRewrite": "none" "authModeRewrite": "default"
}, },
"vendor/screenLock": { "vendor/screenLock": {
"enabled": true, "enabled": true,
@@ -30,9 +30,8 @@
"auraSettings": { "auraSettings": {
"settingsPasswordEnabled": false, "settingsPasswordEnabled": false,
"settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965", "settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965",
"appearance": { "encryptConfig": false,
"enablePasswdDialogBlur": true "appearance": {}
}
}, },
"devTools": false "devTools": false
} }

View 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;

View File

@@ -21,13 +21,6 @@ type HookedWindowsMap = Map<WindowName, HookedWindow>;
type HookRequire = any; type HookRequire = any;
type HooksMap = Map<WindowName, HookRequire>; type UIHooksMap = Map<WindowName, HookRequire>;
interface MainProcessGlobal { type WindowHooksMap = Map<WindowName, HookRequire>;
hookedWindows: HookedWindowsMap;
hooks: HooksMap;
configInit: boolean;
plsStats: PLSStatus | null;
plsSettings: Record<any, any> | null;
plsRules: Record<any, any> | null;
}

View File

@@ -12,3 +12,6 @@ interface DesktopAssistantHugoAuraGlobal extends HugoAuraGlobal {
plsWs: WebSocket | null; plsWs: WebSocket | null;
plsStats: PLSStatus; plsStats: PLSStatus;
} }
type UIFunctionsObject = Record<string, any>;
type UIReactivesObject = Record<string, any>;

View File

@@ -23,3 +23,5 @@ interface UIHookConfig {
interface UIHookConfigFin extends UIHookConfig { interface UIHookConfigFin extends UIHookConfig {
windowName: WindowName; windowName: WindowName;
} }
type UIHooksObject = Record<AuraElementUID, UIHookConfigFin>;

View File

@@ -1,5 +1,6 @@
type AES256EncryptedConfig = string; type AES256EncryptedConfig = string;
type Base64String = string; type Base64String = string;
type SHA256EncryptedPassword = string;
interface EncryptedConfig { interface EncryptedConfig {
content: AES256EncryptedConfig; content: AES256EncryptedConfig;
@@ -7,3 +8,5 @@ interface EncryptedConfig {
salt: Base64String; salt: Base64String;
iv: Base64String; iv: Base64String;
} }
type AuraConfig = Record<any, any>;

37
src/aura/types/shared/global.d.ts vendored Executable file
View File

@@ -0,0 +1,37 @@
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";
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;
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>;
}

View File

@@ -141,9 +141,9 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => {
const elValue = entry.valueGetter(); const elValue = entry.valueGetter();
switchEl.value = elValue; switchEl.value = elValue;
switchEl.checked = elValue; switchEl.checked = elValue;
switchEl.addEventListener("change", (event) => { switchEl.addEventListener("change", async (event) => {
showToast(entry); showToast(entry);
entry.callbackFn(event.target.checked); await entry.callbackFn(event.target.checked);
}); });
entryOperationArea.classList.add("form-check", "form-switch"); entryOperationArea.classList.add("form-check", "form-switch");
entryOperationArea.appendChild(switchEl); entryOperationArea.appendChild(switchEl);
@@ -167,10 +167,10 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => {
template template
)}`; )}`;
radioEl.checked = template === elValue ? true : false; radioEl.checked = template === elValue ? true : false;
radioEl.addEventListener("change", (event) => { radioEl.addEventListener("change", async (event) => {
if (event.target.checked) { if (event.target.checked) {
showToast(entry); showToast(entry);
entry.callbackFn(event.target.value); await entry.callbackFn(event.target.value);
} }
}); });
inlineContainerEl.appendChild(radioEl); inlineContainerEl.appendChild(radioEl);
@@ -192,8 +192,8 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => {
inputEl.value = entry.valueGetter(); inputEl.value = entry.valueGetter();
inputEl.placeholder = entry.placeHolder; inputEl.placeholder = entry.placeHolder;
inputEl.id = entry.id; inputEl.id = entry.id;
inputEl.addEventListener("change", (event) => { inputEl.addEventListener("change", async (event) => {
const result = entry.callbackFn(event.target.value); const result = await entry.callbackFn(event.target.value);
const success = result.valid; const success = result.valid;
if (success) { if (success) {
showToast(entry); showToast(entry);

View File

@@ -1,486 +1,27 @@
/* General */ /* General */
#aura-container-Aura-UI-Assistant-Config { @import url("./css/general.css");
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);
}
/* Header */ /* Header */
.aura-config-page-header-area { @import url("./css/header.css");
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 .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%;
}
/* Status */ /* Status */
.aura-config-page-status-container { @import url("./css/status.css");
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;
}
/* Operation */ /* Operation */
.aura-config-page-operation-area { @import url("./css/operation.css");
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 { /* Config Status Notify */
display: none;
}
.aura-config-page-operation-area.subpage-expanded { @import url("./css/configStatusNotify.css");
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;
}
/* Auth Dialog */ /* Auth Dialog */
.aura-config-page-auth-dialog-area { @import url("./css/authDialog.css");
position: absolute;
height: calc(100% - 40px);
width: 100%;
top: 40px;
left: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
background-color: rgba(255, 255, 255, 0.35);
opacity: 1;
transition: all 0.5s;
}
.aura-config-page-auth-dialog-area.blur-enabled {
height: 100%;
top: 0;
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(5px);
filter: blur(0.1px);
/* ↑ 似乎会导致性能问题 */
}
.acp-ada-hidden {
opacity: 0;
}
.acp-ada-hidden.blur-enabled {
backdrop-filter: blur(0.1px);
filter: unset;
}
.aura-config-page-auth-dialog {
height: 40%;
width: 100%;
background-color: rgba(255, 255, 255, 0.625);
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-confirm-btn {
background-color: transparent;
border-radius: 35px;
border: 1px solid rgba(0, 0, 0, 0.3);
padding: 0.5rem;
}
.acp-auth-confirm-btn .layui-icon {
font-size: 24px;
margin-left: 2px;
}
/* Toast */ /* Toast */
.aura-config-page-toast-area { @import url("./css/toast.css");
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;
}

View 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="header-collapsed aura-config-page-header-area">
<div class="aura-config-page-app-bar" style="-webkit-app-region: drag"> <div class="aura-config-page-app-bar" style="-webkit-app-region: drag">
<div <div
@@ -66,6 +70,28 @@
<div class="aura-config-page-operation-area"> <div class="aura-config-page-operation-area">
<div class="aura-config-page-subpage-container"></div> <div class="aura-config-page-subpage-container"></div>
<div class="aura-config-page-operation-container"> <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 <div
class="operation-el-hidden aura-config-page-operation-el" class="operation-el-hidden aura-config-page-operation-el"
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('disableLimitations', true)" onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('disableLimitations', true)"
@@ -122,6 +148,7 @@
<div <div
class="aura-config-page-auth-dialog-area acp-ada-hidden" class="aura-config-page-auth-dialog-area acp-ada-hidden"
style="display: none" style="display: none"
aura-cancel="true"
> >
<div class="aura-config-page-auth-dialog"> <div class="aura-config-page-auth-dialog">
<p class="acp-auth-dialog-title">验证您的身份</p> <p class="acp-auth-dialog-title">验证您的身份</p>
@@ -134,14 +161,23 @@
id="acp-auth-user-input" 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 <button
class="acp-auth-confirm-btn" class="acp-auth-confirm-btn"
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.verifyAuthPassword()" onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.verifyAuthPassword()"
> >
<i class="layui-icon layui-icon-right"></i> <i class="layui-icon layui-icon-ok"></i>
</button> </button>
</div> </div>
</div> </div>
</div>
<div class="aura-config-page-toast-area"> <div class="aura-config-page-toast-area">
<div class="toast-container position-fixed bottom-0 end-0 p-3"> <div class="toast-container position-fixed bottom-0 end-0 p-3">
@@ -157,10 +193,14 @@
</div> </div>
<div class="toast-body"> <div class="toast-body">
<p>请重载当前窗口以应用修改的设置</p> <p>请重载当前窗口以应用修改的设置</p>
<p>已修改的配置将自动保存</p>
<button <button
type="button" type="button"
class="btn btn-primary btn-sm" 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> </button>
@@ -181,10 +221,14 @@
</div> </div>
<div class="toast-body"> <div class="toast-body">
<p>请重启 Electron 进程以应用修改的设置</p> <p>请重启 Electron 进程以应用修改的设置</p>
<p>已修改的配置将自动保存</p>
<button <button
type="button" type="button"
class="btn btn-primary btn-sm" 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> </button>
@@ -205,6 +249,7 @@
</div> </div>
<div class="toast-body"> <div class="toast-body">
<p>请重启 PLS 进程以应用修改的设置</p> <p>请重启 PLS 进程以应用修改的设置</p>
<p>已修改的配置将自动保存</p>
<button <button
type="button" type="button"
class="btn btn-primary btn-sm" class="btn btn-primary btn-sm"

View File

@@ -2,11 +2,23 @@ global.__HUGO_AURA_UI_REACTIVES__.config = {
isInSubPage: false, isInSubPage: false,
currentActiveSubPage: "", currentActiveSubPage: "",
authenticated: false, authenticated: false,
isConfigPendingWrite: false,
}; };
global.__HUGO_AURA_UI_FUNCTIONS__.config = { global.__HUGO_AURA_UI_FUNCTIONS__.config = {
handleNavBack: () => { handleNavBack: () => {
if (global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage) { 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_FUNCTIONS__.config.toggleSubConfig(
global.__HUGO_AURA_UI_REACTIVES__.config.currentActiveSubPage, global.__HUGO_AURA_UI_REACTIVES__.config.currentActiveSubPage,
false false
@@ -156,13 +168,8 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
encPasswd === encPasswd ===
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt
) { ) {
const acsDialogAreaEl = document.getElementsByClassName( await global.__HUGO_AURA_UI_FUNCTIONS__.config.hideAndResetAuthDialog();
"aura-config-page-auth-dialog-area" await global.__HUGO_AURA_GLOBAL__.utils.sleep(250);
)[0];
acsDialogAreaEl.classList.add("acp-ada-hidden");
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
acsDialogAreaEl.style = "display: none;";
await window.__HUGO_AURA_GLOBAL__.utils.sleep(250);
global.__HUGO_AURA_UI_REACTIVES__.config.authenticated = true; global.__HUGO_AURA_UI_REACTIVES__.config.authenticated = true;
global.__HUGO_AURA_UI_FUNCTIONS__.config.showSecondPhaseAnim(); global.__HUGO_AURA_UI_FUNCTIONS__.config.showSecondPhaseAnim();
return true; return true;
@@ -171,6 +178,91 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
return false; 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
}
},
}; };
(() => { (() => {
@@ -237,15 +329,13 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
const acsDialogAreaEl = document.getElementsByClassName( const acsDialogAreaEl = document.getElementsByClassName(
"aura-config-page-auth-dialog-area" "aura-config-page-auth-dialog-area"
)[0]; )[0];
const acpAppBarEl = document.getElementsByClassName(
"aura-config-page-header-area"
)[0];
acsDialogAreaEl.style = ""; acsDialogAreaEl.style = "";
if (
global.__HUGO_AURA_CONFIG__.auraSettings.appearance
.enablePasswdDialogBlur
) {
acsDialogAreaEl.classList.add("blur-enabled");
}
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500); await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
acsDialogAreaEl.classList.remove("acp-ada-hidden"); acsDialogAreaEl.classList.remove("acp-ada-hidden");
acpAppBarEl.classList.add("color-reverse");
} }
}; };

View 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;
}

View 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;
}

View 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);
}

View 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%;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -1,7 +1,7 @@
<div class="acs-behaviour-control-pls-status-page"> <div class="acs-behaviour-control-pls-status-page">
<p class="acs-bc-pls-status-page-pls-description"> <p class="acs-bc-pls-status-page-pls-description">
HugoAura ProxyLayerServices (Aura-PLS) 是基于 Python + MITMProxy 实现的代理服务, HugoAura ProxyLayerServices (Aura-PLS) 是基于 Python + MITMProxy
用于解密并修改希沃基础服务 (SeewoCore) 的 MQTT 数据包, 实现的代理服务, 用于解密并修改希沃基础服务 (SeewoCore) 的 MQTT 数据包,
实现行为监控、伪造上报等功能 实现行为监控、伪造上报等功能
</p> </p>
<img <img

View File

@@ -8,7 +8,8 @@ const banAuditSettings = [
id: "disableFridayReport", id: "disableFridayReport",
type: "switch", type: "switch",
name: "禁用 Friday 错误统计", name: "禁用 Friday 错误统计",
description: "重置 CVTE 的 Friday 错误收集服务载入 URL, 避免意外的信息上传", description:
"重置 CVTE 的 Friday 错误收集服务载入 URL, 避免意外的信息上传",
restart: true, restart: true,
reload: false, reload: false,
associateVal: null, associateVal: null,
@@ -39,7 +40,8 @@ const banAuditSettings = [
restart: true, restart: true,
reload: false, reload: false,
tip: true, tip: true,
tipTitle: '启用后, 可能造成部分操作出现较长延迟 (如冰点操作)。希沃管家会尝试五次上报, 均失败后才会进行下一步操作', tipTitle:
"启用后, 可能造成部分操作出现较长延迟 (如冰点操作)。希沃管家会尝试五次上报, 均失败后才会进行下一步操作",
associateVal: null, associateVal: null,
auraIf: () => true, auraIf: () => true,
defaultValue: false, defaultValue: false,

View File

@@ -225,8 +225,8 @@ const authSettings = [
auraIf: () => { auraIf: () => {
return ( return (
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"].enabled && global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"].enabled &&
global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"].authRewriteType === global.__HUGO_AURA_CONFIG__.rewrite["vendor/screenLock"]
"customActivationCode" .authRewriteType === "customActivationCode"
); );
}, },
defaultValue: "", defaultValue: "",

View File

@@ -1,3 +1,162 @@
// @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 = [ const auraSettings = [
{ {
id: 0, id: 0,
@@ -12,7 +171,7 @@ const auraSettings = [
restart: false, restart: false,
reload: false, reload: false,
tip: true, tip: true,
tipTitle: "在 0.1.1-beta 版本发布后, 启用访问密码将加密配置文件", tipTitle: "启用访问密码将自动加密配置文件",
associateVal: null, associateVal: null,
auraIf: () => true, auraIf: () => true,
defaultValue: false, defaultValue: false,
@@ -24,11 +183,58 @@ const auraSettings = [
if (typeof newVal !== "boolean") return; if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordEnabled = global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordEnabled =
newVal; newVal;
// TODO: Trigger enc config 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, 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", id: "auraSettingsPasswd",
type: "input", type: "input",
subType: "password", subType: "password",
@@ -48,7 +254,7 @@ const auraSettings = [
valueGetter: () => { valueGetter: () => {
return ""; return "";
}, },
callbackFn: (newVal) => { callbackFn: async (newVal) => {
if (newVal === "" || !newVal) return { valid: true }; if (newVal === "" || !newVal) return { valid: true };
if (newVal.length < 8) if (newVal.length < 8)
return { valid: false, hint: "请输入至少 8 位密码" }; return { valid: false, hint: "请输入至少 8 位密码" };
@@ -74,9 +280,8 @@ const auraSettings = [
.update(newVal + "EndlessX") .update(newVal + "EndlessX")
.digest("hex") .digest("hex")
.toUpperCase(); .toUpperCase();
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt =
result; return await functions.handle2ndPasswordPrompt(result);
return { valid: true };
}, },
}, },
], ],
@@ -84,31 +289,7 @@ const auraSettings = [
{ {
id: 1, id: 1,
categoryName: "外观", categoryName: "外观",
child: [ child: [],
{
index: 0,
id: "enablePasswdDialogBlur",
type: "switch",
name: "密码验证框毛玻璃效果",
description: "启用后, 密码验证时, 背景将具有毛玻璃效果",
restart: false,
reload: false,
warning: true,
warningContent: "不建议在较旧 (如 i5 8 代) 机型上开启, 可能导致性能问题",
associateVal: null,
auraIf: () => true,
defaultValue: true,
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings.appearance
.enablePasswdDialogBlur;
},
callbackFn: (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.appearance.enablePasswdDialogBlur =
newVal;
},
},
],
}, },
]; ];

47
src/aura/utils/eventBus.js Executable file
View 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;

View File

@@ -1,16 +1,17 @@
// @ts-check // @ts-check
if (!global.__HUGO_AURA__) { if (!global.__HUGO_AURA__) {
/**
* @type {import("../aura/types/main/core").MainProcessGlobal}
*/
const __HUGO_AURA__ = { const __HUGO_AURA__ = {
hookedWindows: new Map(), hookedWindows: new Map(),
hooks: new Map(),
configInit: false, configInit: false,
central: () => {},
ipcInit: false,
plsStats: null, plsStats: null,
plsSettings: null, plsSettings: null,
plsRules: null, plsRules: null,
uiHooks: new Map(),
windowHooks: new Map(),
version: require("./preload").__AURA_VERSION__,
}; };
global.__HUGO_AURA__ = __HUGO_AURA__; global.__HUGO_AURA__ = __HUGO_AURA__;
} }
@@ -26,8 +27,9 @@ const os = require("os");
const MainProcessHooksManager = require("../aura/init/main/windowHooksManager"); const MainProcessHooksManager = require("../aura/init/main/windowHooksManager");
const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager"); const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager");
const EventBus = require("../aura/utils/eventBus");
const NetworkHook = require("../aura/init/rendererHook/networkHook"); const NetworkHook = require("../aura/init/rendererHook/networkHook");
const configManager = require("../aura/init/shared/configManager"); const ConfigManager = require("../aura/init/shared/configManager");
const { buildIpcMain } = require("../aura/init/main/ipcHandler"); const { buildIpcMain } = require("../aura/init/main/ipcHandler");
/** /**
@@ -101,9 +103,11 @@ const initLogger = (windowName) => {
* @returns * @returns
*/ */
const launcher = ({ central, windowName, config }) => { const launcher = ({ central, windowName, config }) => {
// >>> Init STD <<< //
process.stdout.isTTY = true; process.stdout.isTTY = true;
process.stderr.isTTY = true; process.stderr.isTTY = true;
// >>> Basic Config <<< //
/** @type {Electron} */ /** @type {Electron} */
const electron = central(1); const electron = central(1);
const app = electron.app; const app = electron.app;
@@ -114,34 +118,58 @@ const launcher = ({ central, windowName, config }) => {
app.exit(0); app.exit(0);
}; };
// >>> Init Logger <<< //
initLogger(windowName); initLogger(windowName);
console.log("[HugoAura / Loaded] Aura is loaded!"); console.log("[HugoAura / Loaded] Aura is loaded!");
console.debug(`[HugoAura / Debug] curWindowName: ${windowName}`); 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(); configManager.ensureConfigExists();
const loadedConfig = configManager.loadConfig(); const loadedConfig = configManager.loadConfig();
if (!global.__HUGO_AURA__.configInit) global.__HUGO_AURA__.configInit = true; 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_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) { if (!global.__HUGO_AURA__.ipcInit) {
buildIpcMain(electron); buildIpcMain(electron);
global.__HUGO_AURA__.ipcInit = true; global.__HUGO_AURA__.ipcInit = true;
} }
// >>> Init Main Process Hooks <<< //
const mainProcessHooksManager = new MainProcessHooksManager(); const mainProcessHooksManager = new MainProcessHooksManager();
const _windowHooks = mainProcessHooksManager.loadHooks(); const _windowHooks = mainProcessHooksManager.loadHooks();
// >>> Init Renderer Process Hooks <<< //
const uiHooksManager = new RendererHooksManager(); const uiHooksManager = new RendererHooksManager();
const uiHooks = uiHooksManager.loadHooks(); const uiHooks = uiHooksManager.loadHooks();
// >>> Activate DevTools <<< //
if (loadedConfig.devTools && !config.canOpenDevTool) { if (loadedConfig.devTools && !config.canOpenDevTool) {
config.canOpenDevTool = true; config.canOpenDevTool = true;
} }
// >>> Listeners <<< //
/**
*
* @param {any} _event
* @param {import("electron").BrowserWindow} browserWindow
*/
const browserWindowCreatedListener = (_event, browserWindow) => { const browserWindowCreatedListener = (_event, browserWindow) => {
mainProcessHooksManager.initHookForWindow( mainProcessHooksManager.initHookForWindow(
windowName, windowName,
@@ -153,7 +181,7 @@ const launcher = ({ central, windowName, config }) => {
/** /**
* *
* @param {Event} _event * @param {any} _event
* @param {import("electron").WebContents} webContents * @param {import("electron").WebContents} webContents
*/ */
const webContentsCreatedListener = (_event, webContents) => { const webContentsCreatedListener = (_event, webContents) => {
@@ -180,13 +208,10 @@ const launcher = ({ central, windowName, config }) => {
}; };
app.once("browser-window-created", browserWindowCreatedListener); app.once("browser-window-created", browserWindowCreatedListener);
// @ts-expect-error
// ↑ idk why
app.once("web-contents-created", webContentsCreatedListener); app.once("web-contents-created", webContentsCreatedListener);
return () => { return () => {
app.removeListener("browser-window-created", browserWindowCreatedListener); app.removeListener("browser-window-created", browserWindowCreatedListener);
// @ts-expect-error
app.removeListener("web-contents-created", webContentsCreatedListener); app.removeListener("web-contents-created", webContentsCreatedListener);
}; };
}; };

View File

@@ -1,9 +1,15 @@
const __AURA_VERSION__ = "0.1.1-pre-II"; // @ts-check
const __AURA_VERSION__ = "0.1.1-pre-III";
(() => { (() => {
if (require.main) return; // 如果只是导入 Aura Version, 不运行闭包逻辑
// >>> Init Global Vars <<< //
if (!global.__HUGO_AURA__) { if (!global.__HUGO_AURA__) {
global.__HUGO_AURA__ = { global.__HUGO_AURA__ = {
configInit: true, // preload 始终比 hook 晚, 默认 config 已初始化 configInit: true, // preload 始终比 hook 晚, 默认 config 已初始化
// ↑ 保留此参数的目的 -> 用于 configManager 中, configManager 的行为在 Renderer 和 Main 中是一致的
version: __AURA_VERSION__, version: __AURA_VERSION__,
}; };
} }
@@ -16,11 +22,29 @@ const __AURA_VERSION__ = "0.1.1-pre-II";
global.__HUGO_AURA_UI_REACTIVES__ = {}; 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"); 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 = []) => { const createConfigProxy = (baseObj, path = []) => {
return new Proxy(baseObj, { return new Proxy(baseObj, {
get(target, prop) { get(target, prop) {
@@ -37,24 +61,76 @@ const __AURA_VERSION__ = "0.1.1-pre-II";
value, value,
}, },
}); });
const pathName = [...path, prop].join(".");
document.dispatchEvent(configUpdateEvent); document.dispatchEvent(configUpdateEvent);
console.log( console.log(
`[HugoAura / Config] Config changed at path: ${[...path, prop].join( `[HugoAura / Config] Config changed at path: ${[...path, prop].join(
"." "."
)}, new value: ${value}` )}, 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; 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); window.__HUGO_AURA_CONFIG__ = createConfigProxy(initialConfig);
// >>> Init Renderer Hooks <<< //
window.__HUGO_AURA_HOOK__ = {}; window.__HUGO_AURA_HOOK__ = {};
const webpackHook = new WebpackHook(); const webpackHook = new WebpackHook();
webpackHook.installHook(window, initialConfig); webpackHook.installHook(window, initialConfig);
// >>> Done <<< //
console.log(`[HugoAura / AppHook / DONE] Hooks installed`); console.log(`[HugoAura / AppHook / DONE] Hooks installed`);
console.log(`[HugoAura / Preload / DONE] Preload done`);
})(); })();
module.exports = { __AURA_VERSION__ };