From fa4a403f3877c9f32368edff928af1ce7b020d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Mon, 6 May 2024 22:11:13 +0800 Subject: [PATCH] feat: webui auth helper --- src/webui/Readme.md | 5 +++ src/webui/src/common/config.ts | 2 + src/webui/src/helper/Auth.ts | 68 ++++++++++++++++++++++++++++++++++ src/webui/webui.json | 5 ++- 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/webui/Readme.md create mode 100644 src/webui/src/helper/Auth.ts diff --git a/src/webui/Readme.md b/src/webui/Readme.md new file mode 100644 index 00000000..58e0997c --- /dev/null +++ b/src/webui/Readme.md @@ -0,0 +1,5 @@ +{ + "port": 6099,//端口 + "token": "123456",//密码 + "loginRate": 3//速率 +} \ No newline at end of file diff --git a/src/webui/src/common/config.ts b/src/webui/src/common/config.ts index cf7355bb..7a0f2240 100644 --- a/src/webui/src/common/config.ts +++ b/src/webui/src/common/config.ts @@ -26,6 +26,7 @@ async function tryUsePort(port: number, tryCount: number = 0): Promise { export interface WebUiConfig { port: number; + token: string; } // 读取当前目录下名为 webui.json 的配置文件,如果不存在则创建初始化配置文件 @@ -34,6 +35,7 @@ export async function config(): Promise { let configPath = resolve(__dirname, "./webui.json"); let config: WebUiConfig = { port: 6099, + token: Math.random().toString(36).slice(2)//生成随机密码 }; if (!existsSync(configPath)) { diff --git a/src/webui/src/helper/Auth.ts b/src/webui/src/helper/Auth.ts new file mode 100644 index 00000000..a369df02 --- /dev/null +++ b/src/webui/src/helper/Auth.ts @@ -0,0 +1,68 @@ +import crypto from 'crypto'; + +interface WebUiCredentialInnerJson { + CreatedTime: number; + TokenEncoded: string; +} + +interface WebUiCredentialJson { + Data: WebUiCredentialInnerJson; + Hmac: string; +} + +export class AuthHelper { + private static secretKey = Math.random().toString(36).slice(2); + + /** + * 签名凭证方法。 + * @param token 待签名的凭证字符串。 + * @returns 签名后的凭证对象。 + */ + public static async signCredential(token: string): Promise { + const innerJson: WebUiCredentialInnerJson = { + CreatedTime: Date.now(), + TokenEncoded: token, + }; + const jsonString = JSON.stringify(innerJson); + const hmac = crypto.createHmac('sha256', AuthHelper.secretKey) + .update(jsonString, 'utf8') + .digest('hex'); + return { Data: innerJson, Hmac: hmac }; + } + + /** + * 检查凭证是否被篡改的方法。 + * @param credentialJson 凭证的JSON对象。 + * @returns 布尔值,表示凭证是否有效。 + */ + public static async checkCredential(credentialJson: WebUiCredentialJson): Promise { + try { + const jsonString = JSON.stringify(credentialJson.Data); + const calculatedHmac = crypto.createHmac('sha256', AuthHelper.secretKey) + .update(jsonString, 'utf8') + .digest('hex'); + return calculatedHmac === credentialJson.Hmac; + } catch (error) { + return false; + } + } + + /** + * 验证凭证在1小时内有效且token与原始token相同。 + * @param token 待验证的原始token。 + * @param credentialJson 已签名的凭证JSON对象。 + * @returns 布尔值,表示凭证是否有效且token匹配。 + */ + public static async validateCredentialWithinOneHour(token: string, credentialJson: WebUiCredentialJson): Promise { + const isValid = await AuthHelper.checkCredential(credentialJson); + if (!isValid) { + return false; + } + + const currentTime = Date.now() / 1000; + const createdTime = credentialJson.Data.CreatedTime; + const timeDifference = currentTime - createdTime; + + return timeDifference <= 3600 && credentialJson.Data.TokenEncoded === token; + } +} \ No newline at end of file diff --git a/src/webui/webui.json b/src/webui/webui.json index 77b151bc..ed5bcc3e 100644 --- a/src/webui/webui.json +++ b/src/webui/webui.json @@ -1,3 +1,6 @@ { - "port":6099 + "port": 6099, + "token": "random", + "loginRate": 3 + } \ No newline at end of file