✨ test plus
This commit is contained in:
parent
1171d6e6cc
commit
1b3b2892d0
@ -3,3 +3,6 @@ DEBUG=1
|
|||||||
|
|
||||||
# 访问IP限制
|
# 访问IP限制
|
||||||
allowedIPs=['127.0.0.1']
|
allowedIPs=['127.0.0.1']
|
||||||
|
|
||||||
|
# 激活PLUS功能的授权码
|
||||||
|
PLUS_KEY=
|
||||||
|
@ -17,6 +17,7 @@ module.exports = {
|
|||||||
notifyConfigDBPath: path.join(process.cwd(),'app/db/notify-config.db'),
|
notifyConfigDBPath: path.join(process.cwd(),'app/db/notify-config.db'),
|
||||||
onekeyDBPath: path.join(process.cwd(),'app/db/onekey.db'),
|
onekeyDBPath: path.join(process.cwd(),'app/db/onekey.db'),
|
||||||
logDBPath: path.join(process.cwd(),'app/db/log.db'),
|
logDBPath: path.join(process.cwd(),'app/db/log.db'),
|
||||||
|
plusDBPath: path.join(process.cwd(),'app/db/plus.db'),
|
||||||
apiPrefix: '/api/v1',
|
apiPrefix: '/api/v1',
|
||||||
logConfig: {
|
logConfig: {
|
||||||
outDir: path.join(process.cwd(),'./app/logs'),
|
outDir: path.join(process.cwd(),'./app/logs'),
|
||||||
|
@ -51,7 +51,7 @@ async function updateHost({ res, request }) {
|
|||||||
hosts,
|
hosts,
|
||||||
id,
|
id,
|
||||||
host: newHost, name: newName, index, oldHost, expired, expiredNotify, group, consoleUrl, remark,
|
host: newHost, name: newName, index, oldHost, expired, expiredNotify, group, consoleUrl, remark,
|
||||||
port, clientPort, username, authType, password, privateKey, credential, command, tempKey
|
port, clientPort, username, authType, password, privateKey, credential, command, tempKey, jumpHosts = []
|
||||||
}
|
}
|
||||||
} = request
|
} = request
|
||||||
let isBatch = Array.isArray(hosts)
|
let isBatch = Array.isArray(hosts)
|
||||||
@ -73,7 +73,6 @@ async function updateHost({ res, request }) {
|
|||||||
target[authType] = await AESEncryptAsync(clearSSHKey)
|
target[authType] = await AESEncryptAsync(clearSSHKey)
|
||||||
// console.log(`${ authType }__commonKey加密存储: `, target[authType])
|
// console.log(`${ authType }__commonKey加密存储: `, target[authType])
|
||||||
}
|
}
|
||||||
delete target._id
|
|
||||||
delete target.monitorData
|
delete target.monitorData
|
||||||
delete target.tempKey
|
delete target.tempKey
|
||||||
Object.assign(oldRecord, target)
|
Object.assign(oldRecord, target)
|
||||||
@ -85,7 +84,7 @@ async function updateHost({ res, request }) {
|
|||||||
|
|
||||||
let updateRecord = {
|
let updateRecord = {
|
||||||
name: newName, host: newHost, index, expired, expiredNotify, group, consoleUrl, remark,
|
name: newName, host: newHost, index, expired, expiredNotify, group, consoleUrl, remark,
|
||||||
port, clientPort, username, authType, password, privateKey, credential, command
|
port, clientPort, username, authType, password, privateKey, credential, command, jumpHosts
|
||||||
}
|
}
|
||||||
|
|
||||||
let oldRecord = await hostListDB.findOneAsync({ _id: id })
|
let oldRecord = await hostListDB.findOneAsync({ _id: id })
|
||||||
|
@ -5,9 +5,10 @@ const QRCode = require('qrcode')
|
|||||||
const { sendNoticeAsync } = require('../utils/notify')
|
const { sendNoticeAsync } = require('../utils/notify')
|
||||||
const { RSADecryptAsync, AESEncryptAsync, SHA1Encrypt } = require('../utils/encrypt')
|
const { RSADecryptAsync, AESEncryptAsync, SHA1Encrypt } = require('../utils/encrypt')
|
||||||
const { getNetIPInfo } = require('../utils/tools')
|
const { getNetIPInfo } = require('../utils/tools')
|
||||||
const { KeyDB, LogDB } = require('../utils/db-class')
|
const { KeyDB, LogDB, PlusDB } = require('../utils/db-class')
|
||||||
const keyDB = new KeyDB().getInstance()
|
const keyDB = new KeyDB().getInstance()
|
||||||
const logDB = new LogDB().getInstance()
|
const logDB = new LogDB().getInstance()
|
||||||
|
const plusDB = new PlusDB().getInstance()
|
||||||
|
|
||||||
const getpublicKey = async ({ res }) => {
|
const getpublicKey = async ({ res }) => {
|
||||||
let { publicKey: data } = await keyDB.findOneAsync({})
|
let { publicKey: data } = await keyDB.findOneAsync({})
|
||||||
@ -164,6 +165,11 @@ const disableMFA2 = async ({ res }) => {
|
|||||||
res.success({ msg: 'success' })
|
res.success({ msg: 'success' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getPlusInfo = async ({ res }) => {
|
||||||
|
const data = await plusDB.findOneAsync({})
|
||||||
|
res.success({ data, msg: 'success' })
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
login,
|
login,
|
||||||
getpublicKey,
|
getpublicKey,
|
||||||
@ -172,5 +178,6 @@ module.exports = {
|
|||||||
getMFA2Status,
|
getMFA2Status,
|
||||||
getMFA2Code,
|
getMFA2Code,
|
||||||
enableMFA2,
|
enableMFA2,
|
||||||
disableMFA2
|
disableMFA2,
|
||||||
|
getPlusInfo
|
||||||
}
|
}
|
||||||
|
44
server/app/encrypt-file.js
Normal file
44
server/app/encrypt-file.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const fs = require('fs-extra')
|
||||||
|
const path = require('path')
|
||||||
|
const CryptoJS = require('crypto-js')
|
||||||
|
require('dotenv').config()
|
||||||
|
console.log(process.env.PLUS_DECRYPT_KEY)
|
||||||
|
|
||||||
|
async function encryptPlusClearFiles(dir) {
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(dir)
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const fullPath = path.join(dir, file)
|
||||||
|
const stat = await fs.stat(fullPath)
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
await encryptPlusClearFiles(fullPath)
|
||||||
|
} else if (file === 'plus-clear.js') {
|
||||||
|
const content = await fs.readFile(fullPath, 'utf-8')
|
||||||
|
|
||||||
|
// global.PLUS_DECRYPT_KEY
|
||||||
|
const encryptedContent = CryptoJS.AES.encrypt(content, process.env.PLUS_DECRYPT_KEY).toString()
|
||||||
|
|
||||||
|
const newPath = path.join(path.dirname(fullPath), 'plus.js')
|
||||||
|
|
||||||
|
await fs.writeFile(newPath, encryptedContent)
|
||||||
|
|
||||||
|
console.log(`已加密文件: ${fullPath}`)
|
||||||
|
console.log(`生成加密文件: ${newPath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加密过程出错:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const appDir = path.join(__dirname)
|
||||||
|
console.log(appDir)
|
||||||
|
// encryptPlusClearFiles(appDir)
|
||||||
|
// .then(() => {
|
||||||
|
// console.log('加密完成!')
|
||||||
|
// })
|
||||||
|
// .catch(error => {
|
||||||
|
// console.error('程序执行出错:', error)
|
||||||
|
// })
|
@ -1,8 +1,7 @@
|
|||||||
const consola = require('consola')
|
|
||||||
global.consola = consola
|
|
||||||
const { httpServer } = require('./server')
|
const { httpServer } = require('./server')
|
||||||
const initDB = require('./db')
|
const initDB = require('./db')
|
||||||
const scheduleJob = require('./schedule')
|
const scheduleJob = require('./schedule')
|
||||||
|
require(process.env.NODE_ENV === 'dev' ? './utils/plus-clear' : './utils/plus')()
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await initDB()
|
await initDB()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const { getSSHList, addSSH, updateSSH, removeSSH, getCommand } = require('../controller/ssh')
|
const { getSSHList, addSSH, updateSSH, removeSSH, getCommand } = require('../controller/ssh')
|
||||||
const { getHostList, addHost, updateHost, removeHost, importHost } = require('../controller/host')
|
const { getHostList, addHost, updateHost, removeHost, importHost } = require('../controller/host')
|
||||||
const { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2 } = require('../controller/user')
|
const { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2, getPlusInfo } = require('../controller/user')
|
||||||
const { getNotifyConfig, updateNotifyConfig, getNotifyList, updateNotifyList } = require('../controller/notify')
|
const { getNotifyConfig, updateNotifyConfig, getNotifyList, updateNotifyList } = require('../controller/notify')
|
||||||
const { getGroupList, addGroupList, updateGroupList, removeGroup } = require('../controller/group')
|
const { getGroupList, addGroupList, updateGroupList, removeGroup } = require('../controller/group')
|
||||||
const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript } = require('../controller/scripts')
|
const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript } = require('../controller/scripts')
|
||||||
@ -101,6 +101,11 @@ const user = [
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
path: '/mfa2-disable',
|
path: '/mfa2-disable',
|
||||||
controller: disableMFA2
|
controller: disableMFA2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
path: '/plus-info',
|
||||||
|
controller: getPlusInfo
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const notify = [
|
const notify = [
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
const schedule = require('node-schedule')
|
|
||||||
const { sendNoticeAsync } = require('../utils/notify')
|
|
||||||
const { formatTimestamp } = require('../utils/tools')
|
|
||||||
const { HostListDB } = require('../utils/db-class')
|
|
||||||
const hostListDB = new HostListDB().getInstance()
|
|
||||||
|
|
||||||
const expiredNotifyJob = async () => {
|
|
||||||
consola.info('=====开始检测服务器到期时间=====', new Date())
|
|
||||||
const hostList = await hostListDB.findAsync({})
|
|
||||||
for (const item of hostList) {
|
|
||||||
if (!item.expiredNotify) continue
|
|
||||||
const { host, name, expired, consoleUrl } = item
|
|
||||||
const restDay = Number(((expired - Date.now()) / (1000 * 60 * 60 * 24)).toFixed(1))
|
|
||||||
console.log(Date.now(), restDay)
|
|
||||||
let title = '服务器到期提醒'
|
|
||||||
let content = `别名: ${ name }\nIP: ${ host }\n到期时间:${ formatTimestamp(expired, 'week') }\n控制台: ${ consoleUrl || '未填写' }`
|
|
||||||
if (0 <= restDay && restDay <= 1) {
|
|
||||||
let temp = '有服务器将在一天后到期,请关注\n'
|
|
||||||
sendNoticeAsync('host_expired', title, temp + content)
|
|
||||||
} else if (3 <= restDay && restDay < 4) {
|
|
||||||
let temp = '有服务器将在三天后到期,请关注\n'
|
|
||||||
sendNoticeAsync('host_expired', title, temp + content)
|
|
||||||
} else if (7 <= restDay && restDay < 8) {
|
|
||||||
let temp = '有服务器将在七天后到期,请关注\n'
|
|
||||||
sendNoticeAsync('host_expired', title, temp + content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = () => {
|
|
||||||
// 每天中午12点执行一次。
|
|
||||||
schedule.scheduleJob('0 0 12 1/1 * ?', expiredNotifyJob)
|
|
||||||
}
|
|
@ -1,5 +1,32 @@
|
|||||||
const expiredNotify = require('./expired-notify')
|
const schedule = require('node-schedule')
|
||||||
|
const { sendNoticeAsync } = require('../utils/notify')
|
||||||
|
const { formatTimestamp } = require('../utils/tools')
|
||||||
|
const { HostListDB } = require('../utils/db-class')
|
||||||
|
const hostListDB = new HostListDB().getInstance()
|
||||||
|
|
||||||
|
const expiredNotifyJob = async () => {
|
||||||
|
consola.info('=====开始检测服务器到期时间=====', new Date())
|
||||||
|
const hostList = await hostListDB.findAsync({})
|
||||||
|
for (const item of hostList) {
|
||||||
|
if (!item.expiredNotify) continue
|
||||||
|
const { host, name, expired, consoleUrl } = item
|
||||||
|
const restDay = Number(((expired - Date.now()) / (1000 * 60 * 60 * 24)).toFixed(1))
|
||||||
|
console.log(Date.now(), restDay)
|
||||||
|
let title = '服务器到期提醒'
|
||||||
|
let content = `别名: ${ name }\nIP: ${ host }\n到期时间:${ formatTimestamp(expired, 'week') }\n控制台: ${ consoleUrl || '未填写' }`
|
||||||
|
if (0 <= restDay && restDay <= 1) {
|
||||||
|
let temp = '有服务器将在一天后到期,请关注\n'
|
||||||
|
sendNoticeAsync('host_expired', title, temp + content)
|
||||||
|
} else if (3 <= restDay && restDay < 4) {
|
||||||
|
let temp = '有服务器将在三天后到期,请关注\n'
|
||||||
|
sendNoticeAsync('host_expired', title, temp + content)
|
||||||
|
} else if (7 <= restDay && restDay < 8) {
|
||||||
|
let temp = '有服务器将在七天后到期,请关注\n'
|
||||||
|
sendNoticeAsync('host_expired', title, temp + content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
expiredNotify()
|
schedule.scheduleJob('0 0 12 1/1 * ?', expiredNotifyJob)
|
||||||
}
|
}
|
||||||
|
0
server/app/socket/plus.js
Normal file
0
server/app/socket/plus.js
Normal file
@ -1,16 +1,15 @@
|
|||||||
const { Server } = require('socket.io')
|
const { Server } = require('socket.io')
|
||||||
const { Client: SSHClient } = require('ssh2')
|
const { Client: SSHClient } = require('ssh2')
|
||||||
const { verifyAuthSync } = require('../utils/verify-auth')
|
const { verifyAuthSync } = require('../utils/verify-auth')
|
||||||
const { AESDecryptAsync } = require('../utils/encrypt')
|
|
||||||
const { sendNoticeAsync } = require('../utils/notify')
|
const { sendNoticeAsync } = require('../utils/notify')
|
||||||
const { isAllowedIp, ping } = require('../utils/tools')
|
const { isAllowedIp, ping } = require('../utils/tools')
|
||||||
const { HostListDB, CredentialsDB } = require('../utils/db-class')
|
const { HostListDB } = require('../utils/db-class')
|
||||||
|
const { getConnectionOptions, connectByJumpHosts } = require(process.env.NODE_ENV === 'dev' ? './plus-clear' : './plus')
|
||||||
const hostListDB = new HostListDB().getInstance()
|
const hostListDB = new HostListDB().getInstance()
|
||||||
const credentialsDB = new CredentialsDB().getInstance()
|
|
||||||
|
|
||||||
function createInteractiveShell(socket, sshClient) {
|
function createInteractiveShell(socket, targetSSHClient) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
sshClient.shell({ term: 'xterm-color' }, (err, stream) => {
|
targetSSHClient.shell({ term: 'xterm-color' }, (err, stream) => {
|
||||||
resolve(stream)
|
resolve(stream)
|
||||||
if (err) return socket.emit('output', err.toString())
|
if (err) return socket.emit('output', err.toString())
|
||||||
// 终端输出
|
// 终端输出
|
||||||
@ -20,70 +19,38 @@ function createInteractiveShell(socket, sshClient) {
|
|||||||
})
|
})
|
||||||
.on('close', () => {
|
.on('close', () => {
|
||||||
consola.info('交互终端已关闭')
|
consola.info('交互终端已关闭')
|
||||||
sshClient.end()
|
targetSSHClient.end()
|
||||||
})
|
})
|
||||||
socket.emit('connect_shell_success') // 已连接终端,web端可以执行指令了
|
socket.emit('connect_shell_success') // 已连接终端,web端可以执行指令了
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// function execShell(sshClient, command = '', callback) {
|
async function createTerminal(hostId, socket, targetSSHClient) {
|
||||||
// if (!command) return
|
|
||||||
// let result = ''
|
|
||||||
// sshClient.exec(`source ~/.bashrc && ${ command }`, (err, stream) => {
|
|
||||||
// if (err) return callback(err.toString())
|
|
||||||
// stream
|
|
||||||
// .on('data', (data) => {
|
|
||||||
// result += data.toString()
|
|
||||||
// })
|
|
||||||
// .stderr
|
|
||||||
// .on('data', (data) => {
|
|
||||||
// result += data.toString()
|
|
||||||
// })
|
|
||||||
// .on('close', () => {
|
|
||||||
// consola.info('一次性指令执行完成:', command)
|
|
||||||
// callback(result)
|
|
||||||
// })
|
|
||||||
// .on('error', (error) => {
|
|
||||||
// console.log('Error:', error.toString())
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
async function createTerminal(hostId, socket, sshClient) {
|
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const hostList = await hostListDB.findAsync({})
|
const targetHostInfo = await hostListDB.findOneAsync({ _id: hostId })
|
||||||
const targetHostInfo = hostList.find(item => item._id === hostId) || {}
|
if (!targetHostInfo) return socket.emit('create_fail', `查找hostId【${ hostId }】凭证信息失败`)
|
||||||
let { authType, host, port, username, name } = targetHostInfo
|
let { authType, host, port, username, name, jumpHosts } = targetHostInfo
|
||||||
if (!host) return socket.emit('create_fail', `查找hostId【${ hostId }】凭证信息失败`)
|
|
||||||
let authInfo = { host, port, username }
|
|
||||||
// 统一使用commonKey解密
|
|
||||||
try {
|
try {
|
||||||
// 解密放到try里面,防止报错【commonKey必须配对, 否则需要重新添加服务器密钥】
|
let { authInfo: targetConnectionOptions } = await getConnectionOptions(hostId)
|
||||||
if (authType === 'credential') {
|
let jumpHostResult = await connectByJumpHosts(jumpHosts, targetConnectionOptions.host, targetConnectionOptions.port, socket)
|
||||||
let credentialId = await AESDecryptAsync(targetHostInfo[authType])
|
if (jumpHostResult) {
|
||||||
const sshRecord = await credentialsDB.findOneAsync({ _id: credentialId })
|
targetConnectionOptions.sock = jumpHostResult.sock
|
||||||
authInfo.authType = sshRecord.authType
|
|
||||||
authInfo[authInfo.authType] = await AESDecryptAsync(sshRecord[authInfo.authType])
|
|
||||||
} else {
|
|
||||||
authInfo[authType] = await AESDecryptAsync(targetHostInfo[authType])
|
|
||||||
}
|
}
|
||||||
consola.info('准备连接终端:', host)
|
|
||||||
// targetHostInfo[targetHostInfo.authType] = await AESDecryptAsync(targetHostInfo[targetHostInfo.authType])
|
socket.emit('terminal_print_info', `准备连接目标终端: ${ name } - ${ host }`)
|
||||||
|
socket.emit('terminal_print_info', `连接信息: ssh ${ username }@${ host } -p ${ port } -> ${ authType }`)
|
||||||
|
|
||||||
|
consola.info('准备连接目标终端:', host)
|
||||||
consola.log('连接信息', { username, port, authType })
|
consola.log('连接信息', { username, port, authType })
|
||||||
sshClient
|
targetSSHClient
|
||||||
.on('ready', async() => {
|
.on('ready', async() => {
|
||||||
sendNoticeAsync('host_login', '终端登录', `别名: ${ name } \n IP:${ host } \n 端口:${ port } \n 状态: 登录成功`)
|
sendNoticeAsync('host_login', '终端登录', `别名: ${ name } \n IP:${ host } \n 端口:${ port } \n 状态: 登录成功`)
|
||||||
|
socket.emit('terminal_print_info', `终端连接成功: ${ name } - ${ host }`)
|
||||||
consola.success('终端连接成功:', host)
|
consola.success('终端连接成功:', host)
|
||||||
socket.emit('connect_terminal_success', `终端连接成功:${ host }`)
|
socket.emit('connect_terminal_success', `终端连接成功:${ host }`)
|
||||||
let stream = await createInteractiveShell(socket, sshClient)
|
let stream = await createInteractiveShell(socket, targetSSHClient)
|
||||||
resolve(stream)
|
resolve(stream)
|
||||||
// execShell(sshClient, 'history', (data) => {
|
|
||||||
// data = data.split('\n').filter(item => item)
|
|
||||||
// console.log(data)
|
|
||||||
// socket.emit('terminal_command_history', data)
|
|
||||||
// })
|
|
||||||
})
|
})
|
||||||
.on('close', () => {
|
.on('close', () => {
|
||||||
consola.info('终端连接断开close: ', host)
|
consola.info('终端连接断开close: ', host)
|
||||||
@ -96,7 +63,7 @@ async function createTerminal(hostId, socket, sshClient) {
|
|||||||
socket.emit('connect_fail', err.message)
|
socket.emit('connect_fail', err.message)
|
||||||
})
|
})
|
||||||
.connect({
|
.connect({
|
||||||
...authInfo
|
...targetConnectionOptions
|
||||||
// debug: (info) => console.log(info)
|
// debug: (info) => console.log(info)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -123,7 +90,7 @@ module.exports = (httpServer) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
consola.success('terminal websocket 已连接')
|
consola.success('terminal websocket 已连接')
|
||||||
let sshClient = null
|
let targetSSHClient = null
|
||||||
socket.on('create', async ({ hostId, token }) => {
|
socket.on('create', async ({ hostId, token }) => {
|
||||||
const { code } = await verifyAuthSync(token, requestIP)
|
const { code } = await verifyAuthSync(token, requestIP)
|
||||||
if (code !== 1) {
|
if (code !== 1) {
|
||||||
@ -131,16 +98,10 @@ module.exports = (httpServer) => {
|
|||||||
socket.disconnect()
|
socket.disconnect()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sshClient = new SSHClient()
|
targetSSHClient = new SSHClient()
|
||||||
|
|
||||||
// 尝试手动断开调试,再次连接后终端输出内容为4份相同的输出,导致异常
|
|
||||||
// setTimeout(() => {
|
|
||||||
// sshClient.end()
|
|
||||||
// }, 3000)
|
|
||||||
let stream = null
|
let stream = null
|
||||||
|
|
||||||
function listenerInput(key) {
|
function listenerInput(key) {
|
||||||
if (sshClient._sock.writable === false) return consola.info('终端连接已关闭,禁止输入')
|
if (targetSSHClient._sock.writable === false) return consola.info('终端连接已关闭,禁止输入')
|
||||||
stream && stream.write(key)
|
stream && stream.write(key)
|
||||||
}
|
}
|
||||||
function resizeShell({ rows, cols }) {
|
function resizeShell({ rows, cols }) {
|
||||||
@ -155,20 +116,20 @@ module.exports = (httpServer) => {
|
|||||||
consola.info('重连终端: ', hostId)
|
consola.info('重连终端: ', hostId)
|
||||||
socket.off('input', listenerInput) // 取消监听,重新注册监听,操作新的stream
|
socket.off('input', listenerInput) // 取消监听,重新注册监听,操作新的stream
|
||||||
socket.off('resize', resizeShell)
|
socket.off('resize', resizeShell)
|
||||||
sshClient?.end()
|
targetSSHClient?.end()
|
||||||
sshClient?.destroy()
|
targetSSHClient?.destroy()
|
||||||
sshClient = null
|
targetSSHClient = null
|
||||||
stream = null
|
stream = null
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
// 初始化新的SSH客户端对象
|
// 初始化新的SSH客户端对象
|
||||||
sshClient = new SSHClient()
|
targetSSHClient = new SSHClient()
|
||||||
stream = await createTerminal(hostId, socket, sshClient)
|
stream = await createTerminal(hostId, socket, targetSSHClient)
|
||||||
socket.emit('reconnect_terminal_success')
|
socket.emit('reconnect_terminal_success')
|
||||||
socket.on('input', listenerInput)
|
socket.on('input', listenerInput)
|
||||||
socket.on('resize', resizeShell)
|
socket.on('resize', resizeShell)
|
||||||
}, 3000)
|
}, 3000)
|
||||||
})
|
})
|
||||||
stream = await createTerminal(hostId, socket, sshClient)
|
stream = await createTerminal(hostId, socket, targetSSHClient)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('get_ping',async (ip) => {
|
socket.on('get_ping',async (ip) => {
|
||||||
|
@ -8,7 +8,8 @@ const {
|
|||||||
groupConfDBPath,
|
groupConfDBPath,
|
||||||
scriptsDBPath,
|
scriptsDBPath,
|
||||||
onekeyDBPath,
|
onekeyDBPath,
|
||||||
logDBPath
|
logDBPath,
|
||||||
|
plusDBPath
|
||||||
} = require('../config')
|
} = require('../config')
|
||||||
|
|
||||||
module.exports.KeyDB = class KeyDB {
|
module.exports.KeyDB = class KeyDB {
|
||||||
@ -118,3 +119,14 @@ module.exports.LogDB = class LogDB {
|
|||||||
return LogDB.instance
|
return LogDB.instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.PlusDB = class PlusDB {
|
||||||
|
constructor() {
|
||||||
|
if (!PlusDB.instance) {
|
||||||
|
PlusDB.instance = new Datastore({ filename: plusDBPath, autoload: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getInstance() {
|
||||||
|
return PlusDB.instance
|
||||||
|
}
|
||||||
|
}
|
0
server/app/utils/plus.js
Normal file
0
server/app/utils/plus.js
Normal file
@ -89,6 +89,35 @@ const getNetIPInfo = async (searchIp = '') => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLocalNetIP = async () => {
|
||||||
|
try {
|
||||||
|
let ipUrls = [
|
||||||
|
'http://whois.pconline.com.cn/ipJson.jsp?json=true',
|
||||||
|
'https://www.ip.cn/api/index?ip=&type=0',
|
||||||
|
'https://freeipapi.com/api/json'
|
||||||
|
]
|
||||||
|
let result = await Promise.allSettled(ipUrls.map(url => axios.get(url)))
|
||||||
|
let [pconline, ipCN, freeipapi] = result
|
||||||
|
if (pconline.status === 'fulfilled') {
|
||||||
|
let ip = pconline.value?.data?.ip
|
||||||
|
if (ip) return ip
|
||||||
|
}
|
||||||
|
if (ipCN.status === 'fulfilled') {
|
||||||
|
let ip = ipCN.value?.data?.ip
|
||||||
|
consola.log('ipCN:', ip)
|
||||||
|
if (ip) return ip
|
||||||
|
}
|
||||||
|
if (freeipapi.status === 'fulfilled') {
|
||||||
|
let ip = pconline.value?.data?.ipAddress
|
||||||
|
if (ip) return ip
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
} catch (error) {
|
||||||
|
console.error('getIpInfo Error: ', error?.message || error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isLocalIP(ip) {
|
function isLocalIP(ip) {
|
||||||
// Check if IPv4 or IPv6 address
|
// Check if IPv4 or IPv6 address
|
||||||
const isIPv4 = net.isIPv4(ip)
|
const isIPv4 = net.isIPv4(ip)
|
||||||
@ -159,7 +188,7 @@ const isIP = (ip = '') => {
|
|||||||
return isIPv4.test(ip) || isIPv6.test(ip)
|
return isIPv4.test(ip) || isIPv6.test(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
const randomStr = (len) =>{
|
const randomStr = (len) => {
|
||||||
len = len || 16
|
len = len || 16
|
||||||
let str = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678',
|
let str = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678',
|
||||||
a = str.length,
|
a = str.length,
|
||||||
@ -178,7 +207,7 @@ const getUTCDate = (num = 8) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formatTimestamp = (timestamp = Date.now(), format = 'time') => {
|
const formatTimestamp = (timestamp = Date.now(), format = 'time') => {
|
||||||
if (typeof(timestamp) !== 'number') return '--'
|
if (typeof (timestamp) !== 'number') return '--'
|
||||||
let date = new Date(timestamp)
|
let date = new Date(timestamp)
|
||||||
let padZero = (num) => String(num).padStart(2, '0')
|
let padZero = (num) => String(num).padStart(2, '0')
|
||||||
let year = date.getFullYear()
|
let year = date.getFullYear()
|
||||||
@ -187,7 +216,7 @@ const formatTimestamp = (timestamp = Date.now(), format = 'time') => {
|
|||||||
let hours = padZero(date.getHours())
|
let hours = padZero(date.getHours())
|
||||||
let minute = padZero(date.getMinutes())
|
let minute = padZero(date.getMinutes())
|
||||||
let second = padZero(date.getSeconds())
|
let second = padZero(date.getSeconds())
|
||||||
let weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六' ]
|
let weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||||
let week = weekday[date.getDay()]
|
let week = weekday[date.getDay()]
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 'date':
|
case 'date':
|
||||||
@ -284,6 +313,7 @@ const ping = (ip, timeout = 5000) => {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getNetIPInfo,
|
getNetIPInfo,
|
||||||
|
getLocalNetIP,
|
||||||
throwError,
|
throwError,
|
||||||
isIP,
|
isIP,
|
||||||
randomStr,
|
randomStr,
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
|
const consola = require('consola')
|
||||||
|
global.consola = consola
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
require('./app/main.js')
|
require('./app/main.js')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "1.0.0",
|
"version": "3.0.0",
|
||||||
"description": "easynode-server",
|
"description": "easynode-server",
|
||||||
"bin": "./bin/www",
|
"bin": "./bin/www",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -8,7 +8,8 @@
|
|||||||
"prod": "cross-env EXEC_ENV=production nodemon index.js",
|
"prod": "cross-env EXEC_ENV=production nodemon index.js",
|
||||||
"start": "node ./index.js",
|
"start": "node ./index.js",
|
||||||
"lint": "eslint . --ext .js,.vue",
|
"lint": "eslint . --ext .js,.vue",
|
||||||
"lint:fix": "eslint . --ext .js,.jsx,.cjs,.mjs --fix"
|
"lint:fix": "eslint . --ext .js,.jsx,.cjs,.mjs --fix",
|
||||||
|
"encrypt": "node ./app/encrypt-file.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user