|
|
@@ -265,7 +265,7 @@ else {
|
|
|
createCore:({root,dataRoot})=>new DesktopHostCore({root,dataRoot}),
|
|
|
encrypt:value=>credentials.encrypt(value),
|
|
|
decrypt:bytes=>credentials.decrypt(bytes),
|
|
|
- onState:message=>{log(`桌面主机: ${message}`);const item=Menu.getApplicationMenu()?.getMenuItemById('desktop-host-status');if(item)item.label=message}})
|
|
|
+ onState:message=>{log(`电脑: ${message}`);const item=Menu.getApplicationMenu()?.getMenuItemById('desktop-host-status');if(item)item.label=message}})
|
|
|
ipcMain.handle('desktop:device-host', async event => {
|
|
|
try {
|
|
|
const trusted = event.sender === window?.webContents && event.senderFrame === event.sender.mainFrame
|
|
|
@@ -281,8 +281,15 @@ else {
|
|
|
}
|
|
|
return { deviceHost: 'local' }
|
|
|
})
|
|
|
- async function hostAction(action){try{await action()}catch(error){await dialog.showMessageBox(window,{type:'error',message:'桌面主机操作未完成',detail:error.message})}}
|
|
|
+ async function hostAction(action){try{await action()}catch(error){await dialog.showMessageBox(window,{type:'error',message:'电脑操作未完成',detail:error.message})}}
|
|
|
const appDialog = options => window && !window.isDestroyed() ? dialog.showMessageBox(window, options) : dialog.showMessageBox(options)
|
|
|
+ async function authorizeComputer(server,session){
|
|
|
+ const previous=await hostManager.read().catch(()=>undefined)
|
|
|
+ const previousHostId=previous&&new URL(previous.serverURL).origin===new URL(server).origin?previous.hostId:undefined
|
|
|
+ const registration=await enrollDesktopHost(session,{name:hostname(),installId:await hostManager.installIdentity(),previousHostId})
|
|
|
+ await hostManager.adopt({protocol:1,serverURL:server,hostId:registration.host.id,token:registration.token,...(server.startsWith('http://')?{allowInsecureLan:true}:{})})
|
|
|
+ return registration
|
|
|
+ }
|
|
|
function requireModePage(event){
|
|
|
let trusted=false
|
|
|
try{trusted=event.sender===window?.webContents&&event.senderFrame===window.webContents.mainFrame
|
|
|
@@ -303,10 +310,26 @@ else {
|
|
|
if(switchingMode)throw new Error('正在切换运行模式,请稍候')
|
|
|
openRemoteLogin()
|
|
|
})
|
|
|
+ ipcMain.handle('desktop:computer-authorize',async(event,csrfToken)=>{
|
|
|
+ requireModePage(event)
|
|
|
+ if(!remoteMode||!remoteURL)return {registered:false}
|
|
|
+ try{
|
|
|
+ const token=String(csrfToken??'').trim()
|
|
|
+ if(!token)throw new Error('登录状态缺少安全令牌,请重新登录')
|
|
|
+ const cookies=await electronSession.defaultSession.cookies.get({url:remoteURL})
|
|
|
+ const registration=await authorizeComputer(remoteURL,{origin:remoteURL,csrfToken:token,cookies:cookies.map(cookie=>[cookie.name,cookie.value])})
|
|
|
+ return {registered:true,hostId:registration.host.id}
|
|
|
+ }catch(error){
|
|
|
+ const message=error instanceof Error?error.message:'电脑授权恢复失败'
|
|
|
+ hostManager.publish(`电脑授权未恢复:${message}`)
|
|
|
+ await appDialog({type:'warning',message:'账号已登录,但电脑授权未恢复',detail:`${message}\n\n请在“电脑”菜单中选择“重新授权…”。`})
|
|
|
+ return {registered:false}
|
|
|
+ }
|
|
|
+ })
|
|
|
async function importDesktopHost(){
|
|
|
const selection=window&&!window.isDestroyed()
|
|
|
- ?await dialog.showOpenDialog(window,{title:'导入桌面主机配置',properties:['openFile'],filters:[{name:'桌面主机配置',extensions:['json']}]})
|
|
|
- :await dialog.showOpenDialog({title:'导入桌面主机配置',properties:['openFile'],filters:[{name:'桌面主机配置',extensions:['json']}]})
|
|
|
+ ?await dialog.showOpenDialog(window,{title:'导入电脑配置',properties:['openFile'],filters:[{name:'电脑配置',extensions:['json']}]})
|
|
|
+ :await dialog.showOpenDialog({title:'导入电脑配置',properties:['openFile'],filters:[{name:'电脑配置',extensions:['json']}]})
|
|
|
if(!selection.canceled&&selection.filePaths[0]&&!closing)await hostAction(()=>hostManager.importFile(selection.filePaths[0]))
|
|
|
}
|
|
|
function openRemoteLogin(){
|
|
|
@@ -388,8 +411,7 @@ else {
|
|
|
const auth=await remoteSession(server,{username:value?.username,password:value?.password})
|
|
|
let registered=false
|
|
|
if(auth.user?.role==='admin'){
|
|
|
- const registration=await enrollDesktopHost(auth,{name:hostname(),installId:await hostManager.installIdentity()})
|
|
|
- await hostManager.adopt({protocol:1,serverURL:server,hostId:registration.host.id,token:registration.token,...(server.startsWith('http://')?{allowInsecureLan:true}:{})})
|
|
|
+ await authorizeComputer(server,auth)
|
|
|
registered=true
|
|
|
}
|
|
|
try{
|
|
|
@@ -401,7 +423,7 @@ else {
|
|
|
if(!window||window.isDestroyed())createWindow()
|
|
|
else void window.loadURL(server)
|
|
|
loginWindow?.close()
|
|
|
- if(!registered)await appDialog({type:'info',message:'已登录远程服务器',detail:'当前账号不是管理员:窗口将使用远程夭夭。要把这台 Mac 注册为可远程控制的桌面主机,请使用管理员账号重新登录。'})
|
|
|
+ if(!registered)await appDialog({type:'info',message:'已登录远程服务器',detail:'当前账号不是管理员:窗口将使用远程夭夭。要把这台 Mac 注册为可远程控制的电脑,请使用管理员账号重新登录。'})
|
|
|
return {ok:true,hostRegistered:registered,user:{username:auth.user.username,role:auth.user.role}}
|
|
|
}catch(error){return {ok:false,error:error instanceof Error?error.message:'登录失败'}}
|
|
|
})
|
|
|
@@ -418,7 +440,7 @@ else {
|
|
|
const stored=preferences.value.startupChoice
|
|
|
if(stored==='local'||stored==='remote')return stored
|
|
|
const choice=await dialog.showMessageBox({type:'question',title:'夭夭',message:'这台 Mac 如何使用夭夭?',
|
|
|
- detail:'「登录远程」用夭夭服务器的地址和账号密码登录另一台电脑上的夭夭:本机不运行 Web 服务,窗口直接使用远程夭夭;管理员账号还会把这台 Mac 注册为可远程控制的桌面主机。只有「作为服务器运行」会启动这台 Mac 的服务,并使用服务器上的 Hermes。客户端不需要安装 Hermes。',
|
|
|
+ detail:'「登录远程」用夭夭服务器的地址和账号密码登录另一台电脑上的夭夭:本机不运行 Web 服务,窗口直接使用远程夭夭;管理员账号还会把这台 Mac 注册为可远程控制的电脑。只有「作为服务器运行」会启动这台 Mac 的服务,并使用服务器上的 Hermes。客户端不需要安装 Hermes。',
|
|
|
buttons:['连接服务器(客户端)','作为服务器运行'],defaultId:0,cancelId:0,checkboxLabel:'记住选择,之后启动不再询问',checkboxChecked:false,noLink:true})
|
|
|
const mode=choice.response===0?'remote':'local'
|
|
|
if(choice.checkboxChecked)await preferences.setStartupChoice(mode).catch(error=>log(error.message))
|
|
|
@@ -461,8 +483,9 @@ else {
|
|
|
{label:'更换服务器…',click:openRemoteLogin},{type:'separator'},
|
|
|
{id:'desktop-host-ask',label:'启动时询问运行模式',type:'checkbox',checked:preferences.value.startupChoice==='ask',
|
|
|
click:item=>{void preferences.setStartupChoice(item.checked?'ask':remoteMode?'remote':'local').catch(async error=>{item.checked=preferences.value.startupChoice==='ask';await appDialog({type:'error',message:'无法保存启动偏好',detail:error.message})})}}]},
|
|
|
- {label:'桌面主机',submenu:[{id:'desktop-host-status',label:'未配置桌面主机',enabled:false},{type:'separator'},
|
|
|
- {id:'desktop-host-import',label:'导入主机配置…',click:importDesktopHost},
|
|
|
+ {label:'电脑',submenu:[{id:'desktop-host-status',label:'未配置电脑',enabled:false},{type:'separator'},
|
|
|
+ {id:'desktop-host-authorize',label:'重新授权…',click:openRemoteLogin},
|
|
|
+ {id:'desktop-host-import',label:'导入电脑配置…',click:importDesktopHost},
|
|
|
{id:'desktop-host-reconnect',label:'重新连接',click:()=>hostAction(()=>hostManager.start())},
|
|
|
{id:'desktop-host-forget',label:'断开并忘记配置',click:()=>hostAction(()=>hostManager.forget())}]},
|
|
|
{ role: 'editMenu', label: '编辑' }, { role: 'viewMenu', label: '显示' }, { role: 'windowMenu', label: '窗口' },
|