Files
CipherTalk/electron/services/windowsHelloService.ts
T

150 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Windows Hello 原生服务
* 使用 koffi 调用 wx_key.dll 中的 Windows Hello API 进行生物识别验证
* 比 WebAuthn API 更快,直接调用 WinRT
* 功能已集成到 wx_key.dll 中,与密钥获取共用同一 DLL
*/
import { app } from 'electron'
import path from 'path'
// Windows Hello 结果枚举
export enum WindowsHelloResult {
VERIFIED = 0, // 验证成功
DEVICE_NOT_PRESENT = 1, // 设备不存在
NOT_CONFIGURED = 2, // 未配置
DISABLED_BY_POLICY = 3, // 被策略禁用
DEVICE_BUSY = 4, // 设备忙
RETRIES_EXHAUSTED = 5, // 重试次数耗尽
CANCELED = 6, // 用户取消
UNKNOWN_ERROR = 99 // 未知错误
}
// 错误消息映射
const ERROR_MESSAGES: Record<number, string> = {
[WindowsHelloResult.VERIFIED]: '验证成功',
[WindowsHelloResult.DEVICE_NOT_PRESENT]: '未检测到生物识别设备',
[WindowsHelloResult.NOT_CONFIGURED]: 'Windows Hello 未配置,请在系统设置中设置',
[WindowsHelloResult.DISABLED_BY_POLICY]: 'Windows Hello 被系统策略禁用',
[WindowsHelloResult.DEVICE_BUSY]: '生物识别设备正忙,请稍后重试',
[WindowsHelloResult.RETRIES_EXHAUSTED]: '验证失败次数过多,请稍后重试',
[WindowsHelloResult.CANCELED]: '用户取消了验证',
[WindowsHelloResult.UNKNOWN_ERROR]: '发生未知错误'
}
class WindowsHelloService {
private lib: any = null
private functions: {
WindowsHelloAvailable: () => number
WindowsHelloVerify: (message: string) => number
WindowsHelloGetErrorMessage: (result: number) => string
} | null = null
/**
* 初始化 DLL (使用 wx_key.dllWindows Hello 功能已集成)
*/
private init(): boolean {
if (this.lib) return true
try {
const koffi = require('koffi')
// 确定 DLL 路径 - 使用现有的 wx_key.dll
const isDev = !app.isPackaged
let dllPath: string
if (isDev) {
// 开发环境:从 native-dlls 目录加载
dllPath = path.join(__dirname, '../../native-dlls/wx_key.dll')
} else {
// 生产环境:从 resources 目录加载
dllPath = path.join(process.resourcesPath, 'resources/wx_key.dll')
}
console.log('[WindowsHello] 加载 DLL:', dllPath)
// 加载 DLL
this.lib = koffi.load(dllPath)
// 定义函数签名
this.functions = {
WindowsHelloAvailable: this.lib.func('int WindowsHelloAvailable()'),
WindowsHelloVerify: this.lib.func('int WindowsHelloVerify(const char* message)'),
WindowsHelloGetErrorMessage: this.lib.func('const char* WindowsHelloGetErrorMessage(int result)')
}
console.log('[WindowsHello] DLL 加载成功')
return true
} catch (e: any) {
console.error('[WindowsHello] 初始化失败:', e.message)
this.lib = null
this.functions = null
return false
}
}
/**
* 检查 Windows Hello 是否可用
*/
isAvailable(): boolean {
if (!this.init()) return false
try {
const result = this.functions!.WindowsHelloAvailable()
return result === 1
} catch (e: any) {
console.error('[WindowsHello] 检查可用性失败:', e.message)
return false
}
}
/**
* 请求 Windows Hello 验证
* @param message 向用户显示的消息
* @returns 验证结果
*/
verify(message: string = 'CipherTalk 需要验证您的身份'): { success: boolean; result: WindowsHelloResult; error?: string } {
if (!this.init()) {
return {
success: false,
result: WindowsHelloResult.UNKNOWN_ERROR,
error: 'Windows Hello DLL 未初始化'
}
}
try {
const result = this.functions!.WindowsHelloVerify(message) as WindowsHelloResult
if (result === WindowsHelloResult.VERIFIED) {
return { success: true, result }
}
return {
success: false,
result,
error: ERROR_MESSAGES[result] || '未知错误'
}
} catch (e: any) {
console.error('[WindowsHello] 验证失败:', e.message)
return {
success: false,
result: WindowsHelloResult.UNKNOWN_ERROR,
error: e.message || '验证过程发生异常'
}
}
}
/**
* 获取错误消息
*/
getErrorMessage(result: WindowsHelloResult): string {
return ERROR_MESSAGES[result] || '未知错误'
}
}
// 导出单例
export const windowsHelloService = new WindowsHelloService()
// 导出类型和枚举
export type { WindowsHelloService }