mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: 主机增加记住密码,支持带密码私钥连接 (#570)
This commit is contained in:
parent
a5fd55e90e
commit
0ddbdfeac9
@ -245,11 +245,13 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
upMap["port"] = req.Port
|
upMap["port"] = req.Port
|
||||||
upMap["user"] = req.User
|
upMap["user"] = req.User
|
||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
if len(req.Password) != 0 {
|
if len(req.Password) != 0 {
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
}
|
}
|
||||||
if len(req.PrivateKey) != 0 {
|
if len(req.PrivateKey) != 0 {
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
}
|
}
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostService.Update(req.ID, upMap); err != nil {
|
if err := hostService.Update(req.ID, upMap); err != nil {
|
||||||
|
@ -44,6 +44,9 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
|||||||
var connInfo ssh.ConnInfo
|
var connInfo ssh.ConnInfo
|
||||||
_ = copier.Copy(&connInfo, &host)
|
_ = copier.Copy(&connInfo, &host)
|
||||||
connInfo.PrivateKey = []byte(host.PrivateKey)
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
|
|
||||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,8 +12,10 @@ type HostOperate struct {
|
|||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
@ -23,8 +25,9 @@ type HostConnTest struct {
|
|||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchHostWithPage struct {
|
type SearchHostWithPage struct {
|
||||||
@ -52,6 +55,10 @@ type HostInfo struct {
|
|||||||
Port uint `json:"port"`
|
Port uint `json:"port"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
AuthMode string `json:"authMode"`
|
AuthMode string `json:"authMode"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
|
||||||
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
||||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
||||||
@ -10,6 +11,8 @@ type Host struct {
|
|||||||
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
||||||
Password string `gorm:"type:varchar(64)" json:"password"`
|
Password string `gorm:"type:varchar(64)" json:"password"`
|
||||||
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
||||||
|
PassPhrase string `gorm:"type:varchar(256)" json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `gorm:"type:varchar(256)" json:"description"`
|
Description string `gorm:"type:varchar(256)" json:"description"`
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,15 @@ func (u *HostService) TestByInfo(req dto.HostConnTest) bool {
|
|||||||
req.Password = host.Password
|
req.Password = host.Password
|
||||||
req.AuthMode = host.AuthMode
|
req.AuthMode = host.AuthMode
|
||||||
req.PrivateKey = host.PrivateKey
|
req.PrivateKey = host.PrivateKey
|
||||||
|
req.PassPhrase = host.PassPhrase
|
||||||
}
|
}
|
||||||
|
|
||||||
var connInfo ssh.ConnInfo
|
var connInfo ssh.ConnInfo
|
||||||
_ = copier.Copy(&connInfo, &req)
|
_ = copier.Copy(&connInfo, &req)
|
||||||
connInfo.PrivateKey = []byte(req.PrivateKey)
|
connInfo.PrivateKey = []byte(req.PrivateKey)
|
||||||
|
if len(req.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(req.PassPhrase)
|
||||||
|
}
|
||||||
client, err := connInfo.NewClient()
|
client, err := connInfo.NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@ -85,6 +89,10 @@ func (u *HostService) TestLocalConn(id uint) bool {
|
|||||||
if err := copier.Copy(&connInfo, &host); err != nil {
|
if err := copier.Copy(&connInfo, &host); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
client, err := connInfo.NewClient()
|
client, err := connInfo.NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@ -115,6 +123,11 @@ func (u *HostService) SearchWithPage(search dto.SearchHostWithPage) (int64, inte
|
|||||||
}
|
}
|
||||||
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
||||||
item.GroupBelong = group.Name
|
item.GroupBelong = group.Name
|
||||||
|
if !item.RememberPassword {
|
||||||
|
item.Password = ""
|
||||||
|
item.PrivateKey = ""
|
||||||
|
item.PassPhrase = ""
|
||||||
|
}
|
||||||
dtoHosts = append(dtoHosts, item)
|
dtoHosts = append(dtoHosts, item)
|
||||||
}
|
}
|
||||||
return total, dtoHosts, err
|
return total, dtoHosts, err
|
||||||
@ -182,6 +195,8 @@ func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) {
|
|||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -23,6 +23,7 @@ func Init() {
|
|||||||
migrations.AddDefaultGroup,
|
migrations.AddDefaultGroup,
|
||||||
migrations.AddTableRuntime,
|
migrations.AddTableRuntime,
|
||||||
migrations.UpdateTableApp,
|
migrations.UpdateTableApp,
|
||||||
|
migrations.UpdateTableHost,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -264,3 +264,13 @@ var UpdateTableApp = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateTableHost = &gormigrate.Migration{
|
||||||
|
ID: "20230410-update-table-host",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.Host{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -127,20 +127,8 @@ func (w *wsBufferWriter) Write(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makePrivateKeySigner(privateKey []byte, passPhrase []byte) (gossh.Signer, error) {
|
func makePrivateKeySigner(privateKey []byte, passPhrase []byte) (gossh.Signer, error) {
|
||||||
var signer gossh.Signer
|
if len(passPhrase) != 0 {
|
||||||
if passPhrase != nil {
|
return gossh.ParsePrivateKeyWithPassphrase(privateKey, passPhrase)
|
||||||
s, err := gossh.ParsePrivateKeyWithPassphrase(privateKey, passPhrase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing SSH key: '%v'", err)
|
|
||||||
}
|
}
|
||||||
signer = s
|
return gossh.ParsePrivateKey(privateKey)
|
||||||
} else {
|
|
||||||
s, err := gossh.ParsePrivateKey(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing SSH key: '%v'", err)
|
|
||||||
}
|
|
||||||
signer = s
|
|
||||||
}
|
|
||||||
|
|
||||||
return signer, nil
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ export namespace Host {
|
|||||||
port: number;
|
port: number;
|
||||||
user: string;
|
user: string;
|
||||||
authMode: string;
|
authMode: string;
|
||||||
|
password: string;
|
||||||
|
privateKey: string;
|
||||||
|
passPhrase: string;
|
||||||
|
rememberPassword: boolean;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
export interface HostOperate {
|
export interface HostOperate {
|
||||||
@ -28,8 +32,10 @@ export namespace Host {
|
|||||||
port: number;
|
port: number;
|
||||||
user: string;
|
user: string;
|
||||||
authMode: string;
|
authMode: string;
|
||||||
privateKey: string;
|
|
||||||
password: string;
|
password: string;
|
||||||
|
privateKey: string;
|
||||||
|
passPhrase: string;
|
||||||
|
rememberPassword: boolean;
|
||||||
|
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
@ -674,10 +674,12 @@ const message = {
|
|||||||
port: 'Port',
|
port: 'Port',
|
||||||
user: 'Username',
|
user: 'Username',
|
||||||
authMode: 'Auth Mode',
|
authMode: 'Auth Mode',
|
||||||
passwordMode: 'password',
|
passwordMode: 'Password',
|
||||||
|
rememberPassword: 'Remember password',
|
||||||
keyMode: 'PrivateKey',
|
keyMode: 'PrivateKey',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
key: 'Private Key',
|
key: 'Private key',
|
||||||
|
keyPassword: 'Private key password',
|
||||||
emptyTerminal: 'No terminal is currently connected',
|
emptyTerminal: 'No terminal is currently connected',
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
|
@ -673,10 +673,12 @@ const message = {
|
|||||||
port: '端口',
|
port: '端口',
|
||||||
user: '用户名',
|
user: '用户名',
|
||||||
authMode: '认证方式',
|
authMode: '认证方式',
|
||||||
passwordMode: '密码输入',
|
passwordMode: '密码认证',
|
||||||
keyMode: '密钥输入',
|
rememberPassword: '记住密码',
|
||||||
|
keyMode: '私钥认证',
|
||||||
password: '密码',
|
password: '密码',
|
||||||
key: '密钥',
|
key: '私钥',
|
||||||
|
keyPassword: '私钥密码',
|
||||||
emptyTerminal: '暂无终端连接',
|
emptyTerminal: '暂无终端连接',
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
|
@ -36,7 +36,22 @@
|
|||||||
>
|
>
|
||||||
<el-input clearable type="textarea" v-model="dialogData.rowData!.privateKey" />
|
<el-input clearable type="textarea" v-model="dialogData.rowData!.privateKey" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.port')" prop="port">
|
<el-form-item
|
||||||
|
:label="$t('terminal.keyPassword')"
|
||||||
|
v-if="dialogData.rowData!.authMode === 'key'"
|
||||||
|
prop="passPhrase"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
clearable
|
||||||
|
v-model="dialogData.rowData!.passPhrase"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-checkbox clearable v-model.number="dialogData.rowData!.rememberPassword">
|
||||||
|
{{ $t('terminal.rememberPassword') }}
|
||||||
|
</el-checkbox>
|
||||||
|
<el-form-item style="margin-top: 10px" :label="$t('terminal.port')" prop="port">
|
||||||
<el-input clearable v-model.number="dialogData.rowData!.port" />
|
<el-input clearable v-model.number="dialogData.rowData!.port" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('commons.table.group')" prop="groupID">
|
<el-form-item :label="$t('commons.table.group')" prop="groupID">
|
||||||
|
@ -40,7 +40,17 @@
|
|||||||
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
|
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
|
||||||
<el-input clearable type="textarea" v-model="hostInfo.privateKey" />
|
<el-input clearable type="textarea" v-model="hostInfo.privateKey" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.port')" prop="port">
|
<el-form-item
|
||||||
|
:label="$t('terminal.keyPassword')"
|
||||||
|
v-if="hostInfo.authMode === 'key'"
|
||||||
|
prop="passPhrase"
|
||||||
|
>
|
||||||
|
<el-input type="password" show-password clearable v-model="hostInfo.passPhrase" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-checkbox clearable v-model.number="hostInfo.rememberPassword">
|
||||||
|
{{ $t('terminal.rememberPassword') }}
|
||||||
|
</el-checkbox>
|
||||||
|
<el-form-item style="margin-top: 10px" :label="$t('terminal.port')" prop="port">
|
||||||
<el-input clearable v-model.number="hostInfo.port" />
|
<el-input clearable v-model.number="hostInfo.port" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('commons.table.title')" prop="name">
|
<el-form-item :label="$t('commons.table.title')" prop="name">
|
||||||
@ -91,6 +101,8 @@ let hostInfo = reactive<Host.HostOperate>({
|
|||||||
authMode: 'password',
|
authMode: 'password',
|
||||||
password: '',
|
password: '',
|
||||||
privateKey: '',
|
privateKey: '',
|
||||||
|
passPhrase: '',
|
||||||
|
rememberPassword: false,
|
||||||
description: '',
|
description: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user