feat(dcauth): 移除机器码,改用纯设备码认证

- DCAuth 协议升级到 v2,签名原文只含设备码;客户端 2.0.0,旧版本返回 426
- 删除客户端机器码采集、后端 machine_code_* 字段与日志、后台机器码展示
- 102 迁移在生产执行前直接改为无机器码结构;SQL 守卫仅放行该文件
- Mock 短信不启用每日限额;修复慢电脑首次启动的协议转发竞态
- 新增 macOS DCAuth.app 打包脚本,注册 dcauth:// 协议,浏览器可直接唤起
This commit is contained in:
yml2213
2026-10-21 20:46:25 +08:00
parent cb916d7750
commit ef36453694
28 changed files with 355 additions and 326 deletions
+46 -25
View File
@@ -191,6 +191,7 @@ var (
trayData notifyIconData
trayAdded bool
runtimeIdentity identity
identityReady bool
authorizationActive bool
windowProcedure = syscall.NewCallback(dcauthWindowProc)
)
@@ -209,16 +210,14 @@ func runClient(protocolArg string) {
if forwardToRunningInstance(protocolArg) {
return
}
showError("DCAuth 启动失败", "已有 DCAuth 实例正在启动,但暂时无法连接,请稍后重试。")
return
firstInstance, err = acquireSingleInstance()
if err != nil || !firstInstance {
showError("DCAuth 启动失败", "DCAuth 已在运行但暂时没有响应。请在任务管理器中结束 DCAuth.exe 后重试。")
return
}
}
registerProtocol()
runtimeIdentity, err = loadOrCreateIdentity()
if err != nil {
showError("DCAuth 初始化失败", err.Error())
return
}
if err := createHiddenWindow(); err != nil {
showError("DCAuth 启动失败", err.Error())
return
@@ -228,10 +227,20 @@ func runClient(protocolArg string) {
return
}
runtimeIdentity, err = loadOrCreateIdentity()
if err != nil {
removeTrayIcon()
showError("DCAuth 初始化失败", err.Error())
destroyWindow.Call(mainWindow)
mainWindow = 0
return
}
identityReady = true
if protocolArg != "" {
handleAuthorization(protocolArg)
} else {
showTrayBalloon("DCAuth v"+clientVersion+" 已在后台运行", "双击托盘图标可查看版本、设备码和机器码。")
showTrayBalloon("DCAuth v"+clientVersion+" 已在后台运行", "双击托盘图标可查看版本和设备码。")
}
runMessageLoop()
@@ -279,16 +288,16 @@ func acquireNamedMutex(name string) (uintptr, bool, error) {
}
func forwardToRunningInstance(protocolArg string) bool {
for attempt := 0; attempt < 100; attempt++ {
if postToRunningInstance(protocolArg) {
return true
for attempt := 0; attempt < 300; attempt++ {
if hwnd := findRunningInstanceWindow(); hwnd != 0 {
return sendToRunningInstance(hwnd, protocolArg)
}
sleep.Call(100)
}
return false
}
func postToRunningInstance(protocolArg string) bool {
func findRunningInstanceWindow() uintptr {
classPtr, _ := syscall.UTF16PtrFromString(windowClassName)
titlePtr, _ := syscall.UTF16PtrFromString(windowTitle)
hwnd, _, _ := findWindowW.Call(
@@ -297,12 +306,13 @@ func postToRunningInstance(protocolArg string) bool {
)
runtime.KeepAlive(classPtr)
runtime.KeepAlive(titlePtr)
if hwnd == 0 {
return false
}
return hwnd
}
func sendToRunningInstance(hwnd uintptr, protocolArg string) bool {
if protocolArg == "" {
postMessageW.Call(hwnd, showWindowMessage, 0, 0)
return true
result, _, _ := postMessageW.Call(hwnd, showWindowMessage, 0, 0)
return result != 0
}
encoded, _ := syscall.UTF16FromString(protocolArg)
@@ -387,6 +397,9 @@ func runMessageLoop() {
func dcauthWindowProc(hwnd, msg, wParam, lParam uintptr) uintptr {
switch uint32(msg) {
case wmCopyData:
if !identityReady {
return 0
}
data := (*copyDataStruct)(unsafe.Pointer(lParam))
if data != nil && data.DwData == copyDataMagic && data.CbData > 0 && data.LpData != 0 {
count := int(data.CbData / 2)
@@ -396,12 +409,18 @@ func dcauthWindowProc(hwnd, msg, wParam, lParam uintptr) uintptr {
}
return 0
case showWindowMessage:
showDeviceInfo()
if identityReady {
showDeviceInfo()
}
return 0
case trayCallbackMessage:
switch uint32(lParam) {
case wmLButtonDblClk:
showDeviceInfo()
if identityReady {
showDeviceInfo()
} else {
showTrayBalloon("DCAuth 正在初始化", "设备信息准备完成后即可查看。")
}
case wmRButtonUp, wmContextMenu:
showTrayMenu(hwnd)
}
@@ -497,7 +516,11 @@ func showTrayMenu(hwnd uintptr) {
switch command {
case trayMenuDeviceInfo:
showDeviceInfo()
if identityReady {
showDeviceInfo()
} else {
showTrayBalloon("DCAuth 正在初始化", "设备信息准备完成后即可查看。")
}
case trayMenuExit:
destroyWindow.Call(hwnd)
}
@@ -505,12 +528,11 @@ func showTrayMenu(hwnd uintptr) {
func showDeviceInfo() {
text := fmt.Sprintf(
"版本:v%s\n\n设备码:%s\n机器码:%s\n\nDCAuth 正在后台运行。浏览器登录时只会打开一个确认窗口。\n设备码和机器码已复制到剪贴板。",
"版本:v%s\n\n设备码:%s\n\nDCAuth 正在后台运行。浏览器登录时只会打开一个确认窗口。\n设备码已复制到剪贴板。",
clientVersion,
runtimeIdentity.deviceID,
runtimeIdentity.machineCode,
)
copyToClipboard(runtimeIdentity.deviceID + "\n" + runtimeIdentity.machineCode)
copyToClipboard(runtimeIdentity.deviceID)
showInfo("DCAuth v"+clientVersion+" 设备信息", text)
}
@@ -543,11 +565,10 @@ func handleAuthorization(raw string) {
if !confirm(
"DCAuth v"+clientVersion+" · "+app.DisplayName+" 本机登录确认",
fmt.Sprintf(
"是否允许使用本机设备登录「%s」?\n\n客户端版本:v%s\n设备码:%s\n机器码:%s\n\n点击“确定”允许本次登录,点击“取消”拒绝。",
"是否允许使用本机设备登录「%s」?\n\n客户端版本:v%s\n设备码:%s\n\n点击“确定”允许本次登录,点击“取消”拒绝。",
app.DisplayName,
clientVersion,
runtimeIdentity.deviceID,
runtimeIdentity.machineCode,
),
) {
return