From 079c62b8381a0dc33a68898b7122887d31b59e48 Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Sun, 10 Nov 2024 10:24:09 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=9B=B4=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- CHANGELOG.md | 6 + README.md | 2 - server/app/controller/user.js | 28 +++- server/app/router/routes.js | 7 +- server/app/socket/sftp.js | 10 +- server/app/utils/get-plus.js | 5 +- server/app/utils/plus-server.js | 4 + server/package.json | 2 +- web/package.json | 2 +- web/src/api/index.js | 3 + web/src/assets/discount.png | Bin 0 -> 4354 bytes web/src/components/top-bar.vue | 145 ++++++++++++++---- web/src/views/terminal/components/sftp.vue | 4 +- .../views/terminal/components/terminal.vue | 2 +- 15 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 server/app/utils/plus-server.js create mode 100644 web/src/assets/discount.png diff --git a/.gitignore b/.gitignore index cd65b26..48350ce 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ plan.md .env.local .env-encrypt-key *clear.js -local-script \ No newline at end of file +local-script +版本发布.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f6549a8..f761e8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [3.0.1](https://github.com/chaos-zhu/easynode/releases) (2024-11-18) + +* 修复同IP实例SFTP连接到其他的实例的bug +* 修复一些UI问题 + + ## [3.0.0](https://github.com/chaos-zhu/easynode/releases) (2024-11-09) * 新增跳板机功能,支持选择多台机器跳转 diff --git a/README.md b/README.md index cd57ea8..07f1030 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,9 @@ _✨ 一个多功能Linux服务器WEB终端面板(webSSH&webSFTP) ✨_ docker run -d -p 8082:8082 --restart=always -v /root/easynode/db:/easynode/app/db chaoszhu/easynode ``` 环境变量: -- `PLUS_KEY`: 激活PLUS功能的授权码 - `DEBUG`: 启动debug日志 0:关闭 1:开启, 默认关闭 - `ALLOWED_IPS`: 可以访问服务的IP白名单, 多个使用逗号分隔, 支持填写部分ip前缀, 例如: `-e ALLOWED_IPS=127.0.0.1,196.168` - ## 监控服务安装 - 监控服务用于实时向服务端&web端推送**系统、公网IP、CPU、内存、硬盘、网卡**等基础信息 diff --git a/server/app/controller/user.js b/server/app/controller/user.js index 6a673e4..bda28bd 100644 --- a/server/app/controller/user.js +++ b/server/app/controller/user.js @@ -2,6 +2,8 @@ const jwt = require('jsonwebtoken') const axios = require('axios') const speakeasy = require('speakeasy') const QRCode = require('qrcode') +const version = require('../../package.json').version +const { plusServer1, plusServer2 } = require('../utils/plus-server') const { sendNoticeAsync } = require('../utils/notify') const { RSADecryptAsync, AESEncryptAsync, SHA1Encrypt } = require('../utils/encrypt') const { getNetIPInfo } = require('../utils/tools') @@ -86,7 +88,7 @@ const beforeLoginHandler = async (clientIp, jwtExpires) => { let token = jwt.sign({ date: Date.now() }, commonKey, { expiresIn: jwtExpires }) // 生成token token = await AESEncryptAsync(token) // 对称加密token后再传输给前端 - // 记录客户端登录IP(用于判断是否异地且只保留最近10条) + // 记录客户端登录IP(用于判断是否异地且只保留最近10��) const clientIPInfo = await getNetIPInfo(clientIp) const { ip, country, city } = clientIPInfo || {} consola.info('登录成功:', new Date(), { ip, country, city }) @@ -172,6 +174,27 @@ const getPlusInfo = async ({ res }) => { res.success({ data, msg: 'success' }) } +const getPlusDiscount = async ({ res } = {}) => { + const servers = [plusServer1, plusServer2] + for (const server of servers) { + try { + const url = `${ server }/api/announcement/public?version=${ version }` + const response = await fetch(url) + if (!response.ok) { + throw new Error(`HTTP error! status: ${ response.status }`) + } + const data = await response.json() + return res.success({ data, msg: 'success' }) + } catch (error) { + if (server === servers[servers.length - 1]) { + consola.error('All servers failed:', error.message) + return res.success({ discount: false }) + } + continue + } + } +} + module.exports = { login, getpublicKey, @@ -181,5 +204,6 @@ module.exports = { getMFA2Code, enableMFA2, disableMFA2, - getPlusInfo + getPlusInfo, + getPlusDiscount } diff --git a/server/app/router/routes.js b/server/app/router/routes.js index 042f34d..e55a906 100644 --- a/server/app/router/routes.js +++ b/server/app/router/routes.js @@ -1,6 +1,6 @@ const { getSSHList, addSSH, updateSSH, removeSSH, getCommand, decryptPrivateKey } = require('../controller/ssh') const { getHostList, addHost, updateHost, batchUpdateHost, removeHost, importHost } = require('../controller/host') -const { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2, getPlusInfo } = require('../controller/user') +const { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2, getPlusInfo, getPlusDiscount } = require('../controller/user') const { getNotifyConfig, updateNotifyConfig, getNotifyList, updateNotifyList } = require('../controller/notify') const { getGroupList, addGroupList, updateGroupList, removeGroup } = require('../controller/group') const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript, batchRemoveScript, importScript } = require('../controller/scripts') @@ -116,6 +116,11 @@ const user = [ method: 'get', path: '/plus-info', controller: getPlusInfo + }, + { + method: 'get', + path: '/plus-discount', + controller: getPlusDiscount } ] const notify = [ diff --git a/server/app/socket/sftp.js b/server/app/socket/sftp.js index 444c09f..2c01fc8 100644 --- a/server/app/socket/sftp.js +++ b/server/app/socket/sftp.js @@ -224,18 +224,18 @@ module.exports = (httpServer) => { let sftpClient = new SFTPClient() consola.success('terminal websocket 已连接') - socket.on('create', async ({ host: ip, token }) => { + socket.on('create', async ({ hostId, token }) => { const { code } = await verifyAuthSync(token, requestIP) + consola.log('code:', code) if (code !== 1) { socket.emit('token_verify_fail') socket.disconnect() return } - - const hostList = await hostListDB.findAsync({}) - const targetHostInfo = hostList.find(item => item.host === ip) || {} + const targetHostInfo = await hostListDB.findOneAsync({ _id: hostId }) + if (!targetHostInfo) throw new Error(`Host with ID ${ hostId } not found`) let { authType, host, port, username } = targetHostInfo - if (!host) return socket.emit('create_fail', `查找【${ ip }】凭证信息失败`) + if (!host) return socket.emit('create_fail', `查找id【${ hostId }】凭证信息失败`) let authInfo = { host, port, username } // 解密放到try里面,防止报错【commonKey必须配对, 否则需要重新添加服务器密钥】 diff --git a/server/app/utils/get-plus.js b/server/app/utils/get-plus.js index 70d6093..5184915 100644 --- a/server/app/utils/get-plus.js +++ b/server/app/utils/get-plus.js @@ -2,6 +2,7 @@ const schedule = require('node-schedule') const { getLocalNetIP } = require('./tools') const { AESEncryptAsync } = require('./encrypt') const version = require('../../package.json').version +const { plusServer1, plusServer2 } = require('./plus-server') async function getLicenseInfo() { let key = process.env.PLUS_KEY @@ -28,7 +29,7 @@ async function getLicenseInfo() { let headers = { 'Content-Type': 'application/json' } let timeout = 10000 try { - response = await fetch('https://en1.221022.xyz/api/licenses/activate', { + response = await fetch(plusServer1 + '/api/licenses/activate', { method, headers, body, @@ -41,7 +42,7 @@ async function getLicenseInfo() { } catch (error) { consola.log('retry to activate plus by backup server') - response = await fetch('https://en2.221022.xyz/api/licenses/activate', { + response = await fetch(plusServer2 + '/api/licenses/activate', { method, headers, body, diff --git a/server/app/utils/plus-server.js b/server/app/utils/plus-server.js new file mode 100644 index 0000000..7f28516 --- /dev/null +++ b/server/app/utils/plus-server.js @@ -0,0 +1,4 @@ +module.exports = { + plusServer1: 'https://en1.221022.xyz', + plusServer2: 'https://en2.221022.xyz' +} diff --git a/server/package.json b/server/package.json index 02a4726..3181cd8 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "server", - "version": "3.0.0", + "version": "3.0.1", "description": "easynode-server", "bin": "./bin/www", "scripts": { diff --git a/web/package.json b/web/package.json index fa33191..07568a8 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "3.0.0", + "version": "3.0.1", "description": "easynode-web", "private": true, "scripts": { diff --git a/web/src/api/index.js b/web/src/api/index.js index 5f4c8c3..2c15ee9 100644 --- a/web/src/api/index.js +++ b/web/src/api/index.js @@ -22,6 +22,9 @@ export default { getPlusInfo() { return axios({ url: '/plus-info', method: 'get' }) }, + getPlusDiscount() { + return axios({ url: '/plus-discount', method: 'get' }) + }, getCommand(hostId) { return axios({ url: '/command', method: 'get', params: { hostId } }) }, diff --git a/web/src/assets/discount.png b/web/src/assets/discount.png new file mode 100644 index 0000000000000000000000000000000000000000..5e24efed21914d476d53e6a201ae24e11766f62a GIT binary patch literal 4354 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 literal 0 HcmV?d00001 diff --git a/web/src/components/top-bar.vue b/web/src/components/top-bar.vue index e721eb6..9635c88 100644 --- a/web/src/components/top-bar.vue +++ b/web/src/components/top-bar.vue @@ -20,7 +20,7 @@ link @click="visible = true" > - 关于 {{ isNew ? `(新版本可用)` : '' }} + 版本更新 {{ isNew ? `(新版本可用)` : '' }} @@ -40,12 +40,20 @@ @@ -122,15 +136,16 @@
-

EasyNode

+

当前版本: {{ currentVersion }} (最新)

-

Error:版本更新检测失败(版本检测API需要外网环境)

+

Error:版本更新检测失败(版本检测API需要外网环境),请手动访问GitHub查看

新版本可用: {{ latestVersion }} -> https://github.com/chaos-zhu/easynode/releases

- 更新日志:https://github.com/chaos-zhu/easynode/blob/main/CHANGELOG.md

- tg更新通知:https://t.me/easynode_notify + TG更新通知频道:https://t.me/easynode_notify

PLUS说明:
@@ -156,11 +171,12 @@        为了项目的可持续发展,从3.0.0版本开始推出了PLUS版本,具体特性鼠标悬浮右上角PLUS图标查看,后续特性功能开发也会优先在PLUS版本中实现,但即使不升级到PLUS,也不会影响到EasyNode的基础功能使用【注意: 暂不支持纯内网用户激活PLUS功能】。
        - 为了感谢前期赞赏过的用户, 在PLUS功能正式发布前,所有进行过赞赏的用户,无论金额大小,均可联系作者TG: @chaoszhu 凭打赏记录获取永久PLUS授权码。 + 为了感谢前期赞赏过的用户, 在PLUS功能正式发布前,所有进行过赞赏的用户,无论金额大小,均可联系作者TG: @chaoszhu 凭打赏记录免费获取永久PLUS授权码。

- @@ -181,18 +197,20 @@ \ No newline at end of file diff --git a/web/src/views/terminal/components/sftp.vue b/web/src/views/terminal/components/sftp.vue index 1e880a5..6e82a2d 100644 --- a/web/src/views/terminal/components/sftp.vue +++ b/web/src/views/terminal/components/sftp.vue @@ -168,7 +168,7 @@ import unknowIcon from '@/assets/image/system/unknow.png' const { io } = socketIo const props = defineProps({ - host: { + hostId: { required: true, type: String } @@ -270,7 +270,7 @@ const connectSftp = () => { socket.value.on('connect', () => { console.log('/sftp socket已连接:', socket.value.id) listenSftp() - socket.value.emit('create', { host: props.host, token: token.value }) + socket.value.emit('create', { hostId: props.hostId, token: token.value }) socket.value.on('root_ls', (tree) => { let temp = sortDirTree(tree).filter((item) => isDir(item.type)) temp.unshift({ name: '/', type: 'd' }) diff --git a/web/src/views/terminal/components/terminal.vue b/web/src/views/terminal/components/terminal.vue index aad38bd..53e0715 100644 --- a/web/src/views/terminal/components/terminal.vue +++ b/web/src/views/terminal/components/terminal.vue @@ -167,7 +167,7 @@