diff --git a/server/app/controller/host.js b/server/app/controller/host.js index f318c44..4a7fc47 100644 --- a/server/app/controller/host.js +++ b/server/app/controller/host.js @@ -4,17 +4,13 @@ async function getHostList({ res }) { // console.log('get-host-list') let data = await readHostList() data?.sort((a, b) => Number(b.index || 0) - Number(a.index || 0)) - data = data.map((item) => { - const { username, port, authType, _id: id } = item + for (const item of data) { + let { username, port, authType, _id: id, credential } = item + if (credential) credential = await AESDecryptSync(credential) + // console.log(credential) const isConfig = Boolean(username && port && (item[authType])) - return { - ...item, - id, - isConfig, - password: '', - privateKey: '' - } - }) + Object.assign(item, { id, isConfig, password: '', privateKey: '', credential }) + } res.success({ data }) } diff --git a/server/app/socket/sftp.js b/server/app/socket/sftp.js index c78b605..e6e7ac0 100644 --- a/server/app/socket/sftp.js +++ b/server/app/socket/sftp.js @@ -2,7 +2,7 @@ const { Server } = require('socket.io') const SFTPClient = require('ssh2-sftp-client') const rawPath = require('path') const fs = require('fs') -const { readSSHRecord, verifyAuthSync, RSADecryptSync, AESDecryptSync } = require('../utils') +const { readHostList, readSSHRecord, verifyAuthSync, RSADecryptSync, AESDecryptSync } = require('../utils') const { sftpCacheDir } = require('../config') const CryptoJS = require('crypto-js') @@ -212,17 +212,27 @@ module.exports = (httpServer) => { socket.disconnect() return } - const sshRecord = await readSSHRecord() - let loginInfo = sshRecord.find(item => item.host === ip) - if(!sshRecord.some(item => item.host === ip)) return socket.emit('create_fail', `未找到【${ ip }】凭证`) - let { type, host, port, username, randomKey } = loginInfo - // 解密放到try里面,防止报错【公私钥必须配对, 否则需要重新添加服务器密钥】 - randomKey = await AESDecryptSync(randomKey) // 先对称解密key - randomKey = await RSADecryptSync(randomKey) // 再非对称解密key - loginInfo[type] = await AESDecryptSync(loginInfo[type], randomKey) // 对称解密ssh密钥 - consola.info('准备连接Sftp:', host) - const authInfo = { host, port, username, [type]: loginInfo[type] } - sftpClient.connect(authInfo) + + const hostList = await readHostList() + const targetHostInfo = hostList.find(item => item.host === ip) || {} + let { authType, host, port, username } = targetHostInfo + if (!host) return socket.emit('create_fail', `查找【${ ip }】凭证信息失败`) + let authInfo = { host, port, username } + + // 解密放到try里面,防止报错【commonKey必须配对, 否则需要重新添加服务器密钥】 + if (authType === 'credential') { + let credentialId = await AESDecryptSync(targetHostInfo[authType]) + const sshRecordList = await readSSHRecord() + const sshRecord = sshRecordList.find(item => item._id === credentialId) + authInfo.authType = sshRecord.authType + authInfo[authInfo.authType] = await AESDecryptSync(sshRecord[authInfo.authType]) + } + consola.info('准备连接Sftp面板:', host) + targetHostInfo[targetHostInfo.authType] = await AESDecryptSync(targetHostInfo[targetHostInfo.authType]) + + consola.log('连接信息', { username, port, authType }) + sftpClient + .connect(authInfo) .then(() => { consola.success('连接Sftp成功:', host) return sftpClient.list('/') diff --git a/server/app/socket/terminal.js b/server/app/socket/terminal.js index 3e54dd4..aeecf03 100644 --- a/server/app/socket/terminal.js +++ b/server/app/socket/terminal.js @@ -1,6 +1,6 @@ const { Server } = require('socket.io') const { Client: SSHClient } = require('ssh2') -const { readSSHRecord, verifyAuthSync, RSADecryptSync, AESDecryptSync } = require('../utils') +const { readHostList, readSSHRecord, verifyAuthSync, RSADecryptSync, AESDecryptSync } = require('../utils') function createTerminal(socket, sshClient) { sshClient.shell({ term: 'xterm-color' }, (err, stream) => { @@ -49,19 +49,25 @@ module.exports = (httpServer) => { socket.disconnect() return } - const sshRecord = await readSSHRecord() - let loginInfo = sshRecord.find(item => item.host === ip) - if (!sshRecord.some(item => item.host === ip)) return socket.emit('create_fail', `未找到【${ ip }】凭证`) - // :TODO: 不用tempKey加密了,统一使用commonKey加密 - let { type, host, port, username, randomKey } = loginInfo + const hostList = await readHostList() + const targetHostInfo = hostList.find(item => item.host === ip) || {} + let { authType, host, port, username } = targetHostInfo + if (!host) return socket.emit('create_fail', `查找【${ ip }】凭证信息失败`) + let authInfo = { host, port, username } + // 统一使用commonKey解密 try { - // 解密放到try里面,防止报错【公私钥必须配对, 否则需要重新添加服务器密钥】 - randomKey = await AESDecryptSync(randomKey) // 先对称解密key - randomKey = await RSADecryptSync(randomKey) // 再非对称解密key - loginInfo[type] = await AESDecryptSync(loginInfo[type], randomKey) // 对称解密ssh密钥 + // 解密放到try里面,防止报错【commonKey必须配对, 否则需要重新添加服务器密钥】 + if (authType === 'credential') { + let credentialId = await AESDecryptSync(targetHostInfo[authType]) + const sshRecordList = await readSSHRecord() + const sshRecord = sshRecordList.find(item => item._id === credentialId) + authInfo.authType = sshRecord.authType + authInfo[authInfo.authType] = await AESDecryptSync(sshRecord[authInfo.authType]) + } consola.info('准备连接终端:', host) - const authInfo = { host, port, username, [type]: loginInfo[type] } // .replace(/\n/g, '') - // console.log(authInfo) + targetHostInfo[targetHostInfo.authType] = await AESDecryptSync(targetHostInfo[targetHostInfo.authType]) + + consola.log('连接信息', { username, port, authType }) sshClient .on('ready', () => { consola.success('已连接到终端:', host) diff --git a/web/src/utils/index.js b/web/src/utils/index.js index a830fc9..63a202e 100644 --- a/web/src/utils/index.js +++ b/web/src/utils/index.js @@ -1,7 +1,25 @@ +import { reactive } from 'vue' import JSRsaEncrypt from 'jsencrypt' import CryptoJS from 'crypto-js' +export const EventBus = reactive({}) + +// 在组件中触发事件 +EventBus.$emit = (event, data) => { + if (EventBus[event]) { + EventBus[event].forEach(callback => callback(data)) + } +} + +// 在组件中监听事件 +EventBus.$on = (event, callback) => { + if (!EventBus[event]) { + EventBus[event] = [] + } + EventBus[event].push(callback) +} + export const randomStr = (e) =>{ e = e || 16 let str = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678', @@ -97,4 +115,4 @@ export const downloadFile = ({ buffer, name }) => { export const getSuffix = (name = '') => { return String(name).split(/\./).pop() -} \ No newline at end of file +} diff --git a/web/src/views/index.vue b/web/src/views/index.vue index 7aba68c..637ef75 100644 --- a/web/src/views/index.vue +++ b/web/src/views/index.vue @@ -3,7 +3,12 @@
- + @@ -17,7 +22,7 @@ import { ref, onBeforeMount, getCurrentInstance } from 'vue' import AsideBox from '@/components/aside-box.vue' import TopBar from '@/components/top-bar.vue' -const { proxy: { $store } } = getCurrentInstance() +const { proxy: { $store, $route } } = getCurrentInstance() const loading = ref(true) const getMainData = async () => { diff --git a/web/src/views/server/components/host-form.vue b/web/src/views/server/components/host-form.vue index cdcf938..3b98f8b 100644 --- a/web/src/views/server/components/host-form.vue +++ b/web/src/views/server/components/host-form.vue @@ -352,9 +352,11 @@ const handleSave = () => { .then(async () => { let tempKey = randomStr(16) let formData = { ...hostForm } + console.log('formData:', formData) // 加密传输 if (formData.password) formData.password = AESEncrypt(formData.password, tempKey) if (formData.privateKey) formData.privateKey = AESEncrypt(formData.privateKey, tempKey) + if (formData.credential) formData.credential = AESEncrypt(formData.credential, tempKey) formData.tempKey = RSAEncrypt(tempKey) if (props.defaultData) { let { msg } = await $api.updateHost(Object.assign({}, formData, { oldHost: oldHost.value })) diff --git a/web/src/views/terminal/components/info-side.vue b/web/src/views/terminal/components/info-side.vue index c58a68b..a399466 100644 --- a/web/src/views/terminal/components/info-side.vue +++ b/web/src/views/terminal/components/info-side.vue @@ -1,5 +1,5 @@