refactor: 重构硬件指纹模块并清理无关依赖

- 添加 ohash 和 systeminformation 依赖项到项目中
- 将硬件指纹生成模块从工具包移至服务器应用,并统一优化注释中的标点符号为中文全角格式,提升代码注释的可读性与一致性。
- 将硬件指纹获取方法的导入路径从 '@furtherverse/utils/fingerprint' 更新为 '@/lib/fingerprint'。
- 移除对本地 workspace 包 @furtherverse/utils 的依赖并清理相关配置
- 删除未使用的工具包配置文件并移除相关依赖项
- 删除硬件指纹测试文件,移除对 systeminformation 模块的模拟和相关测试用例。
- 移除对 fingerprint 工具函数的导出
- 删除未使用的 tsconfig 配置文件
This commit is contained in:
2026-01-24 03:42:12 +08:00
parent 8ceb212033
commit b0d3245b9d
8 changed files with 35 additions and 249 deletions

View File

@@ -1,25 +0,0 @@
{
"name": "@furtherverse/utils",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"fix": "biome check --write",
"typecheck": "tsc --noEmit"
},
"imports": {
"#*": "./src/*"
},
"exports": {
".": "./src/index.ts",
"./*": "./src/*.ts"
},
"dependencies": {
"ohash": "catalog:",
"systeminformation": "catalog:"
},
"devDependencies": {
"@furtherverse/tsconfig": "workspace:*",
"typescript": "catalog:"
}
}

View File

@@ -1,173 +0,0 @@
import { beforeEach, describe, expect, it, mock } from 'bun:test'
import { getHardwareFingerprint } from './fingerprint'
// Mock systeminformation module
const mockSystemInfo = {
uuid: mock(() =>
Promise.resolve({
os: 'test-os-uuid',
hardware: 'test-hardware-uuid',
}),
),
baseboard: mock(() =>
Promise.resolve({
manufacturer: 'Test Manufacturer',
model: 'Test Model',
version: '1.0',
serial: 'TEST123',
}),
),
bios: mock(() =>
Promise.resolve({
vendor: 'Test Vendor',
version: '1.0.0',
releaseDate: '2024-01-01',
}),
),
system: mock(() =>
Promise.resolve({
manufacturer: 'Test System',
model: 'Test Model',
version: '1.0',
sku: 'TEST-SKU',
}),
),
diskLayout: mock(() =>
Promise.resolve([
{
device: '/dev/sda',
type: 'SSD',
name: 'Test Disk',
size: 512000000000,
},
]),
),
networkInterfaces: mock(() =>
Promise.resolve([
{
iface: 'eth0',
mac: '00:11:22:33:44:55',
ip4: '192.168.1.1',
},
]),
),
}
mock.module('systeminformation', () => ({
default: mockSystemInfo,
}))
describe('fingerprint', () => {
beforeEach(() => {
// Reset all mocks before each test
mockSystemInfo.uuid.mockClear()
mockSystemInfo.baseboard.mockClear()
mockSystemInfo.bios.mockClear()
mockSystemInfo.system.mockClear()
mockSystemInfo.diskLayout.mockClear()
mockSystemInfo.networkInterfaces.mockClear()
})
describe('getHardwareFingerprint', () => {
it('should return a fingerprint hash', async () => {
const fingerprint = await getHardwareFingerprint()
expect(fingerprint).toBeDefined()
expect(typeof fingerprint).toBe('string')
expect(fingerprint.length).toBeGreaterThan(0)
})
it('should call all system information methods', async () => {
await getHardwareFingerprint()
expect(mockSystemInfo.uuid).toHaveBeenCalledTimes(1)
expect(mockSystemInfo.baseboard).toHaveBeenCalledTimes(1)
expect(mockSystemInfo.bios).toHaveBeenCalledTimes(1)
expect(mockSystemInfo.system).toHaveBeenCalledTimes(1)
expect(mockSystemInfo.diskLayout).toHaveBeenCalledTimes(1)
expect(mockSystemInfo.networkInterfaces).toHaveBeenCalledTimes(1)
})
it('should return the same fingerprint for the same system info', async () => {
const fingerprint1 = await getHardwareFingerprint()
const fingerprint2 = await getHardwareFingerprint()
expect(fingerprint1).toBe(fingerprint2)
})
it('should return different fingerprint when system info changes', async () => {
const fingerprint1 = await getHardwareFingerprint()
// Change mock data
mockSystemInfo.uuid.mockImplementationOnce(() =>
Promise.resolve({
os: 'different-os-uuid',
hardware: 'different-hardware-uuid',
}),
)
const fingerprint2 = await getHardwareFingerprint()
expect(fingerprint1).not.toBe(fingerprint2)
})
it('should handle empty system information gracefully', async () => {
// Mock empty responses
mockSystemInfo.uuid.mockImplementationOnce(() =>
Promise.resolve({ os: '', hardware: '' }),
)
mockSystemInfo.baseboard.mockImplementationOnce(() =>
Promise.resolve({
manufacturer: '',
model: '',
version: '',
serial: '',
}),
)
mockSystemInfo.bios.mockImplementationOnce(() =>
Promise.resolve({ vendor: '', version: '', releaseDate: '' }),
)
mockSystemInfo.system.mockImplementationOnce(() =>
Promise.resolve({ manufacturer: '', model: '', version: '', sku: '' }),
)
mockSystemInfo.diskLayout.mockImplementationOnce(() =>
Promise.resolve([]),
)
mockSystemInfo.networkInterfaces.mockImplementationOnce(() =>
Promise.resolve([]),
)
const fingerprint = await getHardwareFingerprint()
expect(fingerprint).toBeDefined()
expect(typeof fingerprint).toBe('string')
})
it('should handle partial system information', async () => {
mockSystemInfo.baseboard.mockImplementationOnce(() =>
Promise.resolve({
manufacturer: 'Only Manufacturer',
model: '',
version: '',
serial: '',
}),
)
const fingerprint = await getHardwareFingerprint()
expect(fingerprint).toBeDefined()
expect(typeof fingerprint).toBe('string')
})
it('should be deterministic with the same input', async () => {
const results = await Promise.all([
getHardwareFingerprint(),
getHardwareFingerprint(),
getHardwareFingerprint(),
])
expect(results[0]).toBe(results[1])
expect(results[1]).toBe(results[2])
})
})
})

View File

@@ -1,231 +0,0 @@
import { hash } from 'ohash'
import si from 'systeminformation'
/**
* 硬件指纹质量等级
* - strong: 2+ 个强标识符可用(推荐用于生产授权)
* - medium: 1 个强标识符可用(可用但不理想)
* - weak: 无强标识符(仅适合开发/测试)
*/
export type FingerprintQuality = 'strong' | 'medium' | 'weak'
/**
* 标准化的系统信息(用于机器码生成)
*/
export type NormalizedSystemInfo = {
/** 系统 UUID最稳定的硬件标识符 */
systemUuid: string | null
/** 系统序列号 */
systemSerial: string | null
/** 主板序列号 */
baseboardSerial: string | null
/** 主板制造商 */
baseboardManufacturer: string | null
/** BIOS 版本 */
biosVersion: string | null
/** BIOS 供应商 */
biosVendor: string | null
/** CPU 品牌标识(用于质量评估) */
cpuBrand: string | null
/** 主硬盘序列号(可选,高稳定性) */
primaryDiskSerial?: string | null
}
/**
* 硬件指纹配置选项
*/
export type HardwareFingerprintOptions = {
/**
* 缓存 TTL毫秒默认 10 分钟
* 硬件信息变化频率极低,缓存可大幅提升性能
*/
cacheTtlMs?: number
/**
* 是否包含主硬盘序列号(默认 true
* 注意:在容器/虚拟机环境可能获取失败
*/
includePrimaryDisk?: boolean
}
/**
* 硬件指纹响应
*/
export type HardwareFingerprintResult = {
/** 机器码HMAC-SHA256 哈希64 字符十六进制) */
fingerprint: string
/** 指纹质量等级 */
quality: FingerprintQuality
/** 可用的强标识符数量 */
strongIdentifiersCount: number
/** 生成时间戳 */
timestamp: number
}
// 缓存实例
let cache: {
expiresAt: number
value: HardwareFingerprintResult
} | null = null
// 防止并发重复请求
let inFlight: Promise<HardwareFingerprintResult> | null = null
/**
* 计算指纹质量
*/
function computeQuality(info: NormalizedSystemInfo): {
quality: FingerprintQuality
count: number
} {
const strongKeys = [
info.systemUuid,
info.systemSerial,
info.baseboardSerial,
info.primaryDiskSerial,
].filter(Boolean).length
if (strongKeys >= 2) return { quality: 'strong', count: strongKeys }
if (strongKeys === 1) return { quality: 'medium', count: strongKeys }
return { quality: 'weak', count: 0 }
}
/**
* 安全地收集标准化系统信息(容错处理)
*/
async function collectNormalizedInfo(
opts: HardwareFingerprintOptions,
): Promise<NormalizedSystemInfo> {
// 使用 Promise.allSettled 避免单点失败
const tasks = await Promise.allSettled([
si.uuid(),
si.system(),
si.baseboard(),
si.bios(),
si.cpu(),
opts.includePrimaryDisk !== false ? si.diskLayout() : Promise.resolve([]),
])
const [uuidRes, systemRes, baseboardRes, biosRes, cpuRes, diskRes] = tasks
const uuid = uuidRes.status === 'fulfilled' ? uuidRes.value : null
const system = systemRes.status === 'fulfilled' ? systemRes.value : null
const baseboard =
baseboardRes.status === 'fulfilled' ? baseboardRes.value : null
const bios = biosRes.status === 'fulfilled' ? biosRes.value : null
const cpu = cpuRes.status === 'fulfilled' ? cpuRes.value : null
// 提取主硬盘序列号(通常是第一个物理磁盘)
let primaryDiskSerial: string | null = null
if (diskRes.status === 'fulfilled' && Array.isArray(diskRes.value)) {
const disks = diskRes.value as Array<{ serialNum?: string; type?: string }>
const physicalDisk = disks.find(
(d) => d.type !== 'USB' && d.serialNum && d.serialNum.trim(),
)
primaryDiskSerial = physicalDisk?.serialNum?.trim() || null
}
return {
// 系统级标识符(最稳定)
systemUuid: (system?.uuid ?? uuid?.hardware ?? null) || null,
systemSerial: (system?.serial ?? null) || null,
// 主板标识符(次稳定)
baseboardSerial: (baseboard?.serial ?? null) || null,
baseboardManufacturer: (baseboard?.manufacturer ?? null) || null,
// BIOS 信息(辅助识别)
biosVersion: (bios?.version ?? null) || null,
biosVendor: (bios?.vendor ?? null) || null,
// CPU 信息(辅助识别)
cpuBrand: (cpu?.brand ?? null) || null,
// 磁盘序列号(可选,高稳定性)
...(opts.includePrimaryDisk !== false ? { primaryDiskSerial } : {}),
}
}
/**
/**
* 获取硬件指纹(机器码)
*
* 适用场景:客户端部署的软件授权、机器绑定
*
* 安全说明:
* - 返回 SHA-256 哈希Base64URL 编码43 字符),不可逆推原始硬件信息
* - 使用 ohash 自动处理对象序列化和哈希
* - 客户端部署场景:客户可以看到代码,无法使用密钥加密
* - 安全性依赖硬件信息本身的不可伪造性(来自操作系统)
* - 自动缓存减少系统调用开销
*
* 稳定性:
* - 优先使用系统 UUID、序列号等不易变更的标识符
* - 避免网络接口等易变信息
* - 容错处理,部分信息缺失不影响生成
*
* @example
* ```typescript
* const result = await getHardwareFingerprint({
* cacheTtlMs: 600000, // 10 分钟
* includePrimaryDisk: true,
* })
*
* console.log(result.fingerprint) // "a3f5e8c2d1b4..."
* console.log(result.quality) // "strong"
* ```
*/
export async function getHardwareFingerprint(
opts: HardwareFingerprintOptions,
): Promise<HardwareFingerprintResult> {
const ttl = opts.cacheTtlMs ?? 10 * 60 * 1000
const now = Date.now()
// 返回缓存结果
if (cache && cache.expiresAt > now) {
return cache.value
}
// 防止并发重复请求
if (inFlight) {
return inFlight
}
inFlight = (async () => {
// 收集标准化信息
const info = await collectNormalizedInfo(opts)
// 计算质量
const { quality, count } = computeQuality(info)
// 使用 ohash 生成指纹(自动序列化 + SHA-256 + Base64URL
const fingerprint = hash({
v: 1, // 版本号,未来如需变更采集策略可递增
info,
})
const result: HardwareFingerprintResult = {
fingerprint,
quality,
strongIdentifiersCount: count,
timestamp: now,
}
// 更新缓存
cache = { expiresAt: now + ttl, value: result }
return result
})().finally(() => {
inFlight = null
})
return inFlight
}
/**
* 清除指纹缓存(用于测试或强制刷新)
*/
export function clearFingerprintCache(): void {
cache = null
inFlight = null
}

View File

@@ -1 +0,0 @@
export * from './fingerprint'

View File

@@ -1,3 +0,0 @@
{
"extends": "@furtherverse/tsconfig/base.json"
}