1 Star 0 Fork 0

wait4me/selfGoLib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
ssh.go 5.70 KB
一键复制 编辑 原始数据 按行查看 历史
wait4me 提交于 2026-02-11 14:06 +08:00 . feat: initial release of selfGoLib toolkit
package sshUtil
import (
"errors"
"fmt"
"io"
"log/slog"
"os"
"path/filepath"
"syscall"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/term"
)
// SshClient 创建一个SSH客户端连接。
// 参数:
// - user: 登录用户名,如果为空会提示输入。
// - password: 登录密码,如果为空会提示输入。
// - host: 目标主机地址。
// - port: 目标主机端口。
//
// 返回:
// - *ssh.Client: SSH客户端实例。
// - error: 错误信息。
func SshClient(user, password, host string, port int) (*ssh.Client, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
sshClient *ssh.Client
err error
)
if len(user) == 0 {
fmt.Printf("请输入登陆[%s]的用户名:\n", host)
fmt.Scanln(&user)
}
if len(password) == 0 {
fmt.Printf("请输入登陆[%s]的用户密码:\n", host)
p1, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return nil, fmt.Errorf("读取登陆用户密码失败:%w", err)
}
password = string(p1)
}
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
// 创建 SSH 登录配置
clientConfig = &ssh.ClientConfig{
Timeout: 10 * time.Second,
User: user,
Auth: auth,
// 注意:使用 InsecureIgnoreHostKey 跳过主机密钥验证,存在中间人攻击风险
// 生产环境建议使用 ssh.FixedHostKey 或 known_hosts 文件验证
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
addr = fmt.Sprintf("%s:%d", host, port)
sshClient, err = ssh.Dial("tcp", addr, clientConfig)
if err != nil {
return nil, fmt.Errorf("连接SSH服务器失败: %w", err)
}
return sshClient, nil
}
// SshSession 创建一个SSH会话。
// 参数:
// - c: SSH客户端实例。
//
// 返回:
// - *ssh.Session: SSH会话实例。
// - error: 错误信息。
func SshSession(c *ssh.Client) (*ssh.Session, error) {
if c == nil {
return nil, errors.New("未获取ssh客户端连接")
}
// 创建 SSH 会话
session, err := c.NewSession()
if err != nil {
return nil, fmt.Errorf("创建SSH会话失败: %w", err)
}
return session, nil
}
// SFtpClient 创建一个SFTP客户端连接。
// 参数:
// - c: SSH客户端实例。
//
// 返回:
// - *sftp.Client: SFTP客户端实例。
// - error: 错误信息。
func SFtpClient(c *ssh.Client) (*sftp.Client, error) {
var sftpClient *sftp.Client
if c == nil {
return nil, errors.New("未获取ssh客户端连接")
}
sftpClient, err := sftp.NewClient(c)
if err != nil {
return nil, fmt.Errorf("创建SFTP客户端失败: %w", err)
}
return sftpClient, nil
}
// sftpFileExists 检查远程文件是否存在。
// 参数:
// - sftpClient: SFTP客户端实例。
// - path: 远程文件路径。
//
// 返回:
// - bool: 文件是否存在。
func sftpFileExists(sftpClient *sftp.Client, path string) bool {
_, err := sftpClient.Stat(filepath.ToSlash(path))
if err != nil {
if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENXIO {
return false
}
// 其他错误(如权限拒绝、网络错误)记录日志,但默认返回 false
slog.Debug("检查文件存在性时遇到错误", "path", path, "error", err.Error())
return false
}
return true
}
// SFtpDetectOS 检测远程主机的操作系统类型。
// 参数:
// - sftpClient: SFTP客户端实例。
//
// 返回:
// - string: 操作系统类型("linux"、"mac"、"Windows" 或 "unknown")。
func SFtpDetectOS(sftpClient *sftp.Client) string {
// 方法1:通过特定文件的存在性判断
if sftpFileExists(sftpClient, "/etc/os-release") {
return "linux"
} else if sftpFileExists(sftpClient, "/System/Library/CoreServices/SystemVersion.plist") {
return "mac"
} else if sftpFileExists(sftpClient, "C:\\Windows\\System32\\kernel32.dll") {
return "Windows"
}
return "unknown"
}
// SFtpUpload 上传本地文件到远程主机。
// 参数:
// - sftpClient: SFTP客户端实例。
// - l: 本地文件路径。
// - r: 远程文件路径。
//
// 返回:
// - error: 错误信息。
func SFtpUpload(sftpClient *sftp.Client, l, r string) error {
if sftpClient == nil {
return errors.New("未连接目标服务器,无法上传文件")
}
srcFile, err := os.Open(l)
if err != nil {
return fmt.Errorf("打开本地文件失败: %w", err)
}
defer srcFile.Close()
r = filepath.ToSlash(r)
rDir := filepath.ToSlash(filepath.Dir(r))
slog.Debug("检查目标文件所在目录是否存在", "dir", rDir)
if _, err := sftpClient.Lstat(rDir); err != nil {
if errMakeDir := sftpClient.MkdirAll(rDir); errMakeDir != nil {
return fmt.Errorf("创建目标目录 %s 失败: %w", rDir, errMakeDir)
}
}
dstFile, err := sftpClient.Create(r)
if err != nil {
return fmt.Errorf("创建远端文件失败: %w", err)
}
defer dstFile.Close()
if _, err := io.Copy(dstFile, srcFile); err != nil {
return fmt.Errorf("拷贝文件失败: %w", err)
}
return nil
}
// SFtpDownload 从远程主机下载文件到本地。
// 参数:
// - sftpClient: SFTP客户端实例。
// - l: 本地文件路径。
// - r: 远程文件路径。
//
// 返回:
// - error: 错误信息。
func SFtpDownload(sftpClient *sftp.Client, l, r string) error {
if sftpClient == nil {
return errors.New("未连接目标服务器,无法下载文件")
}
srcFile, err := sftpClient.Open(r)
if err != nil {
return fmt.Errorf("打开远端文件失败: %w", err)
}
defer srcFile.Close()
dstFile, err := os.Create(l)
if err != nil {
return fmt.Errorf("创建本地文件失败: %w", err)
}
defer dstFile.Close()
if _, err = srcFile.WriteTo(dstFile); err != nil {
return fmt.Errorf("写入本地文件失败: %w", err)
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/wait4me/selfGoLib.git
git@gitee.com:wait4me/selfGoLib.git
wait4me
selfGoLib
selfGoLib
v1.0.3

搜索帮助