mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-09 16:23:27 +08:00
🐛 fix(ssh): 修复非 id_rsa 私钥无法浏览选择与读取
- 修正 OpenFileDialog 默认目录,支持无扩展名密钥路径 - macOS 下取消错误文件名过滤,显示隐藏项以选择 ~/.ssh 密钥 - 私钥读/解析失败返回明确错误,示例改为 id_ed25519 - 补充选钥目录解析与私钥读取失败回归测试 Refs #711
This commit is contained in:
@@ -4,11 +4,13 @@ import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -59,18 +61,22 @@ func connectSSH(config connection.SSHConfig) (*ssh.Client, error) {
|
||||
logger.Infof("开始建立 SSH 连接:地址=%s:%d 用户=%s", config.Host, config.Port, config.User)
|
||||
authMethods := []ssh.AuthMethod{}
|
||||
|
||||
if config.KeyPath != "" {
|
||||
key, err := os.ReadFile(config.KeyPath)
|
||||
if keyPath := strings.TrimSpace(config.KeyPath); keyPath != "" {
|
||||
key, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
logger.Warnf("读取 SSH 私钥失败:路径=%s,原因:%v", config.KeyPath, err)
|
||||
} else {
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
logger.Warnf("解析 SSH 私钥失败:路径=%s,原因:%v", config.KeyPath, err)
|
||||
} else {
|
||||
authMethods = append(authMethods, ssh.PublicKeys(signer))
|
||||
}
|
||||
logger.Warnf("读取 SSH 私钥失败:路径=%s,原因:%v", keyPath, err)
|
||||
return nil, fmt.Errorf("failed to read SSH private key %s: %w", keyPath, err)
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
logger.Warnf("解析 SSH 私钥失败:路径=%s,原因:%v", keyPath, err)
|
||||
var passphraseErr *ssh.PassphraseMissingError
|
||||
if errors.As(err, &passphraseErr) {
|
||||
return nil, fmt.Errorf("SSH private key %s is encrypted with a passphrase; passphrase-protected keys are not supported", keyPath)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to parse SSH private key %s: %w", keyPath, err)
|
||||
}
|
||||
authMethods = append(authMethods, ssh.PublicKeys(signer))
|
||||
}
|
||||
|
||||
if config.Password != "" {
|
||||
|
||||
58
internal/ssh/ssh_key_read_test.go
Normal file
58
internal/ssh/ssh_key_read_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"GoNavi-Wails/internal/connection"
|
||||
)
|
||||
|
||||
func TestConnectSSHReturnsErrorWhenPrivateKeyMissing(t *testing.T) {
|
||||
t.Cleanup(CloseAllSSHClients)
|
||||
|
||||
missing := filepath.Join(t.TempDir(), "id_ed25519")
|
||||
_, err := connectSSH(connection.SSHConfig{
|
||||
Host: "127.0.0.1",
|
||||
Port: 1,
|
||||
User: "root",
|
||||
KeyPath: missing,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing private key")
|
||||
}
|
||||
message := err.Error()
|
||||
if !strings.Contains(message, "failed to read SSH private key") {
|
||||
t.Fatalf("expected read failure message, got %q", message)
|
||||
}
|
||||
if !strings.Contains(message, missing) {
|
||||
t.Fatalf("expected key path in error, got %q", message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectSSHReturnsErrorWhenPrivateKeyInvalid(t *testing.T) {
|
||||
t.Cleanup(CloseAllSSHClients)
|
||||
|
||||
keyPath := filepath.Join(t.TempDir(), "custom_deploy_key")
|
||||
if err := os.WriteFile(keyPath, []byte("not-a-private-key"), 0o600); err != nil {
|
||||
t.Fatalf("write key: %v", err)
|
||||
}
|
||||
|
||||
_, err := connectSSH(connection.SSHConfig{
|
||||
Host: "127.0.0.1",
|
||||
Port: 1,
|
||||
User: "root",
|
||||
KeyPath: keyPath,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid private key")
|
||||
}
|
||||
message := err.Error()
|
||||
if !strings.Contains(message, "failed to parse SSH private key") {
|
||||
t.Fatalf("expected parse failure message, got %q", message)
|
||||
}
|
||||
if !strings.Contains(message, keyPath) {
|
||||
t.Fatalf("expected key path in error, got %q", message)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user