mirror of
https://github.com/chaos-zhu/easynode.git
synced 2026-10-07 12:48:28 +08:00
feat: 支持openssh加密密钥
This commit is contained in:
+13
-2
@@ -1,6 +1,5 @@
|
||||
## TODO
|
||||
|
||||
* 服务器文件对传
|
||||
* 批量下发后台定时任务
|
||||
* AI对话收藏
|
||||
* 移动端Ctrl、Tab的按键面板
|
||||
@@ -8,7 +7,19 @@
|
||||
* 进程管理
|
||||
* 当前会话连接|w
|
||||
* 日志打印优化
|
||||
*
|
||||
* rdp
|
||||
* 探针接入
|
||||
|
||||
## [3.4.0](https://github.com/chaos-zhu/easynode/releases) (2025-08-04)
|
||||
* 🎉新增文件对传功能
|
||||
* SFTP面板支持手动断开重连
|
||||
* SFTP loading ui修复
|
||||
* 禁用MFA2添加验证
|
||||
* 支持openssh加密密钥
|
||||
* 点击Logo切换菜单位置
|
||||
* 换了个新Logo
|
||||
* 合并通知配置tab
|
||||
|
||||
## [3.3.0](https://github.com/chaos-zhu/easynode/releases) (2025-08-04)
|
||||
|
||||
* 🎉新增终端连接代理服务
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -9,15 +9,16 @@ async function getSSHList({ res }) {
|
||||
let data = await credentialsDB.findAsync({})
|
||||
data = data?.map(item => {
|
||||
const { name, authType, _id: id, date } = item
|
||||
return { id, name, authType, privateKey: '', password: '', date }
|
||||
return { id, name, authType, privateKey: '', password: '', openSSHKeyPassword: '', date }
|
||||
}) || []
|
||||
data.sort((a, b) => b.date - a.date)
|
||||
res.success({ data })
|
||||
}
|
||||
|
||||
const addSSH = async ({ res, request }) => {
|
||||
let { body: { name, authType, password, privateKey, tempKey } } = request
|
||||
let { body: { name, authType, password, privateKey, openSSHKeyPassword, tempKey } } = request
|
||||
let record = { name, authType, password, privateKey }
|
||||
if (openSSHKeyPassword) record.openSSHKeyPassword = openSSHKeyPassword
|
||||
if (!name || !record[authType]) return res.fail({ data: false, msg: '参数错误' })
|
||||
let count = await credentialsDB.countAsync({ name })
|
||||
if (count > 0) return res.fail({ data: false, msg: '已存在同名凭证' })
|
||||
@@ -34,8 +35,9 @@ const addSSH = async ({ res, request }) => {
|
||||
}
|
||||
|
||||
const updateSSH = async ({ res, request }) => {
|
||||
let { body: { id, name, authType, password, privateKey, date, tempKey } } = request
|
||||
let { body: { id, name, authType, password, privateKey, openSSHKeyPassword, date, tempKey } } = request
|
||||
let record = { name, authType, password, privateKey, date }
|
||||
if (openSSHKeyPassword) record.openSSHKeyPassword = openSSHKeyPassword
|
||||
if (!id || !name) return res.fail({ data: false, msg: '请输入凭据名称' })
|
||||
let oldRecord = await credentialsDB.findOneAsync({ _id: id })
|
||||
if (!oldRecord) return res.fail({ data: false, msg: '凭证不存在' })
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,6 +22,9 @@ async function getConnectionOptions(hostId) {
|
||||
const sshRecord = await credentialsDB.findOneAsync({ _id: credentialId })
|
||||
authInfo.authType = sshRecord.authType
|
||||
authInfo[authInfo.authType] = await AESDecryptAsync(sshRecord[authInfo.authType])
|
||||
if (authInfo.authType === 'privateKey' && sshRecord.openSSHKeyPassword) {
|
||||
authInfo.passphrase = sshRecord.openSSHKeyPassword
|
||||
}
|
||||
} else {
|
||||
authInfo[authType] = await AESDecryptAsync(hostInfo[authType])
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
U2FsdGVkX19cLtuM32n63Jkv0/ObLTjPu6qgg7GgYXu5azvBJiwxIKAZpdoIwwJyxqsRh5oggNeUZxVtLyQ2DPvBV8N+e4P9SCIZ4AwL0NoQzgwes1gjKAR6bfVxCJ1KjB2oSa+HQLtKc9grodpsF++KLNC8+D1ZQBWVQ7Florqr0Zn0Nq2v3tsO2wS22QEGnmtTQaGELMnBgNti1EuBk7XAcChOCIY3KSsELowIdcFyyAlouc/YJiholQELTc3R3li3GSlmOuFPTnnaLe/PBMxjbTApma2otVTl5ddNkKzMrMSyOhBprw1nOVK2k/sHhCcZtoVBp3iT/13Dv50W2YTAw8k9Tb52w1jcn+fDIcj1EBZNOCTUhJ7TJXgncFCvNuRWKwFrx3vHJWW3Qaep/PMRbv+UYfWnU56kXBldOMTeyvIK4GRrm109fSBAf3/Yrt1MquIkt6GLN5x3eF9p/CwSF5ObykkVa4A7mI10wRcY9Le/HyZbcbdkyICA8Y9+ZM9PAOP1rO7W268NJzc//y+tBH9Lh9X7beK6xR0soMkGsboAsGCSQGG8kLSlCtYSN2dWp2GqNrtgrMjqX2STri+/2PTdJ3rQFoABlIl24qLoZsgcsfiEm3MGnTcSCl2sbnJM0MSCdlTCrozmm9h7yFzrdKwxQamtzGd9UYzFzBUqGMmdXj0MxG0Wt8rGJ+ALM5NWJPV9JdXzsVGTMJcuUUole/ZUAnoeOyVPZGw9u2zve1G6DqxTlt7lTdqt+r7YQs8xVqKzNWhrs4JaHN8VC5vpCDAzPxukPfd7spfLqWn97llTP5zR/b4DiM5vwTuWgHgeXp4s3Ii2hgJW7yim8cWk7Q5phP1mvb0PorlSp+4=
|
||||
U2FsdGVkX1/ZvAPYoB/CtzeytYO1I2b3w9dMsJCC7Ij/bQSMkkrORQSfc2kzqp6ZOuRvrYaEj8/SoMyukViiB14z5DVhX+Pjfm8VjQ3sNtPfN/Kc8nxJkipB8bjWVuiK9VuTxxBVatGqQ+ESDF8Vzq1ygL3NTGz0QqnfMiY3NXecc/PGi/dP99feMPpL/5XmbqMhDz8FG/MlGhuXIjd+Zl2qkxhGgI2bgOwcyJBLCOuugaAVNUUSZIq4rrsJPgnj/kFf6rh1qgXkTMa3dE7XACoNyjnYPUCX0brIenKUqd7aehFKiRczudmzSjrPJXxb3txUbzjWJzhjW0FA0odNQCWog0Qvh+WXDc76QpMOD/Bq/yxmQvKwx8AniTTn8zhYUnwSWO+b4+H6v/kGcY9LSocQhbK7Ef5cfn7SRnTE5fKcjTrLnXQ2sc3j77VQFcJZ9lCQk0WgfZhtR37ZjzDeMkV/og9Kw4hJpluAFti+4cD2vpqF8c8rs45CtzqpIfc1evQPbxKH4kKtM0gWXrMuyQN3bIuLydsSFX95GZahg8PGdJkRngcHOKjjR/VMsAibdaGHuuQ3UlAqehWGJodSO81+ULVz5qt9VeSB1qZkdopy6GAuZsRbXibTbCv1E9CduFCiZQ8+eWpQexf83jieYevTEpQoS4L5DTxrYK7zavS+3qlECcpDbPiQ8Ji6AkmUokbe5Mnm9WSR+WaIY3gp1T0Of5f6GDvxce1HrM2ysWt5LjLd4sOACL8mVzbqXoMKaU5HC69CtaXsOee68GSr0P2V0glojMS2awRImA3BMUCGABn8SfVn45w1vf2jcwnITD4QrKTXeARuvs1vltvRXeoKyXa+HesQkgBidgIyIBk=
|
||||
@@ -67,6 +67,19 @@
|
||||
placeholder="-----BEGIN RSA PRIVATE KEY-----"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="sshForm.authType === 'privateKey' && showOpenSSHKeyField" label="私钥密码">
|
||||
<PlusSupportTip>
|
||||
<el-input
|
||||
v-model="sshForm.openSSHKeyPassword"
|
||||
type="password"
|
||||
:disabled="!isPlusActive"
|
||||
placeholder="请输入openssh私钥密码"
|
||||
show-password
|
||||
autocomplete="off"
|
||||
clearable
|
||||
/>
|
||||
</PlusSupportTip>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="sshForm.authType === 'password'" prop="password" label="密码">
|
||||
<el-input
|
||||
v-model.trim="sshForm.password"
|
||||
@@ -129,7 +142,8 @@ const sshForm = reactive({
|
||||
name: '',
|
||||
authType: 'privateKey',
|
||||
privateKey: '',
|
||||
password: ''
|
||||
password: '',
|
||||
openSSHKeyPassword: ''
|
||||
})
|
||||
|
||||
const rules = computed(() => {
|
||||
@@ -203,6 +217,7 @@ const handleClickUploadBtn = () => {
|
||||
const keyPasswordVisible = ref(false)
|
||||
const keyPassword = ref('')
|
||||
const tempPrivateKey = ref('')
|
||||
const showOpenSSHKeyField = ref(false)
|
||||
|
||||
const handleSelectPrivateKeyFile = (event) => {
|
||||
let file = event.target.files[0]
|
||||
@@ -213,6 +228,9 @@ const handleSelectPrivateKeyFile = (event) => {
|
||||
if (content.includes('ENCRYPTED')) {
|
||||
tempPrivateKey.value = content
|
||||
keyPasswordVisible.value = true
|
||||
} else if (content.includes('OPENSSH PRIVATE KEY')) {
|
||||
sshForm.privateKey = content
|
||||
showOpenSSHKeyField.value = true
|
||||
} else {
|
||||
sshForm.privateKey = content
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user