From b962144e7d0a6d3acdced9dd9e3cfe1c73fd5b94 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Thu, 8 Oct 2026 14:06:40 +0800 Subject: [PATCH] fix(ssh): validate imported key pairs and cancel stale file reads (#13991) --- agent/app/api/v2/ssh.go | 2 + agent/app/dto/ssh.go | 2 +- agent/app/service/ssh.go | 83 ++++++-- agent/i18n/lang/en.yaml | 4 + agent/i18n/lang/es-ES.yaml | 4 + agent/i18n/lang/fa.yaml | 4 + agent/i18n/lang/ja.yaml | 4 + agent/i18n/lang/ko.yaml | 4 + agent/i18n/lang/lo.yaml | 4 + agent/i18n/lang/ms.yaml | 4 + agent/i18n/lang/pt-BR.yaml | 4 + agent/i18n/lang/ru.yaml | 4 + agent/i18n/lang/tr.yaml | 4 + agent/i18n/lang/zh-Hant.yaml | 4 + agent/i18n/lang/zh.yaml | 4 + frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/es-es.ts | 3 + frontend/src/lang/modules/fa.ts | 3 + frontend/src/lang/modules/ja.ts | 3 + frontend/src/lang/modules/ko.ts | 3 + frontend/src/lang/modules/lo.ts | 3 + frontend/src/lang/modules/ms.ts | 3 + frontend/src/lang/modules/pt-br.ts | 3 + frontend/src/lang/modules/ru.ts | 3 + frontend/src/lang/modules/tr.ts | 3 + frontend/src/lang/modules/zh-Hant.ts | 2 + frontend/src/lang/modules/zh.ts | 2 + .../ssh/ssh/certification/operate/index.vue | 178 ++++++++++++------ 28 files changed, 280 insertions(+), 67 deletions(-) diff --git a/agent/app/api/v2/ssh.go b/agent/app/api/v2/ssh.go index 6dbd1011a..5f6e1d78f 100644 --- a/agent/app/api/v2/ssh.go +++ b/agent/app/api/v2/ssh.go @@ -83,6 +83,7 @@ func (b *BaseApi) CreateRootCert(c *gin.Context) { } if err := loadCertAfterDecrypt(&req); err != nil { helper.BadRequest(c, err) + return } if err := sshService.CreateRootCert(req); err != nil { helper.InternalServer(c, err) @@ -107,6 +108,7 @@ func (b *BaseApi) EditRootCert(c *gin.Context) { } if err := loadCertAfterDecrypt(&req); err != nil { helper.BadRequest(c, err) + return } if err := sshService.EditRootCert(req); err != nil { helper.InternalServer(c, err) diff --git a/agent/app/dto/ssh.go b/agent/app/dto/ssh.go index de965539f..4b07386f9 100644 --- a/agent/app/dto/ssh.go +++ b/agent/app/dto/ssh.go @@ -25,7 +25,7 @@ type RootCertOperate struct { ID uint `json:"id"` Name string `json:"name"` Mode string `json:"mode"` - EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"` + EncryptionMode string `json:"encryptionMode"` PassPhrase string `json:"passPhrase"` PublicKey string `json:"publicKey"` PrivateKey string `json:"privateKey"` diff --git a/agent/app/service/ssh.go b/agent/app/service/ssh.go index d69ef9dfe..2f970d719 100644 --- a/agent/app/service/ssh.go +++ b/agent/app/service/ssh.go @@ -7,6 +7,7 @@ import ( "context" "encoding/base64" "encoding/json" + "encoding/pem" "fmt" "io" "net" @@ -37,6 +38,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/common" "github.com/1Panel-dev/1Panel/agent/utils/re" "github.com/pkg/errors" + "golang.org/x/crypto/ssh" ) const sshPath = "/etc/ssh/sshd_config" @@ -438,15 +440,33 @@ func (u *SSHService) SyncRootCert() error { global.LOG.Errorf("read pubic key of %s for sync failed, err: %v", item, err) continue } - cert.EncryptionMode = loadEncryptioMode(string(pubItem)) + publicKey, _, _, rest, err := ssh.ParseAuthorizedKey(pubItem) + if err != nil || len(bytes.TrimSpace(rest)) != 0 { + continue + } + cert.EncryptionMode = loadSSHKeyType(publicKey) + if cert.EncryptionMode == "" { + continue + } rootCerts = append(rootCerts, cert) } return hostRepo.SyncCert(rootCerts) } func (u *SSHService) CreateRootCert(req dto.RootCertOperate) error { - if cmd.CheckIllegal(req.EncryptionMode, req.PassPhrase) { - return buserr.New("ErrCmdIllegal") + switch req.Mode { + case "generate": + switch req.EncryptionMode { + case "rsa", "ed25519", "ecdsa", "dsa": + default: + return buserr.WithName("ErrNotSupportType", req.EncryptionMode) + } + case "input", "import": + if err := validateSSHKeyPair(&req); err != nil { + return err + } + default: + return buserr.WithName("ErrNotSupportType", req.Mode) } certItem, _ := hostRepo.GetCert(repo.WithByName(req.Name)) if certItem.ID != 0 { @@ -543,6 +563,9 @@ func (u *SSHService) CreateRootCert(req dto.RootCertOperate) error { } func (u *SSHService) EditRootCert(req dto.RootCertOperate) error { + if err := validateSSHKeyPair(&req); err != nil { + return err + } currentUser, err := user.Current() if err != nil { return fmt.Errorf("load current user failed, err: %v", err) @@ -1681,22 +1704,60 @@ func loadDate(currentYear int, DateStr string, nyc *time.Location) time.Time { return itemDate } -func loadEncryptioMode(content string) string { - if strings.HasPrefix(content, "ssh-rsa") { +func loadSSHKeyType(publicKey ssh.PublicKey) string { + switch publicKey.Type() { + case ssh.KeyAlgoRSA: return "rsa" - } - if strings.HasPrefix(content, "ssh-ed25519") { + case ssh.KeyAlgoED25519: return "ed25519" - } - if strings.HasPrefix(content, "ssh-ecdsa") { + case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: return "ecdsa" - } - if strings.HasPrefix(content, "ssh-dsa") { + case ssh.KeyAlgoDSA: return "dsa" } return "" } +func validateSSHKeyPair(req *dto.RootCertOperate) error { + req.PublicKey = strings.TrimSpace(req.PublicKey) + req.PrivateKey = strings.TrimSpace(req.PrivateKey) + if req.PublicKey == "" || strings.ContainsAny(req.PublicKey, "\r\n") { + return buserr.New("ErrSSHPublicKey") + } + publicKey, comment, options, rest, err := ssh.ParseAuthorizedKey([]byte(req.PublicKey)) + if err != nil || len(options) != 0 || len(bytes.TrimSpace(rest)) != 0 { + return buserr.New("ErrSSHPublicKey") + } + req.EncryptionMode = loadSSHKeyType(publicKey) + if req.EncryptionMode == "" { + return buserr.WithName("ErrNotSupportType", publicKey.Type()) + } + block, rest := pem.Decode([]byte(req.PrivateKey)) + if !strings.HasPrefix(req.PrivateKey, "-----BEGIN ") || block == nil || len(bytes.TrimSpace(rest)) != 0 { + return buserr.New("ErrSSHPrivateKey") + } + signer, err := ssh.ParsePrivateKey([]byte(req.PrivateKey)) + var missingPassphrase *ssh.PassphraseMissingError + if errors.As(err, &missingPassphrase) { + signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(req.PrivateKey), []byte(req.PassPhrase)) + } else if err == nil { + req.PassPhrase = "" + } + if err != nil { + return buserr.New("ErrSSHPrivateKey") + } + if !bytes.Equal(signer.PublicKey().Marshal(), publicKey.Marshal()) { + return buserr.New("ErrSSHKeyMismatch") + } + req.PublicKey = strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey))) + if comment != "" { + req.PublicKey += " " + comment + } + req.PublicKey += "\n" + req.PrivateKey += "\n" + return nil +} + func updateLocalConn(newPort uint) error { conn, _ := settingRepo.GetValueByKey("LocalSSHConn") if len(conn) == 0 { diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index e208725c9..0c6dad9ad 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Target filename: {{ .name }}' ErrFirewallBackendCleanupRequired: "The current backend {{ .current }} still contains 1Panel rules. Clean it up before switching to {{ .target }}." ErrDockerIPv4ForwardingDisabled: "IPv4 forwarding is disabled. Set net.ipv4.ip_forward=1 before using Docker's firewall backend." ErrFirewallRuleSavedApplyFailed: "The new rule configuration was saved, but applying it to the firewall failed. Retry by synchronizing: {{ .detail }}" + +ErrSSHPublicKey: "Enter a valid SSH public key" +ErrSSHPrivateKey: "Invalid SSH private key or incorrect passphrase; encrypted keys require the original passphrase" +ErrSSHKeyMismatch: "The SSH public and private keys do not match" diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 91467f1b0..4a4a52204 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Nombre del archivo de destino: {{ .name }}' ErrFirewallBackendCleanupRequired: "El backend actual {{ .current }} aún contiene reglas de 1Panel. Elimínelas antes de cambiar a {{ .target }}." ErrDockerIPv4ForwardingDisabled: "El reenvío IPv4 está desactivado. Configure net.ipv4.ip_forward=1 antes de usar el backend de cortafuegos de Docker." ErrFirewallRuleSavedApplyFailed: "Se guardó la configuración de la nueva regla, pero no se pudo aplicar al cortafuegos. Vuelva a intentarlo mediante la sincronización: {{ .detail }}" + +ErrSSHPublicKey: "Introduce una clave pública SSH válida" +ErrSSHPrivateKey: "Clave privada SSH no válida o contraseña incorrecta; las claves cifradas requieren la contraseña original" +ErrSSHKeyMismatch: "Las claves pública y privada SSH no coinciden" diff --git a/agent/i18n/lang/fa.yaml b/agent/i18n/lang/fa.yaml index 78ff0019a..a974edfc3 100644 --- a/agent/i18n/lang/fa.yaml +++ b/agent/i18n/lang/fa.yaml @@ -732,3 +732,7 @@ FileTaskRename: 'نام فایل مقصد: {{ .name }}' ErrFirewallBackendCleanupRequired: "بک‌اند فعلی {{ .current }} هنوز شامل قوانین 1Panel است. پیش از تغییر به {{ .target }} آن‌ها را پاک کنید." ErrDockerIPv4ForwardingDisabled: "ارسال IPv4 غیرفعال است. پیش از استفاده از بک‌اند فایروال Docker، مقدار net.ipv4.ip_forward=1 را تنظیم کنید." ErrFirewallRuleSavedApplyFailed: "پیکربندی قانون جدید ذخیره شد، اما اعمال آن در دیوار آتش ناموفق بود. با همگام‌سازی دوباره تلاش کنید: {{ .detail }}" + +ErrSSHPublicKey: "یک کلید عمومی SSH معتبر وارد کنید" +ErrSSHPrivateKey: "کلید خصوصی SSH نامعتبر یا عبارت عبور نادرست است؛ کلیدهای رمزگذاری‌شده به عبارت عبور اصلی نیاز دارند" +ErrSSHKeyMismatch: "کلید عمومی و خصوصی SSH مطابقت ندارند" diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 9653bfebb..47d72c815 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -731,3 +731,7 @@ FileTaskRename: '保存先ファイル名:{{ .name }}' ErrFirewallBackendCleanupRequired: "現在のバックエンド {{ .current }} に 1Panel ルールが残っています。{{ .target }} に切り替える前に削除してください。" ErrDockerIPv4ForwardingDisabled: "IPv4 転送が無効です。Docker のファイアウォールバックエンドを使用する前に net.ipv4.ip_forward=1 を設定してください。" ErrFirewallRuleSavedApplyFailed: "新しいルール設定は保存されましたが、ファイアウォールへの適用に失敗しました。同期で再試行してください:{{ .detail }}" + +ErrSSHPublicKey: "有効な SSH 公開鍵を入力してください" +ErrSSHPrivateKey: "SSH 秘密鍵の形式が無効か、パスフレーズが間違っています。暗号化された鍵には元のパスフレーズが必要です" +ErrSSHKeyMismatch: "SSH 公開鍵と秘密鍵が一致しません" diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index bd9aef612..1f72e42e9 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -731,3 +731,7 @@ FileTaskRename: '대상 파일 이름: {{ .name }}' ErrFirewallBackendCleanupRequired: "현재 백엔드 {{ .current }}에 1Panel 규칙이 남아 있습니다. {{ .target }}로 전환하기 전에 정리하세요." ErrDockerIPv4ForwardingDisabled: "IPv4 전달이 비활성화되어 있습니다. Docker 방화벽 백엔드를 사용하기 전에 net.ipv4.ip_forward=1을 설정하세요." ErrFirewallRuleSavedApplyFailed: "새 규칙 설정이 저장되었지만 방화벽에 적용하지 못했습니다. 동기화하여 다시 시도하세요: {{ .detail }}" + +ErrSSHPublicKey: "유효한 SSH 공개 키를 입력하세요" +ErrSSHPrivateKey: "SSH 개인 키 형식이 잘못되었거나 암호가 틀립니다. 암호화된 키에는 원래 암호가 필요합니다" +ErrSSHKeyMismatch: "SSH 공개 키와 개인 키가 일치하지 않습니다" diff --git a/agent/i18n/lang/lo.yaml b/agent/i18n/lang/lo.yaml index 1875c8c7f..77fd89f8b 100644 --- a/agent/i18n/lang/lo.yaml +++ b/agent/i18n/lang/lo.yaml @@ -722,3 +722,7 @@ FileTaskRename: 'ຊື່ໄຟລ໌ປາຍທາງ: {{ .name }}' ErrFirewallBackendCleanupRequired: "ແບັກເອນປັດຈຸບັນ {{ .current }} ຍັງມີກົດຂອງ 1Panel. ກະລຸນາລຶບອອກກ່ອນປ່ຽນໄປ {{ .target }}." ErrDockerIPv4ForwardingDisabled: "ການສົ່ງຕໍ່ IPv4 ຖືກປິດ. ກະລຸນາຕັ້ງ net.ipv4.ip_forward=1 ກ່ອນໃຊ້ແບັກເອນໄຟວໍຂອງ Docker." ErrFirewallRuleSavedApplyFailed: "ບັນທຶກການຕັ້ງຄ່າກົດໃໝ່ແລ້ວ ແຕ່ນຳໃຊ້ກັບໄຟວໍບໍ່ສຳເລັດ. ລອງອີກຄັ້ງດ້ວຍການຊິງຂໍ້ມູນ: {{ .detail }}" + +ErrSSHPublicKey: "ກະລຸນາປ້ອນຄີສາທາລະນະ SSH ທີ່ຖືກຕ້ອງ" +ErrSSHPrivateKey: "ຄີສ່ວນຕົວ SSH ບໍ່ຖືກຕ້ອງ ຫຼື ລະຫັດຜ່ານຜິດ; ຄີທີ່ເຂົ້າລະຫັດຕ້ອງໃຊ້ລະຫັດຜ່ານເດີມ" +ErrSSHKeyMismatch: "ຄີສາທາລະນະ ແລະ ຄີສ່ວນຕົວ SSH ບໍ່ກົງກັນ" diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index dd261ff94..2e90ec676 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Nama fail sasaran: {{ .name }}' ErrFirewallBackendCleanupRequired: "Bahagian belakang semasa {{ .current }} masih mengandungi peraturan 1Panel. Buangkannya sebelum beralih kepada {{ .target }}." ErrDockerIPv4ForwardingDisabled: "Pemajuan IPv4 dilumpuhkan. Tetapkan net.ipv4.ip_forward=1 sebelum menggunakan bahagian belakang tembok api Docker." ErrFirewallRuleSavedApplyFailed: "Konfigurasi peraturan baharu telah disimpan, tetapi gagal digunakan pada tembok api. Cuba lagi melalui penyegerakan: {{ .detail }}" + +ErrSSHPublicKey: "Masukkan kunci awam SSH yang sah" +ErrSSHPrivateKey: "Kunci peribadi SSH tidak sah atau frasa laluan salah; kunci yang disulitkan memerlukan frasa laluan asal" +ErrSSHKeyMismatch: "Kunci awam dan peribadi SSH tidak sepadan" diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index a8a2544a7..9b9d7da92 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Nome do arquivo de destino: {{ .name }}' ErrFirewallBackendCleanupRequired: "O backend atual {{ .current }} ainda contém regras do 1Panel. Remova-as antes de mudar para {{ .target }}." ErrDockerIPv4ForwardingDisabled: "O encaminhamento IPv4 está desativado. Defina net.ipv4.ip_forward=1 antes de usar o backend de firewall do Docker." ErrFirewallRuleSavedApplyFailed: "A configuração da nova regra foi salva, mas não pôde ser aplicada ao firewall. Tente novamente por meio da sincronização: {{ .detail }}" + +ErrSSHPublicKey: "Informe uma chave pública SSH válida" +ErrSSHPrivateKey: "Chave privada SSH inválida ou senha incorreta; chaves criptografadas exigem a senha original" +ErrSSHKeyMismatch: "As chaves pública e privada SSH não correspondem" diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 89ed5305e..ad6838b31 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Имя целевого файла: {{ .name }}' ErrFirewallBackendCleanupRequired: "В текущем бэкенде {{ .current }} остались правила 1Panel. Удалите их перед переключением на {{ .target }}." ErrDockerIPv4ForwardingDisabled: "Пересылка IPv4 отключена. Перед использованием бэкенда межсетевого экрана Docker установите net.ipv4.ip_forward=1." ErrFirewallRuleSavedApplyFailed: "Настройки нового правила сохранены, но применить их к межсетевому экрану не удалось. Повторите попытку с помощью синхронизации: {{ .detail }}" + +ErrSSHPublicKey: "Введите действительный открытый ключ SSH" +ErrSSHPrivateKey: "Недопустимый закрытый ключ SSH или неверная парольная фраза; для зашифрованных ключей требуется исходная парольная фраза" +ErrSSHKeyMismatch: "Открытый и закрытый ключи SSH не соответствуют друг другу" diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index ca8140314..adf567a5b 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -731,3 +731,7 @@ FileTaskRename: 'Hedef dosya adı: {{ .name }}' ErrFirewallBackendCleanupRequired: "Mevcut {{ .current }} arka ucunda hâlâ 1Panel kuralları var. {{ .target }} arka ucuna geçmeden önce bunları temizleyin." ErrDockerIPv4ForwardingDisabled: "IPv4 yönlendirmesi devre dışı. Docker güvenlik duvarı arka ucunu kullanmadan önce net.ipv4.ip_forward=1 ayarını yapın." ErrFirewallRuleSavedApplyFailed: "Yeni kural yapılandırması kaydedildi, ancak güvenlik duvarına uygulanamadı. Eşitleme yaparak yeniden deneyin: {{ .detail }}" + +ErrSSHPublicKey: "Geçerli bir SSH açık anahtarı girin" +ErrSSHPrivateKey: "SSH özel anahtarı geçersiz veya parola yanlış; şifreli anahtarlar mevcut parolayı gerektirir" +ErrSSHKeyMismatch: "SSH açık ve özel anahtarları eşleşmiyor" diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index ae7d9b747..79d190076 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -731,3 +731,7 @@ FileTaskRename: '目標檔名:{{ .name }}' ErrFirewallBackendCleanupRequired: "目前後端 {{ .current }} 中仍有 1Panel 規則,請先清理後再切換至 {{ .target }}。" ErrDockerIPv4ForwardingDisabled: "IPv4 轉送尚未啟用,請先設定 net.ipv4.ip_forward=1,再使用 Docker 防火牆後端。" ErrFirewallRuleSavedApplyFailed: "新規則設定已儲存,但套用至防火牆失敗。可透過同步重試:{{ .detail }}" + +ErrSSHPublicKey: "請輸入有效的 SSH 公鑰" +ErrSSHPrivateKey: "SSH 私鑰格式無效或密碼錯誤;加密私鑰需要填寫原密碼" +ErrSSHKeyMismatch: "SSH 公鑰與私鑰不相符" diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 00852883d..4a7ef3db2 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -731,3 +731,7 @@ FileTaskRename: '目标文件名:{{ .name }}' ErrFirewallBackendCleanupRequired: "当前后端 {{ .current }} 中仍有 1Panel 规则,请先清理后再切换到 {{ .target }}。" ErrDockerIPv4ForwardingDisabled: "IPv4 转发未开启,请先设置 net.ipv4.ip_forward=1,再使用 Docker 防火墙后端。" ErrFirewallRuleSavedApplyFailed: "新规则配置已保存,但应用到防火墙失败。可通过同步重试:{{ .detail }}" + +ErrSSHPublicKey: "请输入有效的 SSH 公钥" +ErrSSHPrivateKey: "SSH 私钥格式无效或密码错误;加密私钥需要填写原密码" +ErrSSHKeyMismatch: "SSH 公钥与私钥不匹配" diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index f2a43c34a..14b75ce5f 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -2888,6 +2888,9 @@ const message = { privateKey: 'Private Key', publicKey: 'Public Key', password: 'Password', + existingPassPhrase: 'Existing private key passphrase', + existingPassPhraseHelper: + 'Enter the original passphrase if the private key is encrypted; otherwise leave blank. This does not change the passphrase.', createMode: 'Creation Method', generate: 'Auto-generate', unSyncPass: 'Key password cannot be synchronized', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index cdabe72a4..4be0207ce 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -2930,6 +2930,9 @@ const message = { privateKey: 'Clave privada', publicKey: 'Clave pública', password: 'Contraseña', + existingPassPhrase: 'Contraseña actual de la clave privada', + existingPassPhraseHelper: + 'Introduce la contraseña original si la clave privada está cifrada; en caso contrario, deja el campo vacío. Esto no cambia la contraseña.', createMode: 'Método de creación', generate: 'Autogenerar', unSyncPass: 'La contraseña de la clave no se puede sincronizar', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index d47aecd2a..1ef3bc82a 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -2861,6 +2861,9 @@ const message = { privateKey: 'کلید خصوصی', publicKey: 'کلید عمومی', password: 'رمز عبور', + existingPassPhrase: 'عبارت عبور فعلی کلید خصوصی', + existingPassPhraseHelper: + 'اگر کلید خصوصی رمزگذاری شده است، عبارت عبور اصلی را وارد کنید؛ در غیر این صورت خالی بگذارید. این کار عبارت عبور را تغییر نمی‌دهد.', createMode: 'روش ایجاد', generate: 'تولید خودکار', unSyncPass: 'رمز عبور کلید قابل همگام‌سازی نیست', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 819866e7a..ba3336f96 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -2865,6 +2865,9 @@ const message = { privateKey: '秘密鍵', publicKey: '公開鍵', password: 'パスワード', + existingPassPhrase: '既存の秘密鍵のパスフレーズ', + existingPassPhraseHelper: + '秘密鍵が暗号化されている場合は元のパスフレーズを入力し、それ以外は空欄にしてください。パスフレーズは変更されません。', createMode: '作成方法', generate: '自動生成', unSyncPass: '鍵パスワードは同期できません', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 22cf61f59..24725ebe7 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -2827,6 +2827,9 @@ const message = { privateKey: '개인 키', publicKey: '공개 키', password: '비밀번호', + existingPassPhrase: '기존 개인 키 암호', + existingPassPhraseHelper: + '개인 키가 암호화되어 있으면 원래 암호를 입력하고, 그렇지 않으면 비워 두세요. 이 작업은 암호를 변경하지 않습니다.', createMode: '생성 방식', generate: '자동 생성', unSyncPass: '키 비밀번호 동기화 불가', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index 12e16868a..40038f6bd 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -2807,6 +2807,9 @@ const message = { privateKey: 'ຄີສ່ວນຕົວ', publicKey: 'ຄີສາທາລະນະ', password: 'ລະຫັດຜ່ານ', + existingPassPhrase: 'ລະຫັດຜ່ານເດີມຂອງຄີສ່ວນຕົວ', + existingPassPhraseHelper: + 'ຖ້າຄີສ່ວນຕົວຖືກເຂົ້າລະຫັດ ໃຫ້ປ້ອນລະຫັດຜ່ານເດີມ; ຖ້າບໍ່ ໃຫ້ປະໄວ້ຫວ່າງ. ການດຳເນີນການນີ້ບໍ່ປ່ຽນລະຫັດຜ່ານ.', createMode: 'ວິທີການສ້າງ', generate: 'ສ້າງອັດຕະໂນມັດ', unSyncPass: 'ບໍ່ສາມາດຊິງຄ໌ລະຫັດຜ່ານຄີໄດ້', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 2a6054108..ae6b54ebe 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -2930,6 +2930,9 @@ const message = { privateKey: 'Kunci Persendirian', publicKey: 'Kunci Awam', password: 'Kata Laluan', + existingPassPhrase: 'Frasa laluan kunci peribadi sedia ada', + existingPassPhraseHelper: + 'Masukkan frasa laluan asal jika kunci peribadi disulitkan; jika tidak, biarkan kosong. Ini tidak mengubah frasa laluan.', createMode: 'Kaedah Penciptaan', generate: 'Jana Automatik', unSyncPass: 'Kata laluan kunci tidak dapat diselaraskan', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index fd5a60def..fc4d6a39f 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -2929,6 +2929,9 @@ const message = { privateKey: 'Chave Privada', publicKey: 'Chave Pública', password: 'Senha', + existingPassPhrase: 'Senha atual da chave privada', + existingPassPhraseHelper: + 'Informe a senha original se a chave privada estiver criptografada; caso contrário, deixe em branco. Isso não altera a senha.', createMode: 'Método de Criação', generate: 'Gerar Automaticamente', unSyncPass: 'Senha da chave não pode ser sincronizada', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index f7b45cba4..feef1be02 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -2903,6 +2903,9 @@ const message = { privateKey: 'Приватный ключ', publicKey: 'Публичный ключ', password: 'Пароль', + existingPassPhrase: 'Текущая парольная фраза закрытого ключа', + existingPassPhraseHelper: + 'Если закрытый ключ зашифрован, введите исходную парольную фразу; иначе оставьте поле пустым. Это не изменяет парольную фразу.', createMode: 'Способ создания', generate: 'Автогенерация', unSyncPass: 'Пароль ключа не может быть синхронизирован', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 965ebd937..a8f2887fa 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -2921,6 +2921,9 @@ const message = { privateKey: 'Özel Anahtar', publicKey: 'Genel Anahtar', password: 'Parola', + existingPassPhrase: 'Mevcut özel anahtar parolası', + existingPassPhraseHelper: + 'Özel anahtar şifreliyse mevcut parolayı girin; değilse boş bırakın. Bu işlem parolayı değiştirmez.', createMode: 'Oluşturma Yöntemi', generate: 'Otomatik Oluştur', unSyncPass: 'Anahtar parolası senkronize edilemez', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 537457e7f..216b070a4 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -2720,6 +2720,8 @@ const message = { privateKey: '私鑰', publicKey: '公鑰', password: '密碼', + existingPassPhrase: '現有私鑰密碼', + existingPassPhraseHelper: '私鑰已加密時填寫原密碼,未加密則留空;此處不會修改私鑰密碼。', createMode: '建立方式', generate: '自動生成', unSyncPass: '金鑰密碼無法同步', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 8fc0dafc6..dd0e77f5c 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -2751,6 +2751,8 @@ const message = { privateKey: '私钥', publicKey: '公钥', password: '密码', + existingPassPhrase: '已有私钥密码', + existingPassPhraseHelper: '私钥已加密时填写原密码,未加密则留空;此处不会修改私钥密码。', createMode: '创建方式', generate: '自动生成', unSyncPass: '密钥密码无法同步', diff --git a/frontend/src/views/host/ssh/ssh/certification/operate/index.vue b/frontend/src/views/host/ssh/ssh/certification/operate/index.vue index 097a60a2c..5a28ac7ea 100644 --- a/frontend/src/views/host/ssh/ssh/certification/operate/index.vue +++ b/frontend/src/views/host/ssh/ssh/certification/operate/index.vue @@ -16,8 +16,15 @@ + + + {{ $t('ssh.generate') }} + {{ $t('ssh.input') }} + {{ $t('ssh.import') }} + + - + @@ -28,50 +35,38 @@ - + -