Skip to content

Commit 5a1e010

Browse files
authored
fix: Modify the terminal connection method (#8415)
1 parent 7792601 commit 5a1e010

26 files changed

Lines changed: 326 additions & 103 deletions

File tree

agent/app/api/v2/setting.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package v2
22

33
import (
4+
"encoding/json"
5+
"os"
6+
"os/user"
7+
"path"
8+
49
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
510
"github.com/1Panel-dev/1Panel/agent/app/dto"
611
"github.com/1Panel-dev/1Panel/agent/global"
12+
"github.com/1Panel-dev/1Panel/agent/utils/ssh"
713
"github.com/gin-gonic/gin"
14+
"github.com/pkg/errors"
815
)
916

1017
// @Tags System Setting
@@ -63,3 +70,75 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
6370
func (b *BaseApi) LoadBaseDir(c *gin.Context) {
6471
helper.SuccessWithData(c, global.Dir.DataDir)
6572
}
73+
74+
func (b *BaseApi) CheckLocalConn(c *gin.Context) {
75+
_, err := loadLocalConn()
76+
helper.SuccessWithData(c, err == nil)
77+
}
78+
79+
// @Tags System Setting
80+
// @Summary Check local conn info
81+
// @Success 200 {bool} isOk
82+
// @Security ApiKeyAuth
83+
// @Security Timestamp
84+
// @Router /settings/ssh/check/info [post]
85+
func (b *BaseApi) CheckLocalConnByInfo(c *gin.Context) {
86+
var req dto.SSHConnData
87+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
88+
return
89+
}
90+
helper.SuccessWithData(c, settingService.TestConnByInfo(req))
91+
}
92+
93+
// @Tags System Setting
94+
// @Summary Save local conn info
95+
// @Success 200
96+
// @Security ApiKeyAuth
97+
// @Security Timestamp
98+
// @Router /settings/ssh [post]
99+
func (b *BaseApi) SaveLocalConnInfo(c *gin.Context) {
100+
var req dto.SSHConnData
101+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
102+
return
103+
}
104+
helper.SuccessWithData(c, settingService.SaveConnInfo(req))
105+
}
106+
107+
func loadLocalConn() (*ssh.SSHClient, error) {
108+
itemPath := ""
109+
currentInfo, _ := user.Current()
110+
if len(currentInfo.HomeDir) == 0 {
111+
itemPath = "/root/.ssh/id_ed25519_1panel"
112+
} else {
113+
itemPath = path.Join(currentInfo.HomeDir, ".ssh/id_ed25519_1panel")
114+
}
115+
if _, err := os.Stat(itemPath); err != nil {
116+
_ = sshService.GenerateSSH(dto.GenerateSSH{EncryptionMode: "ed25519", Name: "_1panel"})
117+
}
118+
119+
privateKey, _ := os.ReadFile(itemPath)
120+
connWithKey := ssh.ConnInfo{
121+
Addr: "127.0.0.1",
122+
User: "root",
123+
Port: 22,
124+
AuthMode: "key",
125+
PrivateKey: privateKey,
126+
}
127+
client, err := ssh.NewClient(connWithKey)
128+
if err == nil {
129+
return client, nil
130+
}
131+
132+
connInfoInDB, err := settingService.GetSSHInfo()
133+
if err != nil {
134+
return nil, err
135+
}
136+
if len(connInfoInDB) == 0 {
137+
return nil, errors.New("no such ssh conn info in db!")
138+
}
139+
var connInDB ssh.ConnInfo
140+
if err := json.Unmarshal([]byte(connInfoInDB), &connInDB); err != nil {
141+
return nil, err
142+
}
143+
return ssh.NewClient(connInDB)
144+
}

agent/app/api/v2/terminal.go

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,21 @@ func (b *BaseApi) WsSSH(c *gin.Context) {
4040
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
4141
return
4242
}
43-
name, err := loadExecutor()
44-
if wshandleError(wsConn, err) {
45-
return
46-
}
47-
slave, err := terminal.NewCommand(name)
48-
if wshandleError(wsConn, err) {
43+
44+
client, err := loadLocalConn()
45+
if wshandleError(wsConn, errors.WithMessage(err, "failed to set up the connection. Please check the host information")) {
4946
return
5047
}
51-
defer slave.Close()
52-
53-
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
48+
defer client.Close()
49+
sws, err := terminal.NewLogicSshWsSession(cols, rows, client.Client, wsConn, "")
5450
if wshandleError(wsConn, err) {
5551
return
5652
}
53+
defer sws.Close()
5754

5855
quitChan := make(chan bool, 3)
59-
tty.Start(quitChan)
60-
go slave.Wait(quitChan)
56+
sws.Start(quitChan)
57+
go sws.Wait(quitChan)
6158

6259
<-quitChan
6360

@@ -254,12 +251,3 @@ var upGrader = websocket.Upgrader{
254251
return true
255252
},
256253
}
257-
258-
func loadExecutor() (string, error) {
259-
std, err := cmd.RunDefaultWithStdoutBashC("echo $SHELL")
260-
if err != nil {
261-
return "", fmt.Errorf("load default executor failed, err: %s", std)
262-
}
263-
264-
return strings.ReplaceAll(std, "\n", ""), nil
265-
}

agent/app/dto/setting.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,13 @@ type Clean struct {
6161
Name string `json:"name"`
6262
Size uint64 `json:"size"`
6363
}
64+
65+
type SSHConnData struct {
66+
Addr string `json:"addr" validate:"required"`
67+
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
68+
User string `json:"user" validate:"required"`
69+
AuthMode string `json:"authMode" validate:"oneof=password key"`
70+
Password string `json:"password"`
71+
PrivateKey string `json:"privateKey"`
72+
PassPhrase string `json:"passPhrase"`
73+
}

agent/app/dto/ssh.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type SSHInfo struct {
2424
type GenerateSSH struct {
2525
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
2626
Password string `json:"password"`
27+
Name string `json:"name"`
2728
}
2829

2930
type GenerateLoad struct {

agent/app/service/setting.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
package service
22

33
import (
4+
"encoding/base64"
45
"encoding/json"
56
"time"
67

78
"github.com/1Panel-dev/1Panel/agent/app/dto"
89
"github.com/1Panel-dev/1Panel/agent/buserr"
10+
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
11+
"github.com/1Panel-dev/1Panel/agent/utils/ssh"
12+
"github.com/jinzhu/copier"
913
)
1014

1115
type SettingService struct{}
1216

1317
type ISettingService interface {
1418
GetSettingInfo() (*dto.SettingInfo, error)
1519
Update(key, value string) error
20+
21+
GetSSHInfo() (string, error)
22+
TestConnByInfo(req dto.SSHConnData) bool
23+
SaveConnInfo(req dto.SSHConnData) error
1624
}
1725

1826
func NewISettingService() ISettingService {
@@ -44,3 +52,75 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
4452
func (u *SettingService) Update(key, value string) error {
4553
return settingRepo.UpdateOrCreate(key, value)
4654
}
55+
56+
func (u *SettingService) GetSSHInfo() (string, error) {
57+
conn, err := settingRepo.GetValueByKey("LocalSSHConn")
58+
if err != nil || len(conn) == 0 {
59+
return "", err
60+
}
61+
return encrypt.StringDecrypt(conn)
62+
}
63+
64+
func (u *SettingService) TestConnByInfo(req dto.SSHConnData) bool {
65+
if req.AuthMode == "password" && len(req.Password) != 0 {
66+
password, err := base64.StdEncoding.DecodeString(req.Password)
67+
if err != nil {
68+
return false
69+
}
70+
req.Password = string(password)
71+
}
72+
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
73+
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
74+
if err != nil {
75+
return false
76+
}
77+
req.PrivateKey = string(privateKey)
78+
}
79+
80+
var connInfo ssh.ConnInfo
81+
_ = copier.Copy(&connInfo, &req)
82+
connInfo.PrivateKey = []byte(req.PrivateKey)
83+
if len(req.PassPhrase) != 0 {
84+
connInfo.PassPhrase = []byte(req.PassPhrase)
85+
}
86+
client, err := ssh.NewClient(connInfo)
87+
if err != nil {
88+
return false
89+
}
90+
defer client.Close()
91+
return true
92+
}
93+
94+
func (u *SettingService) SaveConnInfo(req dto.SSHConnData) error {
95+
if req.AuthMode == "password" && len(req.Password) != 0 {
96+
password, err := base64.StdEncoding.DecodeString(req.Password)
97+
if err != nil {
98+
return err
99+
}
100+
req.Password = string(password)
101+
}
102+
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
103+
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
104+
if err != nil {
105+
return err
106+
}
107+
req.PrivateKey = string(privateKey)
108+
}
109+
110+
var connInfo ssh.ConnInfo
111+
_ = copier.Copy(&connInfo, &req)
112+
connInfo.PrivateKey = []byte(req.PrivateKey)
113+
if len(req.PassPhrase) != 0 {
114+
connInfo.PassPhrase = []byte(req.PassPhrase)
115+
}
116+
client, err := ssh.NewClient(connInfo)
117+
if err != nil {
118+
return err
119+
}
120+
defer client.Close()
121+
122+
localConn, _ := json.Marshal(&connInfo)
123+
connAfterEncrypt, _ := encrypt.StringEncrypt(string(localConn))
124+
_ = settingRepo.Update("LocalSSHConn", connAfterEncrypt)
125+
return nil
126+
}

agent/app/service/ssh.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,10 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
254254
}
255255

256256
fileOp := files.NewFileOp()
257-
if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s", currentUser.HomeDir, req.EncryptionMode)); err != nil {
257+
if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s%s", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil {
258258
return err
259259
}
260-
if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s.pub", currentUser.HomeDir, req.EncryptionMode)); err != nil {
260+
if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s%s.pub", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil {
261261
return err
262262
}
263263

agent/app/task/task.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
114114
if taskID == "" {
115115
taskID = uuid.New().String()
116116
}
117-
logDir := path.Join(global.Dir.LogDir, taskScope)
117+
logDir := path.Join(global.Dir.TaskDir, taskScope)
118118
if _, err := os.Stat(logDir); os.IsNotExist(err) {
119119
if err = os.MkdirAll(logDir, constant.DirPerm); err != nil {
120120
return nil, fmt.Errorf("failed to create log directory: %w", err)
121121
}
122122
}
123-
logPath := path.Join(global.Dir.LogDir, taskScope, taskID+".log")
123+
logPath := path.Join(global.Dir.TaskDir, taskScope, taskID+".log")
124124
file, err := os.OpenFile(logPath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, constant.FilePerm)
125125
if err != nil {
126126
return nil, fmt.Errorf("failed to open log file: %w", err)
@@ -267,7 +267,7 @@ func (t *Task) LogFailed(msg string) {
267267
}
268268

269269
func (t *Task) LogFailedWithErr(msg string, err error) {
270-
t.Logger.Println(fmt.Sprintf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error()))
270+
t.Logger.Printf("%s %s : %s\n", msg, i18n.GetMsgByKey("Failed"), err.Error())
271271
}
272272

273273
func (t *Task) LogSuccess(msg string) {
@@ -278,7 +278,7 @@ func (t *Task) LogSuccessF(format string, v ...any) {
278278
}
279279

280280
func (t *Task) LogStart(msg string) {
281-
t.Logger.Println(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg))
281+
t.Logger.Printf("%s%s\n", i18n.GetMsgByKey("Start"), msg)
282282
}
283283

284284
func (t *Task) LogWithOps(operate, msg string) {

agent/global/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type SystemDir struct {
2525
BaseDir string
2626
DbDir string
2727
LogDir string
28+
TaskDir string
2829
DataDir string
2930
TmpDir string
3031
LocalBackupDir string

agent/init/dir/dir.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ func Init() {
1515
global.Dir.BaseDir, _ = fileOp.CreateDirWithPath(true, baseDir)
1616
global.Dir.DataDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel"))
1717
global.Dir.DbDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/db"))
18-
global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/task"))
18+
global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log"))
19+
global.Dir.TaskDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/task"))
1920
global.Dir.TmpDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/tmp"))
2021

2122
global.Dir.AppDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/apps"))

agent/init/migration/migrate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func InitAgentDB() {
2828
migrations.UpdateSettingStatus,
2929
migrations.InitDefault,
3030
migrations.UpdateWebsiteExpireDate,
31+
migrations.AddLocalSSHSetting,
3132
})
3233
if err := m.Migrate(); err != nil {
3334
global.LOG.Error(err)

0 commit comments

Comments
 (0)