- SFTP模块:连接/断开/文件CRUD/系统信息采集/base64二进制写入 - 连接池:多服务器同时在线,瞬间切换profile - autoConnect:启动时自动连接所有非本地服务器 - 端口自动回退:listenWithFallback消除TOCTOU,解决端口冲突崩溃 - 文件服务器URL集中管理:file-server.ts消除8+处硬编码端口 - Sidebar设置面板:添加服务器/自动连接/自动刷新开关 - 修复:validateFilePath越界panic、正则预编译 - 修复:注释准确性(RemoveAll/端口8073/动态端口文档)
70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
package sftp
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ConnectionError SFTP 连接错误(区分阶段)
|
|
type ConnectionError struct {
|
|
Op string // dial / handshake / auth / sftp_init
|
|
Err error
|
|
}
|
|
|
|
func (e *ConnectionError) Error() string {
|
|
return fmt.Sprintf("SFTP 连接失败 [%s]: %v", e.Op, e.Err)
|
|
}
|
|
|
|
func (e *ConnectionError) Unwrap() error { return e.Err }
|
|
|
|
// ToUserMessage 将底层错误转换为用户友好的中文错误(返回 error 类型)
|
|
func ToUserMessage(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var connErr *ConnectionError
|
|
if errors.As(err, &connErr) {
|
|
switch connErr.Op {
|
|
case "dial":
|
|
return fmt.Errorf("无法连接到服务器 (%v)。请检查地址和端口是否正确", connErr.Err)
|
|
case "handshake":
|
|
return fmt.Errorf("SSH 握手失败,请检查服务是否正常运行")
|
|
case "auth":
|
|
return fmt.Errorf("认证失败,请检查用户名和密码/密钥是否正确")
|
|
case "sftp_init":
|
|
return fmt.Errorf("SFTP 子系统初始化失败,请确认远程服务器支持 SFTP")
|
|
}
|
|
}
|
|
|
|
msg := err.Error()
|
|
switch {
|
|
case strings.Contains(msg, "unable authenticate"), strings.Contains(msg, "no auth method"):
|
|
return fmt.Errorf("认证失败:用户名或密码/密钥不正确")
|
|
case strings.Contains(msg, "connection refused"):
|
|
return fmt.Errorf("连接被拒绝:目标机器可能未开启 SSH 服务")
|
|
case strings.Contains(msg, "timeout"), strings.Contains(msg, "i/o timeout"):
|
|
return fmt.Errorf("连接超时:请检查网络连通性或防火墙设置")
|
|
case strings.Contains(msg, "host key mismatch"):
|
|
return fmt.Errorf("主机密钥不匹配:可能存在中间人攻击风险")
|
|
case strings.Contains(msg, "permission denied"):
|
|
return fmt.Errorf("权限不足:当前用户无权访问该资源")
|
|
case strings.Contains(msg, "no such file"), strings.Contains(msg, "not found"):
|
|
return fmt.Errorf("文件或目录不存在")
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
|
|
// isNetworkError 判断是否为网络层错误(需要重连)
|
|
func isNetworkError(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
msg := strings.ToLower(err.Error())
|
|
return strings.Contains(msg, "broken pipe") ||
|
|
strings.Contains(msg, "connection reset") ||
|
|
strings.Contains(msg, "timeout")
|
|
}
|