diff --git a/agent/app/api/v2/setting.go b/agent/app/api/v2/setting.go index 80bb907dc..1f6180cf6 100644 --- a/agent/app/api/v2/setting.go +++ b/agent/app/api/v2/setting.go @@ -1,13 +1,12 @@ package v2 import ( + "encoding/base64" "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/app/model" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/ssh" "github.com/gin-gonic/gin" @@ -71,6 +70,35 @@ func (b *BaseApi) LoadBaseDir(c *gin.Context) { helper.SuccessWithData(c, global.Dir.DataDir) } +// @Tags System Setting +// @Summary Load local conn +// @Success 200 {object} dto.SSHConnData +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /settings/ssh [get] +func (b *BaseApi) LoadLocalConn(c *gin.Context) { + connInfoInDB, err := settingService.GetSSHInfo() + if err != nil { + helper.InternalServer(c, err) + return + } + var data dto.SSHConnData + if err := json.Unmarshal([]byte(connInfoInDB), &data); err != nil { + helper.InternalServer(c, err) + return + } + if len(data.Password) != 0 { + data.Password = base64.StdEncoding.EncodeToString([]byte(data.Password)) + } + if len(data.PrivateKey) != 0 { + data.PrivateKey = base64.StdEncoding.EncodeToString([]byte(data.PrivateKey)) + } + if len(data.PassPhrase) != 0 { + data.PassPhrase = base64.StdEncoding.EncodeToString([]byte(data.PassPhrase)) + } + helper.SuccessWithData(c, data) +} + func (b *BaseApi) CheckLocalConn(c *gin.Context) { _, err := loadLocalConn() helper.SuccessWithData(c, err == nil) @@ -87,6 +115,7 @@ func (b *BaseApi) CheckLocalConnByInfo(c *gin.Context) { if err := helper.CheckBindAndValidate(&req, c); err != nil { return } + helper.SuccessWithData(c, settingService.TestConnByInfo(req)) } @@ -96,39 +125,20 @@ func (b *BaseApi) CheckLocalConnByInfo(c *gin.Context) { // @Security ApiKeyAuth // @Security Timestamp // @Router /settings/ssh [post] -func (b *BaseApi) SaveLocalConnInfo(c *gin.Context) { +func (b *BaseApi) SaveLocalConn(c *gin.Context) { var req dto.SSHConnData if err := helper.CheckBindAndValidate(&req, c); err != nil { return } - helper.SuccessWithData(c, settingService.SaveConnInfo(req)) + + if err := settingService.SaveConnInfo(req); err != nil { + helper.InternalServer(c, err) + return + } + helper.Success(c) } 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.CreateRootCert(dto.CreateRootCert{EncryptionMode: "ed25519", Name: "id_ed25519_1panel", Description: "1Panel Terminal"}) - } - - 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 @@ -136,11 +146,20 @@ func loadLocalConn() (*ssh.SSHClient, error) { if len(connInfoInDB) == 0 { return nil, errors.New("no such ssh conn info in db!") } - var connInDB ssh.ConnInfo + var connInDB model.LocalConnInfo if err := json.Unmarshal([]byte(connInfoInDB), &connInDB); err != nil { return nil, err } - return ssh.NewClient(connInDB) + sshInfo := ssh.ConnInfo{ + Addr: connInDB.Addr, + Port: int(connInDB.Port), + User: connInDB.User, + AuthMode: connInDB.AuthMode, + Password: connInDB.Password, + PrivateKey: []byte(connInDB.PrivateKey), + PassPhrase: []byte(connInDB.PassPhrase), + } + return ssh.NewClient(sshInfo) } // @Tags System Setting diff --git a/agent/app/model/setting.go b/agent/app/model/setting.go index 721ce42aa..a21a08f26 100644 --- a/agent/app/model/setting.go +++ b/agent/app/model/setting.go @@ -15,3 +15,13 @@ type NodeInfo struct { ServerCrt string `json:"serverCrt"` ServerKey string `json:"serverKey"` } + +type LocalConnInfo struct { + 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"` +} diff --git a/agent/app/service/setting.go b/agent/app/service/setting.go index 8240e3a54..b8c7a2249 100644 --- a/agent/app/service/setting.go +++ b/agent/app/service/setting.go @@ -143,6 +143,13 @@ func (u *SettingService) GetSettingByKey(key string) string { case "SystemIP": value, _ := settingRepo.GetValueByKey(key) return value + case "LocalSSHConn": + value, _ := settingRepo.GetValueByKey(key) + if len(value) == 0 { + return "" + } + itemStr, _ := encrypt.StringDecryptWithBase64(value) + return itemStr default: return "" } diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 80c5274ce..bef5e7bfd 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -39,6 +39,7 @@ func InitAgentDB() { migrations.UpdateWebsiteSSL, migrations.AddQuickJump, migrations.UpdateMcpServerAddType, + migrations.InitLocalSSHConn, }) 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 4da705642..987a88373 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -1,17 +1,23 @@ package migrations import ( + "encoding/json" "fmt" + "os" + "os/user" "path" "time" + "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/dto/request" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/service" "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/copier" "github.com/1Panel-dev/1Panel/agent/utils/encrypt" + "github.com/1Panel-dev/1Panel/agent/utils/ssh" "github.com/1Panel-dev/1Panel/agent/utils/xpack" "github.com/go-gormigrate/gormigrate/v2" @@ -510,3 +516,40 @@ var UpdateMcpServerAddType = &gormigrate.Migration{ return nil }, } + +var InitLocalSSHConn = &gormigrate.Migration{ + ID: "20250905-init-local-ssh", + Migrate: func(tx *gorm.DB) 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 { + _ = service.NewISSHService().CreateRootCert(dto.CreateRootCert{EncryptionMode: "ed25519", Name: "id_ed25519_1panel", Description: "1Panel Terminal"}) + } + privateKey, _ := os.ReadFile(itemPath) + connWithKey := ssh.ConnInfo{ + Addr: "127.0.0.1", + User: "root", + Port: 22, + AuthMode: "key", + PrivateKey: privateKey, + } + if _, err := ssh.NewClient(connWithKey); err != nil { + return nil + } + var conn model.LocalConnInfo + _ = copier.Copy(&conn, &connWithKey) + conn.PrivateKey = string(privateKey) + conn.PassPhrase = "" + localConn, _ := json.Marshal(&conn) + connAfterEncrypt, _ := encrypt.StringEncrypt(string(localConn)) + if err := tx.Model(&model.Setting{}).Where("key = ?", "LocalSSHConn").Updates(map[string]interface{}{"value": connAfterEncrypt}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/agent/router/ro_setting.go b/agent/router/ro_setting.go index 79686e669..a8cb5b46c 100644 --- a/agent/router/ro_setting.go +++ b/agent/router/ro_setting.go @@ -29,7 +29,8 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) { settingRouter.GET("/basedir", baseApi.LoadBaseDir) settingRouter.POST("/ssh/check", baseApi.CheckLocalConn) - settingRouter.POST("/ssh", baseApi.SaveLocalConnInfo) + settingRouter.GET("/ssh/conn", baseApi.LoadLocalConn) + settingRouter.POST("/ssh", baseApi.SaveLocalConn) settingRouter.POST("/ssh/check/info", baseApi.CheckLocalConnByInfo) } } diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 47077a708..5a0f7f0a8 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -47,6 +47,7 @@ export namespace Host { user: string; authMode: string; privateKey: string; + passPhrase: string; password: string; } export interface GroupChange { diff --git a/frontend/src/api/modules/terminal.ts b/frontend/src/api/modules/terminal.ts index 3ddf41fc9..b42b3b2d7 100644 --- a/frontend/src/api/modules/terminal.ts +++ b/frontend/src/api/modules/terminal.ts @@ -60,6 +60,9 @@ export const deleteHost = (params: { ids: number[] }) => { }; // agent +export const loadLocalConn = () => { + return http.get(`/settings/ssh/conn`); +}; 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 9ccb635ac..d4d254c60 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1165,6 +1165,8 @@ const message = { }, terminal: { local: 'Local', + defaultConn: 'Default Connection', + defaultConnHelper: 'Whether to connect to the host by default after opening the terminal', 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', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index afbd6a301..a1a79c0a3 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -1126,6 +1126,8 @@ const message = { }, terminal: { local: 'ローカル', + defaultConn: 'デフォルト接続', + defaultConnHelper: 'ターミナルを開いた後にデフォルトでホストに接続するかどうか', localHelper: 'ローカル名はシステムのローカル識別にのみ使用されます。', connLocalErr: '自動的に認証できない場合は、ローカルサーバーのログイン情報を入力してください。', testConn: 'テスト接続', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 342e80ccd..b204ea3d4 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -1118,6 +1118,8 @@ const message = { }, terminal: { local: '로컬', + defaultConn: '기본 연결', + defaultConnHelper: '터미널을 연 후 기본적으로 호스트에 연결할지 여부', localHelper: '로컬 이름은 시스템 로컬 식별에만 사용됩니다.', connLocalErr: '자동 인증에 실패했습니다. 로컬 서버 로그인 정보를 입력해주세요.', testConn: '연결 테스트', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 7cdb4b8d0..9c732d307 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -1154,6 +1154,8 @@ const message = { }, terminal: { local: 'Tempatan', + defaultConn: 'Sambungan Lalai', + defaultConnHelper: 'Sama ada untuk menyambung ke hos secara lalai selepas membuka terminal', 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', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 0dcfae212..d016b4089 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -1146,6 +1146,8 @@ const message = { }, terminal: { local: 'Local', + defaultConn: 'Conexão Padrão', + defaultConnHelper: 'Se deve conectar ao host por padrão após abrir o terminal', localHelper: 'O nome local é usado apenas para identificação local do sistema.', connLocalErr: 'Невозможно автоматически аутентифицироваться, пожалуйста, заполните информацию для входа на локальный сервер.', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index ab57b9479..9ddd275fa 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -1149,8 +1149,11 @@ const message = { }, terminal: { local: 'Локальный', + defaultConn: 'Соединение по умолчанию', + defaultConnHelper: 'Подключаться ли к хосту по умолчанию после открытия терминала', localHelper: 'Локальное имя используется только для локальной идентификации системы.', - connLocalErr: '無法自動認證,請填寫本地服務器的登錄信息!', + connLocalErr: + 'Невозможно выполнить автоматическую аутентификацию, пожалуйста, заполните информацию для входа на локальный сервер!', testConn: 'Проверить подключение', saveAndConn: 'Сохранить и подключиться', connTestOk: 'Информация о подключении доступна', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 1b1dc8301..ac02f12da 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -1178,6 +1178,8 @@ const message = { }, terminal: { local: 'Yerel', + defaultConn: 'Varsayılan Bağlantı', + defaultConnHelper: 'Terminal açıldıktan sonra varsayılan olarak ana bilgisayara bağlanılsın mı', localHelper: '`local` adı sadece sistem yerel tanımlaması için kullanılır', connLocalErr: 'Otomatik kimlik doğrulama yapılamıyor, lütfen yerel sunucu giriş bilgilerini doldurun.', testConn: 'Bağlantıyı test et', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index ad78b4142..2b9fb58f3 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -1110,6 +1110,8 @@ const message = { }, terminal: { local: '本機', + defaultConn: '預設連接', + defaultConnHelper: '開啟終端後是否預設連線到主機', localHelper: 'local 名稱僅用於系統本機標識', connLocalErr: '無法自動認證,請填寫本地服務器的登錄信息!', testConn: '連接測試', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 840684bdb..0adee0fe8 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1110,6 +1110,8 @@ const message = { }, terminal: { local: '本机', + defaultConn: '默认连接', + defaultConnHelper: '打开终端后是否默认连接主机', localHelper: 'local 名称仅用于系统本机标识', connLocalErr: '无法自动认证,请填写本地服务器的登录信息!', testConn: '连接测试', diff --git a/frontend/src/views/terminal/setting/default_conn/index.vue b/frontend/src/views/terminal/setting/default_conn/index.vue new file mode 100644 index 000000000..8c2170473 --- /dev/null +++ b/frontend/src/views/terminal/setting/default_conn/index.vue @@ -0,0 +1,146 @@ + + + diff --git a/frontend/src/views/terminal/setting/index.vue b/frontend/src/views/terminal/setting/index.vue index 13a66db8f..84480b6b4 100644 --- a/frontend/src/views/terminal/setting/index.vue +++ b/frontend/src/views/terminal/setting/index.vue @@ -78,6 +78,18 @@ @change="changeItem()" /> + + + {{ $t('terminal.defaultConnHelper') }} + + {{ $t('commons.button.view') }} + + {{ $t('commons.button.setDefault') }} @@ -90,14 +102,16 @@ +