diff --git a/backend/app/api/v1/host.go b/backend/app/api/v1/host.go index 7bd794138..3dc2a0aba 100644 --- a/backend/app/api/v1/host.go +++ b/backend/app/api/v1/host.go @@ -245,11 +245,13 @@ func (b *BaseApi) UpdateHost(c *gin.Context) { upMap["port"] = req.Port upMap["user"] = req.User upMap["auth_mode"] = req.AuthMode + upMap["remember_password"] = req.RememberPassword if len(req.Password) != 0 { upMap["password"] = req.Password } if len(req.PrivateKey) != 0 { upMap["private_key"] = req.PrivateKey + upMap["pass_phrase"] = req.PassPhrase } upMap["description"] = req.Description if err := hostService.Update(req.ID, upMap); err != nil { diff --git a/backend/app/api/v1/terminal.go b/backend/app/api/v1/terminal.go index 52d5b933c..736d16338 100644 --- a/backend/app/api/v1/terminal.go +++ b/backend/app/api/v1/terminal.go @@ -44,6 +44,9 @@ func (b *BaseApi) WsSsh(c *gin.Context) { var connInfo ssh.ConnInfo _ = copier.Copy(&connInfo, &host) connInfo.PrivateKey = []byte(host.PrivateKey) + if len(host.PassPhrase) != 0 { + connInfo.PassPhrase = []byte(host.PassPhrase) + } wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) if err != nil { diff --git a/backend/app/dto/host.go b/backend/app/dto/host.go index 3d510404f..9853d8f34 100644 --- a/backend/app/dto/host.go +++ b/backend/app/dto/host.go @@ -5,15 +5,17 @@ import ( ) type HostOperate struct { - ID uint `json:"id"` - GroupID uint `json:"groupID"` - Name string `json:"name"` - Addr string `json:"addr" validate:"required"` - Port uint `json:"port" validate:"required,number,max=65535,min=1"` - User string `json:"user" validate:"required"` - AuthMode string `json:"authMode" validate:"oneof=password key"` - PrivateKey string `json:"privateKey"` - Password string `json:"password"` + ID uint `json:"id"` + GroupID uint `json:"groupID"` + Name string `json:"name"` + Addr string `json:"addr" validate:"required"` + Port uint `json:"port" validate:"required,number,max=65535,min=1"` + User string `json:"user" validate:"required"` + AuthMode string `json:"authMode" validate:"oneof=password key"` + Password string `json:"password"` + PrivateKey string `json:"privateKey"` + PassPhrase string `json:"passPhrase"` + RememberPassword bool `json:"rememberPassword"` Description string `json:"description"` } @@ -23,8 +25,9 @@ type HostConnTest struct { Port uint `json:"port" validate:"required,number,max=65535,min=1"` User string `json:"user" validate:"required"` AuthMode string `json:"authMode" validate:"oneof=password key"` - PrivateKey string `json:"privateKey"` Password string `json:"password"` + PrivateKey string `json:"privateKey"` + PassPhrase string `json:"passPhrase"` } type SearchHostWithPage struct { @@ -43,15 +46,19 @@ type ChangeHostGroup struct { } type HostInfo struct { - ID uint `json:"id"` - CreatedAt time.Time `json:"createdAt"` - GroupID uint `json:"groupID"` - GroupBelong string `json:"groupBelong"` - Name string `json:"name"` - Addr string `json:"addr"` - Port uint `json:"port"` - User string `json:"user"` - AuthMode string `json:"authMode"` + ID uint `json:"id"` + CreatedAt time.Time `json:"createdAt"` + GroupID uint `json:"groupID"` + GroupBelong string `json:"groupBelong"` + Name string `json:"name"` + Addr string `json:"addr"` + Port uint `json:"port"` + User string `json:"user"` + AuthMode string `json:"authMode"` + Password string `json:"password"` + PrivateKey string `json:"privateKey"` + PassPhrase string `json:"passPhrase"` + RememberPassword bool `json:"rememberPassword"` Description string `json:"description"` } diff --git a/backend/app/model/host.go b/backend/app/model/host.go index b25a57b82..a4fe6aedd 100644 --- a/backend/app/model/host.go +++ b/backend/app/model/host.go @@ -2,14 +2,17 @@ package model type Host struct { BaseModel - GroupID uint `gorm:"type:decimal;not null" json:"group_id"` - Name string `gorm:"type:varchar(64);not null" json:"name"` - Addr string `gorm:"type:varchar(16);not null" json:"addr"` - Port int `gorm:"type:decimal;not null" json:"port"` - User string `gorm:"type:varchar(64);not null" json:"user"` - AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"` - Password string `gorm:"type:varchar(64)" json:"password"` - PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"` + + GroupID uint `gorm:"type:decimal;not null" json:"group_id"` + Name string `gorm:"type:varchar(64);not null" json:"name"` + Addr string `gorm:"type:varchar(16);not null" json:"addr"` + Port int `gorm:"type:decimal;not null" json:"port"` + User string `gorm:"type:varchar(64);not null" json:"user"` + AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"` + Password string `gorm:"type:varchar(64)" json:"password"` + 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"` } diff --git a/backend/app/service/host.go b/backend/app/service/host.go index 5286c5312..d928f16ba 100644 --- a/backend/app/service/host.go +++ b/backend/app/service/host.go @@ -52,11 +52,15 @@ func (u *HostService) TestByInfo(req dto.HostConnTest) bool { req.Password = host.Password req.AuthMode = host.AuthMode req.PrivateKey = host.PrivateKey + req.PassPhrase = host.PassPhrase } var connInfo ssh.ConnInfo _ = copier.Copy(&connInfo, &req) connInfo.PrivateKey = []byte(req.PrivateKey) + if len(req.PassPhrase) != 0 { + connInfo.PassPhrase = []byte(req.PassPhrase) + } client, err := connInfo.NewClient() if err != nil { return false @@ -85,6 +89,10 @@ func (u *HostService) TestLocalConn(id uint) bool { if err := copier.Copy(&connInfo, &host); err != nil { return false } + connInfo.PrivateKey = []byte(host.PrivateKey) + if len(host.PassPhrase) != 0 { + connInfo.PassPhrase = []byte(host.PassPhrase) + } client, err := connInfo.NewClient() if err != nil { return false @@ -115,6 +123,11 @@ func (u *HostService) SearchWithPage(search dto.SearchHostWithPage) (int64, inte } group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID)) item.GroupBelong = group.Name + if !item.RememberPassword { + item.Password = "" + item.PrivateKey = "" + item.PassPhrase = "" + } dtoHosts = append(dtoHosts, item) } return total, dtoHosts, err @@ -182,6 +195,8 @@ func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) { upMap["auth_mode"] = req.AuthMode upMap["password"] = req.Password upMap["private_key"] = req.PrivateKey + upMap["pass_phrase"] = req.PassPhrase + upMap["remember_password"] = req.RememberPassword upMap["description"] = req.Description if err := hostRepo.Update(sameHostID, upMap); err != nil { return nil, err diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index 0b37edaff..db2d247ea 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -23,6 +23,7 @@ func Init() { migrations.AddDefaultGroup, migrations.AddTableRuntime, migrations.UpdateTableApp, + migrations.UpdateTableHost, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index 1b3dc6e1c..e7b7ea5e0 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -264,3 +264,13 @@ var UpdateTableApp = &gormigrate.Migration{ 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 + }, +} diff --git a/backend/utils/ssh/ssh.go b/backend/utils/ssh/ssh.go index a1cd69659..bbe6d2377 100644 --- a/backend/utils/ssh/ssh.go +++ b/backend/utils/ssh/ssh.go @@ -127,20 +127,8 @@ func (w *wsBufferWriter) Write(p []byte) (int, error) { } func makePrivateKeySigner(privateKey []byte, passPhrase []byte) (gossh.Signer, error) { - var signer gossh.Signer - if passPhrase != nil { - s, err := gossh.ParsePrivateKeyWithPassphrase(privateKey, passPhrase) - if err != nil { - return nil, fmt.Errorf("error parsing SSH key: '%v'", err) - } - signer = s - } else { - s, err := gossh.ParsePrivateKey(privateKey) - if err != nil { - return nil, fmt.Errorf("error parsing SSH key: '%v'", err) - } - signer = s + if len(passPhrase) != 0 { + return gossh.ParsePrivateKeyWithPassphrase(privateKey, passPhrase) } - - return signer, nil + return gossh.ParsePrivateKey(privateKey) } diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 70f3a2929..8fc9273d9 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -18,6 +18,10 @@ export namespace Host { port: number; user: string; authMode: string; + password: string; + privateKey: string; + passPhrase: string; + rememberPassword: boolean; description: string; } export interface HostOperate { @@ -28,8 +32,10 @@ export namespace Host { port: number; user: string; authMode: string; - privateKey: string; password: string; + privateKey: string; + passPhrase: string; + rememberPassword: boolean; description: string; } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 7e12c906e..96fe81819 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -674,10 +674,12 @@ const message = { port: 'Port', user: 'Username', authMode: 'Auth Mode', - passwordMode: 'password', + passwordMode: 'Password', + rememberPassword: 'Remember password', keyMode: 'PrivateKey', password: 'Password', - key: 'Private Key', + key: 'Private key', + keyPassword: 'Private key password', emptyTerminal: 'No terminal is currently connected', }, logs: { diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 87e4a814b..373016a30 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -673,10 +673,12 @@ const message = { port: '端口', user: '用户名', authMode: '认证方式', - passwordMode: '密码输入', - keyMode: '密钥输入', + passwordMode: '密码认证', + rememberPassword: '记住密码', + keyMode: '私钥认证', password: '密码', - key: '密钥', + key: '私钥', + keyPassword: '私钥密码', emptyTerminal: '暂无终端连接', }, logs: { diff --git a/frontend/src/views/host/terminal/host/operate/index.vue b/frontend/src/views/host/terminal/host/operate/index.vue index d1f8b0e5b..d0645d92f 100644 --- a/frontend/src/views/host/terminal/host/operate/index.vue +++ b/frontend/src/views/host/terminal/host/operate/index.vue @@ -36,7 +36,22 @@ > - + + + + + {{ $t('terminal.rememberPassword') }} + + diff --git a/frontend/src/views/host/terminal/terminal/host-create.vue b/frontend/src/views/host/terminal/terminal/host-create.vue index 3f4662120..c24d4e665 100644 --- a/frontend/src/views/host/terminal/terminal/host-create.vue +++ b/frontend/src/views/host/terminal/terminal/host-create.vue @@ -40,7 +40,17 @@ - + + + + + {{ $t('terminal.rememberPassword') }} + + @@ -91,6 +101,8 @@ let hostInfo = reactive({ authMode: 'password', password: '', privateKey: '', + passPhrase: '', + rememberPassword: false, description: '', });