From 5a1e010788ec9d4879b2ed30493c060f2cbbdc28 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 17 Apr 2025 22:26:23 +0800 Subject: [PATCH] fix: Modify the terminal connection method (#8415) --- agent/app/api/v2/setting.go | 79 +++++++++++++ agent/app/api/v2/terminal.go | 30 ++--- agent/app/dto/setting.go | 10 ++ agent/app/dto/ssh.go | 1 + agent/app/service/setting.go | 80 +++++++++++++ agent/app/service/ssh.go | 4 +- agent/app/task/task.go | 8 +- agent/global/config.go | 1 + agent/init/dir/dir.go | 3 +- agent/init/migration/migrate.go | 1 + agent/init/migration/migrations/init.go | 10 ++ agent/router/ro_host.go | 2 +- agent/router/ro_setting.go | 4 + agent/utils/ssh/ssh.go | 34 ++---- agent/utils/terminal/ws_session.go | 10 +- frontend/src/api/interface/host.ts | 2 + frontend/src/api/modules/terminal.ts | 11 ++ frontend/src/lang/modules/en.ts | 1 + frontend/src/lang/modules/ja.ts | 1 + frontend/src/lang/modules/ko.ts | 1 + frontend/src/lang/modules/ms.ts | 1 + frontend/src/lang/modules/pt-br.ts | 2 + frontend/src/lang/modules/ru.ts | 1 + frontend/src/lang/modules/zh-Hant.ts | 1 + .../views/terminal/terminal/host-create.vue | 110 +++++++++++------- .../src/views/terminal/terminal/index.vue | 25 ++-- 26 files changed, 328 insertions(+), 105 deletions(-) diff --git a/agent/app/api/v2/setting.go b/agent/app/api/v2/setting.go index fcc774401..73c688147 100644 --- a/agent/app/api/v2/setting.go +++ b/agent/app/api/v2/setting.go @@ -1,10 +1,17 @@ package v2 import ( + "encoding/json" + "os" + "os/user" + "path" + "github.com/1Panel-dev/1Panel/agent/app/api/v2/helper" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/ssh" "github.com/gin-gonic/gin" + "github.com/pkg/errors" ) // @Tags System Setting @@ -63,3 +70,75 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) { func (b *BaseApi) LoadBaseDir(c *gin.Context) { helper.SuccessWithData(c, global.Dir.DataDir) } + +func (b *BaseApi) CheckLocalConn(c *gin.Context) { + _, err := loadLocalConn() + helper.SuccessWithData(c, err == nil) +} + +// @Tags System Setting +// @Summary Check local conn info +// @Success 200 {bool} isOk +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /settings/ssh/check/info [post] +func (b *BaseApi) CheckLocalConnByInfo(c *gin.Context) { + var req dto.SSHConnData + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + helper.SuccessWithData(c, settingService.TestConnByInfo(req)) +} + +// @Tags System Setting +// @Summary Save local conn info +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /settings/ssh [post] +func (b *BaseApi) SaveLocalConnInfo(c *gin.Context) { + var req dto.SSHConnData + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + helper.SuccessWithData(c, settingService.SaveConnInfo(req)) +} + +func loadLocalConn() (*ssh.SSHClient, error) { + itemPath := "" + currentInfo, _ := user.Current() + if len(currentInfo.HomeDir) == 0 { + itemPath = "/root/.ssh/id_ed25519_1panel" + } else { + itemPath = path.Join(currentInfo.HomeDir, ".ssh/id_ed25519_1panel") + } + if _, err := os.Stat(itemPath); err != nil { + _ = sshService.GenerateSSH(dto.GenerateSSH{EncryptionMode: "ed25519", Name: "_1panel"}) + } + + privateKey, _ := os.ReadFile(itemPath) + connWithKey := ssh.ConnInfo{ + Addr: "127.0.0.1", + User: "root", + Port: 22, + AuthMode: "key", + PrivateKey: privateKey, + } + client, err := ssh.NewClient(connWithKey) + if err == nil { + return client, nil + } + + connInfoInDB, err := settingService.GetSSHInfo() + if err != nil { + return nil, err + } + if len(connInfoInDB) == 0 { + return nil, errors.New("no such ssh conn info in db!") + } + var connInDB ssh.ConnInfo + if err := json.Unmarshal([]byte(connInfoInDB), &connInDB); err != nil { + return nil, err + } + return ssh.NewClient(connInDB) +} diff --git a/agent/app/api/v2/terminal.go b/agent/app/api/v2/terminal.go index 2d71d4a95..f91e87530 100644 --- a/agent/app/api/v2/terminal.go +++ b/agent/app/api/v2/terminal.go @@ -40,24 +40,21 @@ func (b *BaseApi) WsSSH(c *gin.Context) { if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) { return } - name, err := loadExecutor() - if wshandleError(wsConn, err) { - return - } - slave, err := terminal.NewCommand(name) - if wshandleError(wsConn, err) { - return - } - defer slave.Close() - tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false) + client, err := loadLocalConn() + if wshandleError(wsConn, errors.WithMessage(err, "failed to set up the connection. Please check the host information")) { + return + } + defer client.Close() + sws, err := terminal.NewLogicSshWsSession(cols, rows, client.Client, wsConn, "") if wshandleError(wsConn, err) { return } + defer sws.Close() quitChan := make(chan bool, 3) - tty.Start(quitChan) - go slave.Wait(quitChan) + sws.Start(quitChan) + go sws.Wait(quitChan) <-quitChan @@ -254,12 +251,3 @@ var upGrader = websocket.Upgrader{ return true }, } - -func loadExecutor() (string, error) { - std, err := cmd.RunDefaultWithStdoutBashC("echo $SHELL") - if err != nil { - return "", fmt.Errorf("load default executor failed, err: %s", std) - } - - return strings.ReplaceAll(std, "\n", ""), nil -} diff --git a/agent/app/dto/setting.go b/agent/app/dto/setting.go index 50591c407..fd85f26e8 100644 --- a/agent/app/dto/setting.go +++ b/agent/app/dto/setting.go @@ -61,3 +61,13 @@ type Clean struct { Name string `json:"name"` Size uint64 `json:"size"` } + +type SSHConnData struct { + 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"` +} diff --git a/agent/app/dto/ssh.go b/agent/app/dto/ssh.go index c020ad567..be606b437 100644 --- a/agent/app/dto/ssh.go +++ b/agent/app/dto/ssh.go @@ -24,6 +24,7 @@ type SSHInfo struct { type GenerateSSH struct { EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"` Password string `json:"password"` + Name string `json:"name"` } type GenerateLoad struct { diff --git a/agent/app/service/setting.go b/agent/app/service/setting.go index 5129189fe..4451017cc 100644 --- a/agent/app/service/setting.go +++ b/agent/app/service/setting.go @@ -1,11 +1,15 @@ package service import ( + "encoding/base64" "encoding/json" "time" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/buserr" + "github.com/1Panel-dev/1Panel/agent/utils/encrypt" + "github.com/1Panel-dev/1Panel/agent/utils/ssh" + "github.com/jinzhu/copier" ) type SettingService struct{} @@ -13,6 +17,10 @@ type SettingService struct{} type ISettingService interface { GetSettingInfo() (*dto.SettingInfo, error) Update(key, value string) error + + GetSSHInfo() (string, error) + TestConnByInfo(req dto.SSHConnData) bool + SaveConnInfo(req dto.SSHConnData) error } func NewISettingService() ISettingService { @@ -44,3 +52,75 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) { func (u *SettingService) Update(key, value string) error { return settingRepo.UpdateOrCreate(key, value) } + +func (u *SettingService) GetSSHInfo() (string, error) { + conn, err := settingRepo.GetValueByKey("LocalSSHConn") + if err != nil || len(conn) == 0 { + return "", err + } + return encrypt.StringDecrypt(conn) +} + +func (u *SettingService) TestConnByInfo(req dto.SSHConnData) bool { + if req.AuthMode == "password" && len(req.Password) != 0 { + password, err := base64.StdEncoding.DecodeString(req.Password) + if err != nil { + return false + } + req.Password = string(password) + } + if req.AuthMode == "key" && len(req.PrivateKey) != 0 { + privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey) + if err != nil { + return false + } + req.PrivateKey = string(privateKey) + } + + 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 := ssh.NewClient(connInfo) + if err != nil { + return false + } + defer client.Close() + return true +} + +func (u *SettingService) SaveConnInfo(req dto.SSHConnData) error { + if req.AuthMode == "password" && len(req.Password) != 0 { + password, err := base64.StdEncoding.DecodeString(req.Password) + if err != nil { + return err + } + req.Password = string(password) + } + if req.AuthMode == "key" && len(req.PrivateKey) != 0 { + privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey) + if err != nil { + return err + } + req.PrivateKey = string(privateKey) + } + + 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 := ssh.NewClient(connInfo) + if err != nil { + return err + } + defer client.Close() + + localConn, _ := json.Marshal(&connInfo) + connAfterEncrypt, _ := encrypt.StringEncrypt(string(localConn)) + _ = settingRepo.Update("LocalSSHConn", connAfterEncrypt) + return nil +} diff --git a/agent/app/service/ssh.go b/agent/app/service/ssh.go index 5480ca8bb..ec50ea924 100644 --- a/agent/app/service/ssh.go +++ b/agent/app/service/ssh.go @@ -254,10 +254,10 @@ func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error { } fileOp := files.NewFileOp() - if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s", currentUser.HomeDir, req.EncryptionMode)); err != nil { + if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s%s", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil { return err } - if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s.pub", currentUser.HomeDir, req.EncryptionMode)); err != nil { + if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s%s.pub", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil { return err } diff --git a/agent/app/task/task.go b/agent/app/task/task.go index ebf524619..bfd0d51b3 100644 --- a/agent/app/task/task.go +++ b/agent/app/task/task.go @@ -114,13 +114,13 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e if taskID == "" { taskID = uuid.New().String() } - logDir := path.Join(global.Dir.LogDir, taskScope) + logDir := path.Join(global.Dir.TaskDir, taskScope) if _, err := os.Stat(logDir); os.IsNotExist(err) { if err = os.MkdirAll(logDir, constant.DirPerm); err != nil { return nil, fmt.Errorf("failed to create log directory: %w", err) } } - logPath := path.Join(global.Dir.LogDir, taskScope, taskID+".log") + logPath := path.Join(global.Dir.TaskDir, taskScope, taskID+".log") file, err := os.OpenFile(logPath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, constant.FilePerm) if err != nil { return nil, fmt.Errorf("failed to open log file: %w", err) @@ -267,7 +267,7 @@ func (t *Task) LogFailed(msg string) { } func (t *Task) LogFailedWithErr(msg string, err error) { - t.Logger.Println(fmt.Sprintf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error())) + t.Logger.Printf("%s %s : %s\n", msg, i18n.GetMsgByKey("Failed"), err.Error()) } func (t *Task) LogSuccess(msg string) { @@ -278,7 +278,7 @@ func (t *Task) LogSuccessF(format string, v ...any) { } func (t *Task) LogStart(msg string) { - t.Logger.Println(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg)) + t.Logger.Printf("%s%s\n", i18n.GetMsgByKey("Start"), msg) } func (t *Task) LogWithOps(operate, msg string) { diff --git a/agent/global/config.go b/agent/global/config.go index 41b9d4fe4..c4e39167e 100644 --- a/agent/global/config.go +++ b/agent/global/config.go @@ -25,6 +25,7 @@ type SystemDir struct { BaseDir string DbDir string LogDir string + TaskDir string DataDir string TmpDir string LocalBackupDir string diff --git a/agent/init/dir/dir.go b/agent/init/dir/dir.go index 3f36f6ebf..7e8ddb1cd 100644 --- a/agent/init/dir/dir.go +++ b/agent/init/dir/dir.go @@ -15,7 +15,8 @@ func Init() { global.Dir.BaseDir, _ = fileOp.CreateDirWithPath(true, baseDir) global.Dir.DataDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel")) global.Dir.DbDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/db")) - global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/task")) + global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log")) + global.Dir.TaskDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/task")) global.Dir.TmpDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/tmp")) global.Dir.AppDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/apps")) diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 4484b5850..9dfa5ebd1 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -28,6 +28,7 @@ func InitAgentDB() { migrations.UpdateSettingStatus, migrations.InitDefault, migrations.UpdateWebsiteExpireDate, + migrations.AddLocalSSHSetting, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index d5ee2bfde..ab5db461f 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -311,3 +311,13 @@ var UpdateWebsiteExpireDate = &gormigrate.Migration{ return nil }, } + +var AddLocalSSHSetting = &gormigrate.Migration{ + ID: "20250417-add-local-ssh-setting", + Migrate: func(tx *gorm.DB) error { + if err := tx.Create(&model.Setting{Key: "LocalSSHConn", Value: ""}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/agent/router/ro_host.go b/agent/router/ro_host.go index d155bd853..b601ae39a 100644 --- a/agent/router/ro_host.go +++ b/agent/router/ro_host.go @@ -47,6 +47,6 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) { hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess) hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile) - hostRouter.GET("/exec", baseApi.WsSSH) + hostRouter.GET("/terminal", baseApi.WsSSH) } } diff --git a/agent/router/ro_setting.go b/agent/router/ro_setting.go index 9d2524bad..9f9ebf729 100644 --- a/agent/router/ro_setting.go +++ b/agent/router/ro_setting.go @@ -26,5 +26,9 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) { settingRouter.POST("/snapshot/description/update", baseApi.UpdateSnapDescription) settingRouter.GET("/basedir", baseApi.LoadBaseDir) + + settingRouter.POST("/ssh/check", baseApi.CheckLocalConn) + settingRouter.POST("/ssh", baseApi.SaveLocalConnInfo) + settingRouter.POST("/ssh/check/info", baseApi.CheckLocalConnByInfo) } } diff --git a/agent/utils/ssh/ssh.go b/agent/utils/ssh/ssh.go index 604d97d03..d64264e7e 100644 --- a/agent/utils/ssh/ssh.go +++ b/agent/utils/ssh/ssh.go @@ -17,13 +17,13 @@ type ConnInfo struct { PrivateKey []byte `json:"privateKey"` PassPhrase []byte `json:"passPhrase"` DialTimeOut time.Duration `json:"dialTimeOut"` - - Client *gossh.Client `json:"client"` - Session *gossh.Session `json:"session"` - LastResult string `json:"lastResult"` } -func (c *ConnInfo) NewClient() (*ConnInfo, error) { +type SSHClient struct { + Client *gossh.Client `json:"client"` +} + +func NewClient(c ConnInfo) (*SSHClient, error) { if strings.Contains(c.Addr, ":") { c.Addr = fmt.Sprintf("[%s]", c.Addr) } @@ -52,30 +52,12 @@ func (c *ConnInfo) NewClient() (*ConnInfo, error) { } client, err := gossh.Dial(proto, addr, config) if nil != err { - return c, err + return nil, err } - c.Client = client - return c, nil + return &SSHClient{Client: client}, nil } -func (c *ConnInfo) Run(shell string) (string, error) { - if c.Client == nil { - if _, err := c.NewClient(); err != nil { - return "", err - } - } - session, err := c.Client.NewSession() - if err != nil { - return "", err - } - defer session.Close() - buf, err := session.CombinedOutput(shell) - - c.LastResult = string(buf) - return c.LastResult, err -} - -func (c *ConnInfo) Close() { +func (c *SSHClient) Close() { _ = c.Client.Close() } diff --git a/agent/utils/terminal/ws_session.go b/agent/utils/terminal/ws_session.go index 54411f967..c5fd9dc60 100644 --- a/agent/utils/terminal/ws_session.go +++ b/agent/utils/terminal/ws_session.go @@ -59,7 +59,7 @@ type LogicSshWsSession struct { IsFlagged bool } -func NewLogicSshWsSession(cols, rows int, isAdmin bool, sshClient *ssh.Client, wsConn *websocket.Conn) (*LogicSshWsSession, error) { +func NewLogicSshWsSession(cols, rows int, sshClient *ssh.Client, wsConn *websocket.Conn, initCmd string) (*LogicSshWsSession, error) { sshSession, err := sshClient.NewSession() if err != nil { return nil, err @@ -87,6 +87,10 @@ func NewLogicSshWsSession(cols, rows int, isAdmin bool, sshClient *ssh.Client, w if err := sshSession.Shell(); err != nil { return nil, err } + if len(initCmd) != 0 { + time.Sleep(100 * time.Millisecond) + _, _ = stdinP.Write([]byte(initCmd + "\n")) + } return &LogicSshWsSession{ stdinPipe: stdinP, comboOutput: comboWriter, @@ -94,7 +98,7 @@ func NewLogicSshWsSession(cols, rows int, isAdmin bool, sshClient *ssh.Client, w inputFilterBuff: inputBuf, session: sshSession, wsConn: wsConn, - isAdmin: isAdmin, + isAdmin: true, IsFlagged: false, }, nil } @@ -110,6 +114,7 @@ func (sws *LogicSshWsSession) Close() { sws.comboOutput = nil } } + func (sws *LogicSshWsSession) Start(quitChan chan bool) { go sws.receiveWsMsg(quitChan) go sws.sendComboOutput(quitChan) @@ -148,7 +153,6 @@ func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) { } sws.sendWebsocketInputCommandToSshSessionStdinPipe(decodeBytes) case WsMsgHeartbeat: - // 接收到心跳包后将心跳包原样返回,可以用于网络延迟检测等情况 err = wsConn.WriteMessage(websocket.TextMessage, wsData) if err != nil { global.LOG.Errorf("ssh sending heartbeat to webSocket failed, err: %v", err) diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 6bf7bc2eb..a8b857115 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -25,6 +25,7 @@ export namespace Host { description: string; } export interface HostOperate { + isLocal: boolean; id: number; name: string; groupID: number; @@ -40,6 +41,7 @@ export namespace Host { description: string; } export interface HostConnTest { + isLocal: boolean; addr: string; port: number; user: string; diff --git a/frontend/src/api/modules/terminal.ts b/frontend/src/api/modules/terminal.ts index 1c049dfc8..3ddf41fc9 100644 --- a/frontend/src/api/modules/terminal.ts +++ b/frontend/src/api/modules/terminal.ts @@ -21,6 +21,9 @@ export const addHost = (params: Host.HostOperate) => { if (request.privateKey) { request.privateKey = Base64.encode(request.privateKey); } + if (params.isLocal) { + return http.post(`/settings/ssh`, request); + } return http.post(`/core/hosts`, request); }; export const testByInfo = (params: Host.HostConnTest) => { @@ -31,6 +34,9 @@ export const testByInfo = (params: Host.HostConnTest) => { if (request.privateKey) { request.privateKey = Base64.encode(request.privateKey); } + if (params.isLocal) { + return http.post(`/settings/ssh/check/info`, request); + } return http.post(`/core/hosts/test/byinfo`, request); }; export const testByID = (id: number) => { @@ -52,3 +58,8 @@ export const editHostGroup = (params: Host.GroupChange) => { export const deleteHost = (params: { ids: number[] }) => { return http.post(`/core/hosts/del`, params); }; + +// agent +export const testLocalConn = () => { + return http.post(`/settings/ssh/check`); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index d14e41469..e16e33b9d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1092,6 +1092,7 @@ const message = { terminal: { local: 'Local', localHelper: 'The `local` name is used only for system local identification', + connLocalErr: 'Unable to automatically authenticate, please fill in the local server login information!', testConn: 'Test connection', saveAndConn: 'Save and Connect', connTestOk: 'Connection information available', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index fe90de8e1..0cc48e257 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -1050,6 +1050,7 @@ const message = { terminal: { local: 'ローカル', localHelper: 'ローカル名はシステムのローカル識別にのみ使用されます。', + connLocalErr: '自動的に認証できない場合は、ローカルサーバーのログイン情報を入力してください。', testConn: 'テスト接続', saveAndConn: '保存して接続します', connTestOk: '利用可能な接続情報', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 5a542a3f4..372729293 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -1043,6 +1043,7 @@ const message = { terminal: { local: '로컬', localHelper: '로컬 이름은 시스템 로컬 식별에만 사용됩니다.', + connLocalErr: '자동 인증에 실패했습니다. 로컬 서버 로그인 정보를 입력해주세요.', testConn: '연결 테스트', saveAndConn: '저장 후 연결', connTestOk: '연결 정보가 유효합니다.', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index aab819a7b..d6454dbfb 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -1079,6 +1079,7 @@ const message = { terminal: { local: 'Tempatan', localHelper: 'Nama tempatan hanya digunakan untuk pengenalan sistem tempatan.', + connLocalErr: 'Tidak dapat mengesahkan secara automatik, sila isi maklumat log masuk pelayan tempatan.', testConn: 'Uji sambungan', saveAndConn: 'Simpan dan sambung', connTestOk: 'Maklumat sambungan tersedia', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 97258ad84..4f826e97e 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -1069,6 +1069,8 @@ const message = { terminal: { local: 'Local', localHelper: 'O nome local é usado apenas para identificação local do sistema.', + connLocalErr: + 'Невозможно автоматически аутентифицироваться, пожалуйста, заполните информацию для входа на локальный сервер.', testConn: 'Testar conexão', saveAndConn: 'Salvar e conectar', connTestOk: 'Informações de conexão disponíveis', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 50ca533a1..42e659751 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -1074,6 +1074,7 @@ const message = { terminal: { local: 'Локальный', localHelper: 'Локальное имя используется только для локальной идентификации системы.', + connLocalErr: '無法自動認證,請填寫本地服務器的登錄信息!', testConn: 'Проверить подключение', saveAndConn: 'Сохранить и подключиться', connTestOk: 'Информация о подключении доступна', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index ee4943371..e60cbbd33 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -1040,6 +1040,7 @@ const message = { terminal: { local: '本機', localHelper: 'local 名稱僅用於系統本機標識', + connLocalErr: '无法自动认证,请填写本地服务器的登录信息!', testConn: '連接測試', saveAndConn: '保存並連接', connTestOk: '連接信息可用', diff --git a/frontend/src/views/terminal/terminal/host-create.vue b/frontend/src/views/terminal/terminal/host-create.vue index 60d941c10..8572dae57 100644 --- a/frontend/src/views/terminal/terminal/host-create.vue +++ b/frontend/src/views/terminal/terminal/host-create.vue @@ -1,41 +1,43 @@