[Feat] Settings UI Auth (#3) & Prepare for v0.1.1-rel

This commit is contained in:
Minoricew
2025-06-02 00:22:46 +08:00
parent 1320f5397a
commit a86d13431b
12 changed files with 569 additions and 34 deletions

View File

@@ -68,3 +68,29 @@
.aura-settings-entry-property-icon.layui-icon-refresh {
color: rgb(0, 106, 188);
}
/* 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);
}
}

View File

@@ -45,6 +45,7 @@
padding-left: 8px;
padding-right: 8px;
color: white;
z-index: 12000;
opacity: 1;
transform: translateY(0);
@@ -368,6 +369,82 @@
font-size: small;
}
/* Auth Dialog */
.aura-config-page-auth-dialog-area {
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 */
.aura-config-page-toast-area {

View File

@@ -80,8 +80,10 @@
</div>
<div
class="operation-el-hidden aura-config-page-operation-el"
onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('behaviourCtrl', true)"
aura-disabled="true"
>
<!-- Still WIP -->
<!-- onclick="window.__HUGO_AURA_UI_FUNCTIONS__.config.toggleSubConfig('behaviourCtrl', true)" -->
<div class="aura-config-page-operation-body">
<img src="../../aura/ui/static/config/behaviour_mon.svg" />
<div>
@@ -114,6 +116,30 @@
</div>
</div>
<div
class="aura-config-page-auth-dialog-area acp-ada-hidden"
style="display: none"
>
<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"
/>
<button
class="acp-auth-confirm-btn"
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.verifyAuthPassword()"
>
<i class="layui-icon layui-icon-right"></i>
</button>
</div>
</div>
<div class="aura-config-page-toast-area">
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div

View File

@@ -117,6 +117,48 @@ 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
) {
const acsDialogAreaEl = document.getElementsByClassName(
"aura-config-page-auth-dialog-area"
)[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_FUNCTIONS__.config.showSecondPhaseAnim();
return true;
} else {
showFailedAnimation(inputEl);
return false;
}
},
};
(() => {
@@ -167,23 +209,51 @@ 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) {
showOperationsAnimation();
} else {
await window.__HUGO_AURA_GLOBAL__.utils.sleep(50);
const acsDialogAreaEl = document.getElementsByClassName(
"aura-config-page-auth-dialog-area"
)[0];
acsDialogAreaEl.style = "";
if (
global.__HUGO_AURA_CONFIG__.auraSettings.appearance
.enablePasswdDialogBlur
) {
acsDialogAreaEl.classList.add("blur-enabled");
}
await window.__HUGO_AURA_GLOBAL__.utils.sleep(500);
acsDialogAreaEl.classList.remove("acp-ada-hidden");
}
};
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 = () => {

View File

@@ -6,6 +6,20 @@
<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="auth-subpage-tab"
data-bs-toggle="pill"
data-bs-target="#auth-subpage"
@@ -14,7 +28,7 @@
aria-controls="auth-subpage"
aria-selected="true"
>
认证与基础设施
认证与环境
</button>
</li>
<li class="nav-item" role="presentation">
@@ -35,6 +49,12 @@
<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 show"
id="auth-subpage"
role="tabpanel"
aria-labelledby="auth-subpage-tab"

View File

@@ -5,9 +5,15 @@
const {
settingsRenderer,
} = require("../../aura/ui/composables/settingsRenderer");
const { auraSettings } = require(`${pathBase}/aura`);
const { authSettings } = require(`${pathBase}/auth`);
const { banAuditSettings } = require(`${pathBase}/audit`);
const initAuraSubPage = () => {
const auraSettingsSubPageEl = document.getElementById("aura-subpage");
settingsRenderer(auraSettingsSubPageEl, auraSettings);
};
const initAuthSubPage = () => {
const authSubPageEl = document.getElementById("auth-subpage");
settingsRenderer(authSubPageEl, authSettings);
@@ -19,6 +25,7 @@
};
const onMounted = () => {
initAuraSubPage();
initAuthSubPage();
initBanAuditSubPage();

View File

@@ -0,0 +1,113 @@
const auraSettings = [
{
id: 0,
categoryName: "安全性",
child: [
{
index: 0,
id: "enableAuraSettingsPasswd",
type: "switch",
name: "启用访问密码",
description: "启用后, Aura 设置 UI 需要输入密码才可访问",
restart: false,
reload: false,
tip: true,
tipTitle: "在 0.1.1-beta 版本发布后, 启用访问密码将加密配置文件",
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;
// TODO: Trigger enc config
},
},
{
index: 1,
id: "auraSettingsPasswd",
type: "input",
subType: "password",
name: "访问密码",
description: "此密码将用于访问 Aura 设置 UI",
restart: false,
reload: false,
associateVal: ["auraSettings.settingsPasswordEnabled"],
auraIf: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings
.settingsPasswordEnabled;
},
defaultValue: "",
placeHolder: "留空表示不修改, 保留已设置值",
valueGetter: () => {
return "";
},
callbackFn: (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();
global.__HUGO_AURA_CONFIG__.auraSettings.settingsPasswordWithSalt =
result;
return { valid: true };
},
},
],
},
{
id: 1,
categoryName: "外观",
child: [
{
index: 0,
id: "enablePasswdDialogBlur",
type: "switch",
name: "密码验证框毛玻璃效果",
description: "启用后, 密码验证时, 背景将具有毛玻璃效果",
restart: false,
reload: false,
tip: true,
tipTitle: "不建议在较旧 (如 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;
},
},
],
},
];
module.exports = { auraSettings };

View File

@@ -1,7 +1,7 @@
const authSettings = [
{
id: 0,
categoryName: "身份验证",
categoryName: "管家身份验证",
child: [
{
index: 0,