From d6fd7964b5f5b0de5e58fef4b56233d13555db2e Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Sun, 8 Feb 2026 14:45:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20sftp=E9=BB=98=E8=AE=A4=E5=B8=B8?= =?UTF-8?q?=E7=94=A8=E7=9B=AE=E5=BD=95&=E5=B1=95=E7=A4=BA=E4=BC=98?= =?UTF-8?q?=E5=85=88=E7=BA=A7=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/controller/user.js | 2 +- server/app/socket/sftp-v2.js | 50 ++++++++++++------- server/app/utils/verify-auth.js | 2 +- web/src/views/terminal/components/sftp-v2.vue | 14 ++++-- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/server/app/controller/user.js b/server/app/controller/user.js index bb01ef7..b0e3c34 100644 --- a/server/app/controller/user.js +++ b/server/app/controller/user.js @@ -63,7 +63,7 @@ const login = async (ctx) => { // 登录流程 try { let loginPwd = await RSADecryptAsync(ciphertext) - let { user, pwd, enableMFA2, secret, _id } = await keyDB.findOneAsync({}) + let { user, pwd, enableMFA2, secret } = await keyDB.findOneAsync({}) if (enableMFA2) { const isValid = speakeasy.totp.verify({ secret, encoding: 'base32', token: String(mfa2Token), window: 1 }) console.log('MFA2 verfify:', isValid) diff --git a/server/app/socket/sftp-v2.js b/server/app/socket/sftp-v2.js index 9c679c9..3b102e1 100644 --- a/server/app/socket/sftp-v2.js +++ b/server/app/socket/sftp-v2.js @@ -1656,25 +1656,39 @@ module.exports = (httpServer) => { let isRootUser = true let currentWorkingDir = '/' - try { - rootList = await sftpClient.list('/') - logger.info('获取根目录成功') - } catch (error) { - logger.error('获取根目录失败:', error.message) - logger.info('尝试获取当前目录') - isRootUser = false - + // 如果是 root 用户,直接进入 root 家目录 + if (username === 'root') { try { - // 获取当前工作目录的绝对路径 - currentWorkingDir = await sftpClient.cwd() - logger.info('当前工作目录:', currentWorkingDir) - rootList = await sftpClient.list(currentWorkingDir) - logger.info('获取当前目录成功') - } catch (cwdError) { - logger.warn('获取工作目录失败,使用相对路径:', cwdError.message) - currentWorkingDir = '~' - rootList = await sftpClient.list('./') - logger.info('获取当前目录成功') + currentWorkingDir = '/root' + rootList = await sftpClient.list('/root') + } catch (rootError) { + // 如果 /root 不存在或无权限,降级到根目录 + logger.warn('获取 /root 失败,降级到根目录:', rootError.message) + currentWorkingDir = '/' + rootList = await sftpClient.list('/') + logger.info('root 用户进入根目录成功') + } + } else { + try { + rootList = await sftpClient.list('/') + logger.info('获取根目录成功') + } catch (error) { + logger.error('获取根目录失败:', error.message) + logger.info('尝试获取当前目录') + isRootUser = false + + try { + // 获取当前工作目录的绝对路径 + currentWorkingDir = await sftpClient.cwd() + logger.info('当前工作目录:', currentWorkingDir) + rootList = await sftpClient.list(currentWorkingDir) + logger.info('获取当前目录成功') + } catch (cwdError) { + logger.warn('获取工作目录失败,使用相对路径:', cwdError.message) + currentWorkingDir = '~' + rootList = await sftpClient.list('./') + logger.info('获取当前目录成功') + } } } diff --git a/server/app/utils/verify-auth.js b/server/app/utils/verify-auth.js index af41e3c..12f986d 100644 --- a/server/app/utils/verify-auth.js +++ b/server/app/utils/verify-auth.js @@ -91,7 +91,7 @@ const verifyWsAuthSync = async (socket, next) => { logger.warn('ws终端连接身份验证失败, code:', code) return next(new Error('Authentication Failed')) } - console.log('🤓 ws terminal auth success') + // console.log('🤓 ws terminal auth success') next() } diff --git a/web/src/views/terminal/components/sftp-v2.vue b/web/src/views/terminal/components/sftp-v2.vue index 20faff6..410dca5 100644 --- a/web/src/views/terminal/components/sftp-v2.vue +++ b/web/src/views/terminal/components/sftp-v2.vue @@ -737,10 +737,16 @@ function getRank(item) { const isHidden = item.name.startsWith('.') const isDir = item.type === 'd' const isLink = item.type === 'l' - if (isHidden && isDir) return 0 // hidden dir - if (isDir && item.name === 'root') return 1 // root directory special - if (isHidden) return 2 // hidden file - if (isDir) return 3 // visible dir + + // .文件夹 -> 文件夹 -> .文件 -> 文件 + if (isDir) { + if (isHidden) return 0 // hidden dir + if (item.name === 'root') return 1 // root directory special + return 2 // visible dir + } + + // 非文件夹 + if (isHidden) return 3 // hidden file if (isLink) return 4 // link return 5 // regular file }