SnowCat 雪猫底层全源码:NapCat 4.18.28 底座 + SnowLuma 能力移植 + V8 通道适配 9.9.37

26 包 monorepo(TS 全源码):
- snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包
- snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线
- snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI)
- snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports)
- snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时
- 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏)
- 工具件: 解包器/启动器/便携制作器/doctor

GitHub 关联已全量指向 DandanLLab/SnowCatQQ
This commit is contained in:
天天的鸟蛋蛋 committed 2026-11-12 06:27:36 +08:00
commit b9655a5ab1
1048 files changed
+130851

No files matched your search

@@ -0,0 +1,114 @@
import crypto from 'crypto';
import store from 'snowcat-common/src/store';
import type { WebUiCredentialJson, WebUiCredentialInnerJson } from '@/snowcat-webui-backend/src/types';
export class AuthHelper {
private static readonly secretKey = process.env['NAPCAT_WEBUI_JWT_SECRET_KEY'] || Math.random().toString(36).slice(2);
private static readonly MAX_CREDENTIAL_VALID_SECONDS = 3600;
public static getSecretKey (): string {
return AuthHelper.secretKey;
}
/**
* 签名凭证方法。
* @param hash 待签名的凭证字符串。
* @returns 签名后的凭证对象。
*/
public static signCredential (hash: string): WebUiCredentialJson {
const innerJson: WebUiCredentialInnerJson = {
// 统一使用秒级时间戳,避免与校验逻辑出现单位不一致
CreatedTime: Math.floor(Date.now() / 1000),
HashEncoded: hash,
};
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 checkCredential (credentialJson: WebUiCredentialJson): boolean {
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 validateCredentialWithinOneHour (token: string, credentialJson: WebUiCredentialJson): boolean {
// 首先检查凭证是否被篡改
const isValid = AuthHelper.checkCredential(credentialJson);
if (!isValid) {
return false;
}
// 检查凭证是否在黑名单中
if (AuthHelper.isCredentialRevoked(credentialJson)) {
return false;
}
const currentTimeSeconds = Math.floor(Date.now() / 1000);
const createdTimeSeconds = Math.floor(Number(credentialJson.Data.CreatedTime));
const timeDifferenceSeconds = currentTimeSeconds - createdTimeSeconds;
const isWithinOneHour = timeDifferenceSeconds >= 0 && timeDifferenceSeconds <= AuthHelper.MAX_CREDENTIAL_VALID_SECONDS;
return isWithinOneHour && credentialJson.Data.HashEncoded === AuthHelper.generatePasswordHash(token);
}
/**
* 注销指定的Token凭证
* @param credentialJson 凭证JSON对象
* @returns void
*/
public static revokeCredential (credentialJson: WebUiCredentialJson): void {
const jsonString = JSON.stringify(credentialJson.Data);
const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');
// 将已注销的凭证添加到黑名单中,有效期1小时
store.set(`revoked:${hmac}`, true, 3600);
}
/**
* 检查凭证是否已被注销
* @param credentialJson 凭证JSON对象
* @returns 布尔值,表示凭证是否已被注销
*/
public static isCredentialRevoked (credentialJson: WebUiCredentialJson): boolean {
const jsonString = JSON.stringify(credentialJson.Data);
const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');
return store.exists(`revoked:${hmac}`) > 0;
}
/**
* 生成密码Hash
* @param password 密码
* @returns 生成的Hash值
*/
public static generatePasswordHash (password: string): string {
return crypto.createHash('sha256').update(password + '.napcat').digest().toString('hex');
}
/**
* 对比密码和Hash值
* @param password 密码
* @param hash Hash值
* @returns 布尔值,表示密码是否匹配Hash值
*/
public static comparePasswordHash (password: string, hash: string): boolean {
return this.generatePasswordHash(password) === hash;
}
}