1
0

merge: 合并代码20240531

This commit is contained in:
TsMask
2024-06-01 18:56:18 +08:00
parent 3cc193f57d
commit 3b50e2f3f8
129 changed files with 3705 additions and 11065 deletions

View File

@@ -1,7 +1,7 @@
# 项目信息
framework:
name: "CN EMS"
version: "2.2404.6"
version: "2.2405.4"
# 应用服务配置
server:
@@ -15,7 +15,7 @@ logger:
fileDir: "/var/log"
fileName: "omc.log"
level: 2 # 日志记录的等级 0:silent<1:info<2:warn<3:error
maxDay: 180 # 日志会保留 180 天
maxDay: 7 # 日志会保留 180 天
maxSize: 10 # 调整按 10MB 大小的切割
# 静态文件配置, 相对项目根路径或填绝对路径

View File

@@ -19,3 +19,6 @@ const STATUS_NO = "0"
// 上下文信息-登录用户
const CTX_LOGIN_USER = "loginuser"
// 启动-引导系统初始
const LAUNCH_BOOTLOADER = "bootloader"

View File

@@ -34,7 +34,7 @@ const (
// NewLogger 实例日志器对象
func NewLogger(env, fileDir, fileName string, level, maxDay, maxSize int) (*Logger, error) {
logFilePath := filepath.Join(fileDir, fileName)
if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(logFilePath), 0775); err != nil {
return nil, fmt.Errorf("failed to mkdir logger dir: %v", err)
}
fileHandle, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

View File

@@ -10,21 +10,17 @@ import (
"io"
)
// aesKey 字符串AES加解密密钥
const aesKey = "AGT66VfY4SMaiT97"
// StringEncryptByAES 字符串AES加密
func StringEncryptByAES(text string) (string, error) {
if len(text) == 0 {
return "", nil
}
pass := []byte(text)
xpass, err := aesEncryptWithSalt([]byte(aesKey), pass)
if err == nil {
pass64 := base64.StdEncoding.EncodeToString(xpass)
return pass64, err
xpass, err := aesEncryptWithSalt([]byte(text))
if err != nil {
return "", err
}
return "", err
pass64 := base64.StdEncoding.EncodeToString(xpass)
return pass64, nil
}
// StringDecryptByAES 字符串AES解密
@@ -36,53 +32,70 @@ func StringDecryptByAES(text string) (string, error) {
if err != nil {
return "", err
}
var tpass []byte
tpass, err = aesDecryptWithSalt([]byte(aesKey), bytesPass)
if err == nil {
result := string(tpass[:])
return result, err
tpass, err := aesDecryptWithSalt(bytesPass)
if err != nil {
return "", err
}
return "", err
return string(tpass), nil
}
// aesEncryptWithSalt AES加密
func aesEncryptWithSalt(key, plaintext []byte) ([]byte, error) {
blockSize := aes.BlockSize
padding := blockSize - len(plaintext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
plaintext = append(plaintext, padtext...)
// aesKey 字符串AES加解密密钥
const aesKey = "AGT66VfY4SMaiT97a7df0aef1704d5c5"
block, err := aes.NewCipher(key)
// const aesKey = "AGT66VfY4SMaiT97"
// aesEncryptWithSalt AES加密
func aesEncryptWithSalt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return nil, err
}
blockSize := aes.BlockSize
padding := blockSize - (len(plaintext) % blockSize)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
plaintext = append(plaintext, padtext...)
ciphertext := make([]byte, blockSize+len(plaintext))
iv := ciphertext[0:blockSize]
iv := ciphertext[:blockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cbc := cipher.NewCBCEncrypter(block, iv)
cbc.CryptBlocks(ciphertext[blockSize:], plaintext)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[blockSize:], plaintext)
return ciphertext, nil
}
// aesDecryptWithSalt AES解密
func aesDecryptWithSalt(key, ciphertext []byte) ([]byte, error) {
func aesDecryptWithSalt(ciphertext []byte) ([]byte, error) {
blockSize := aes.BlockSize
var block cipher.Block
block, err := aes.NewCipher(key)
if len(ciphertext) < blockSize {
return nil, fmt.Errorf("ciphertext too short")
}
iv := ciphertext[:blockSize]
ciphertext = ciphertext[blockSize:]
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return nil, err
}
if len(ciphertext) < blockSize {
return nil, fmt.Errorf("iciphertext too short")
if len(ciphertext)%blockSize != 0 {
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
}
iv := ciphertext[:blockSize]
ciphertext = ciphertext[blockSize:]
cbc := cipher.NewCBCDecrypter(block, iv)
cbc.CryptBlocks(ciphertext, ciphertext)
length := len(ciphertext)
unpadding := int(ciphertext[len(ciphertext)-1])
ciphertext = ciphertext[:(length - unpadding)]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
// 去除填充
padding := int(ciphertext[len(ciphertext)-1])
if padding > blockSize || padding == 0 {
return nil, fmt.Errorf("invalid padding")
}
ciphertext = ciphertext[:len(ciphertext)-padding]
return ciphertext, nil
}

View File

@@ -20,7 +20,7 @@ func WriterFileCSV(data [][]string, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("MkdirAll dir %v", err)
}

View File

@@ -142,7 +142,7 @@ func WriteSheet(headerCells map[string]string, dataCells []map[string]any, fileN
saveFilePath := filepath.Join(dir, filePath, fileName)
// 创建文件目录
if err := os.MkdirAll(filepath.Dir(saveFilePath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(saveFilePath), 0775); err != nil {
return "", fmt.Errorf("failed to create save file %v", err)
}

View File

@@ -177,13 +177,13 @@ func ReadUploadFileStream(filePath, headerRange string) (map[string]any, error)
"range": "",
"chunkSize": 0,
"fileSize": 0,
"data": nil,
"data": []byte{},
}
// 文件大小
fileSize := getFileSize(fileAsbPath)
if fileSize <= 0 {
return result, nil
return result, fmt.Errorf("file does not exist")
}
result["fileSize"] = fileSize
@@ -312,12 +312,12 @@ func CopyUploadFile(filePath, dst string) error {
}
defer src.Close()
if err := os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
if _, err := os.Stat(dst); err == nil {
if info, err := os.Stat(dst); err == nil && !info.IsDir() {
ext := filepath.Ext(dst)
name := dst[0 : len(dst)-len(ext)]
newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)

View File

@@ -16,7 +16,7 @@ func WriterFileJSON(data any, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}
@@ -46,7 +46,7 @@ func WriterFileJSONLine(data []any, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}

View File

@@ -22,7 +22,7 @@ func WriterFileTXT(data [][]string, sep string, filePath string) error {
dirPath := filepath.Dir(filePath)
// 确保文件夹路径存在
err := os.MkdirAll(dirPath, os.ModePerm)
err := os.MkdirAll(dirPath, 0775)
if err != nil {
logger.Errorf("CreateFile MkdirAll %v", err)
}

View File

@@ -26,7 +26,7 @@ func transferToNewFile(file *multipart.FileHeader, dst string) error {
}
defer src.Close()
if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
if err = os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
return err
}
@@ -66,7 +66,7 @@ func mergeToNewFile(dirPath string, writePath string, fileName string) error {
// 写入到新路径文件
newFilePath := filepath.Join(writePath, fileName)
if err = os.MkdirAll(filepath.Dir(newFilePath), 0750); err != nil {
if err = os.MkdirAll(filepath.Dir(newFilePath), 0775); err != nil {
return err
}

View File

@@ -0,0 +1,178 @@
package machine
import (
"encoding/json"
"fmt"
"hash/fnv"
"os"
"runtime"
"time"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
"be.ems/src/framework/utils/crypto"
"be.ems/src/framework/utils/parse"
)
// 机器的唯一标识符
var Code string
// 初始信息
var LaunchInfo map[string]any
// codeGenerate 生成机器的唯一标识符
func codeGenerate() string {
var machineID string
// 获取主机名
hostname, err := os.Hostname()
if err != nil {
panic(err)
}
machineID += hostname
// 获取 CPU 信息
numCPU := runtime.NumCPU()
machineID += fmt.Sprintf("%d", numCPU)
// 获取操作系统信息
osInfo := runtime.GOOS
machineID += osInfo
// 使用哈希函数生成机器码
h := fnv.New32a()
h.Write([]byte(machineID))
machineCode := h.Sum32()
return fmt.Sprintf("%x", machineCode)
}
// 网管本地路径
func filePath() string {
filePath := "/usr/local/etc/omc/machine.ini"
if runtime.GOOS == "windows" {
filePath = fmt.Sprintf("C:%s", filePath)
}
return filePath
}
// codeFileRead 读取机器保留的信息
func codeFileRead() (map[string]any, error) {
var mapData map[string]any
// 读取文件内容
bytes, err := os.ReadFile(filePath())
if err != nil {
logger.Warnf("CodeFileRead ReadFile => %s", err.Error())
return mapData, fmt.Errorf("not file")
}
content := string(bytes)
// 解密
contentDe, err := crypto.StringDecryptByAES(content)
if err != nil {
logger.Errorf("CodeFileRead decrypt: %v", err.Error())
return mapData, fmt.Errorf("decrypt fail")
}
// 序列化Map
mapData, err = parse.ConvertConfigToMap("json", string(contentDe))
if err != nil {
logger.Warnf("NeConfPara5GRead ConvertConfigToMap => %s", err.Error())
return mapData, fmt.Errorf("content error")
}
return mapData, nil
}
// codeFileWrite 写入机器保留的信息
func codeFileWrite(data map[string]any) error {
jsonByte, _ := json.Marshal(data)
// 加密
contentEn, err := crypto.StringEncryptByAES(string(jsonByte))
if err != nil {
logger.Errorf("insert encrypt: %v", err.Error())
return fmt.Errorf("encrypt fail")
}
return parse.ConvertConfigToFile("txt", filePath(), contentEn)
}
// Launch 记录首次安装启动初始信息
func Launch() {
Code = codeGenerate()
// 检查文件是否存在
if _, err := os.Stat(filePath()); err != nil {
LaunchInfo = map[string]any{
"code": Code, // 机器码
"useTime": time.Now().UnixMilli(), // 首次使用时间
common.LAUNCH_BOOTLOADER: true, // 启动引导
common.LAUNCH_BOOTLOADER + "Time": 0, // 引导完成时间
}
codeFileWrite(LaunchInfo)
} else {
// 读取记录文件
data, err := codeFileRead()
if err != nil {
// 文件异常就重新生成
os.Remove(filePath())
Launch()
return
}
LaunchInfo = data
}
}
// SetLaunchInfo 新增额外的初始信息
func SetLaunchInfo(info map[string]any) error {
if info == nil {
return fmt.Errorf("not info")
}
// 固定值禁止变更
constKeys := []string{"code", "useTime"}
for k, v := range info {
constKey := false
for _, ck := range constKeys {
if ck == k {
constKey = true
break
}
}
if constKey {
continue
} else {
LaunchInfo[k] = v
}
}
return codeFileWrite(LaunchInfo)
}
// Bootloader 启动引导标记
func Bootloader(flag bool) error {
return SetLaunchInfo(map[string]any{
common.LAUNCH_BOOTLOADER: flag, // 启动引导 true开 false关
common.LAUNCH_BOOTLOADER + "Time": time.Now().UnixMilli(), // 引导完成时间
})
}
// Reset 引导数据重置
func Reset() error {
// 重置数据库
if runtime.GOOS == "windows" {
// return fmt.Errorf("not support window")
} else {
// 重置数据库
if _, err := cmd.Execf("sudo /usr/local/omc/bin/setomc.sh -m install"); err != nil {
return err
}
// 重启服务
if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart restagent"); err != nil {
return err
}
}
// 重置引导标记
if err := Bootloader(true); err != nil {
return err
}
return nil
}

View File

@@ -1,8 +1,11 @@
package parse
import (
"encoding/json"
"fmt"
"image/color"
"os"
"path/filepath"
"reflect"
"regexp"
"strconv"
@@ -10,6 +13,7 @@ import (
"time"
"github.com/robfig/cron/v3"
"gopkg.in/yaml.v3"
)
// Number 解析数值型
@@ -51,6 +55,8 @@ func Boolean(str any) bool {
case float32, float64:
num := reflect.ValueOf(str).Float()
return num != 0
case bool:
return str
default:
return false
}
@@ -165,3 +171,83 @@ func Color(colorStr string) *color.RGBA {
A: 255, // 不透明
}
}
// ConvertIPMask 转换IP网络地址掩码 24 -> 255.255.255.0
func ConvertIPMask(bits int64) string {
if bits < 0 || bits > 32 {
return "Invalid Mask Bits"
}
// 构建一个32位的uint32类型掩码指定前bits位为1其余为0
mask := uint32((1<<bits - 1) << (32 - bits))
// 将掩码转换为四个八位分组
groups := []string{
fmt.Sprintf("%d", mask>>24),
fmt.Sprintf("%d", (mask>>16)&255),
fmt.Sprintf("%d", (mask>>8)&255),
fmt.Sprintf("%d", mask&255),
}
// 将分组用点号连接起来形成掩码字符串
return strings.Join(groups, ".")
}
// ConvertConfigToMap 将配置内容转换为Map结构数据
//
// configType 类型支持txt json yaml yml
func ConvertConfigToMap(configType, content string) (map[string]any, error) {
// 类型支持viper.SupportedExts
// config := viper.New()
// config.SetConfigType(configType)
// err := config.ReadConfig(bytes.NewBuffer([]byte(content)))
// return config.AllSettings(), err
var configMap map[string]interface{}
var err error
if configType == "" || configType == "txt" {
configMap = map[string]interface{}{
"txt": content,
}
}
if configType == "yaml" || configType == "yml" {
err = yaml.Unmarshal([]byte(content), &configMap)
}
if configType == "json" {
err = json.Unmarshal([]byte(content), &configMap)
}
return configMap, err
}
// ConvertConfigToFile 将数据写入到指定文件内
//
// configType 类型支持txt json yaml yml
func ConvertConfigToFile(configType, filePath string, data any) error {
// viper.SupportedExts
// config := viper.New()
// config.SetConfigType(configType)
// for key, value := range mapData {
// config.Set(key, value)
// }
// return config.WriteConfigAs(filePath)
var dataByte []byte
var err error
if configType == "" || configType == "txt" {
dataByte = []byte(data.(string))
}
if configType == "yaml" || configType == "yml" {
dataByte, err = yaml.Marshal(data)
}
if configType == "json" {
dataByte, err = json.Marshal(data)
}
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(filePath), 0775); err != nil {
return err
}
return os.WriteFile(filePath, dataByte, 0644)
}

View File

@@ -20,7 +20,7 @@ func PageNumSize(pageNum, pageSize any) (int64, int64) {
// 显示记录数
size := parse.Number(pageSize)
if size < 0 {
if size < 1 {
size = 10
}
return num - 1, size

View File

@@ -28,7 +28,7 @@ func FileSCPLocalToNe(neIp, localPath, nePath string) error {
// 网元NE 远程文件复制到本地文件
func FileSCPNeToLocal(neIp, nePath, localPath string) error {
// 确保文件夹路径存在
if err := os.MkdirAll(filepath.Dir(localPath), 0750); err != nil {
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
logger.Errorf("FileSCPNeToLocal MkdirAll err %v", err)
return err
}

View File

@@ -6,12 +6,14 @@ import (
"io"
"os"
"os/user"
"path/filepath"
"strings"
"sync"
"time"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
gosftp "github.com/pkg/sftp"
gossh "golang.org/x/crypto/ssh"
)
@@ -133,8 +135,12 @@ func (c *ConnSSH) SendToAuthorizedKeys() error {
return err
}
authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey))
cmdStr := "echo '" + authorizedKeysEntry + "' >> ~/.ssh/authorized_keys"
_, err = c.RunCMD(cmdStr)
cmdStrArr := []string{
fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User),
}
_, err = c.RunCMD(strings.Join(cmdStrArr, " && "))
if err != nil {
logger.Errorf("SendAuthorizedKeys echo err %s", err.Error())
return err
@@ -156,9 +162,8 @@ func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) {
// 是否存在私钥并创建
keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir)
if _, err := os.Stat(keyPath); err != nil {
_, err2 := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath)
if err2 != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err2.Error())
if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error())
}
}
@@ -239,12 +244,11 @@ func (s *SSHClientSession) Write(cmd string) (int, error) {
return s.Stdin.Write([]byte(cmd))
}
// Read 读取结果 等待一会才有结果
// Read 读取结果
func (s *SSHClientSession) Read() []byte {
if s.Stdout == nil {
return []byte{}
}
// time.Sleep(300 * time.Millisecond)
bs := s.Stdout.Bytes()
if len(bs) > 0 {
s.Stdout.Reset()
@@ -253,15 +257,6 @@ func (s *SSHClientSession) Read() []byte {
return []byte{}
}
// CombinedOutput 发送命令带结果返回
func (s *SSHClientSession) CombinedOutput(cmd string) (string, error) {
n, err := s.Write(cmd)
if n == 0 || err != nil {
return "", err
}
return string(s.Read()), nil
}
// singleWriter SSH客户端会话消息
type singleWriter struct {
b bytes.Buffer
@@ -283,3 +278,208 @@ func (w *singleWriter) Reset() {
defer w.mu.Unlock()
w.b.Reset()
}
// NewClientSFTP 创建SSH客户端SFTP对象
func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
sftpClient, err := gosftp.NewClient(c.Client)
if err != nil {
logger.Errorf("NewClientSFTP failed to create sftp: => %s", err.Error())
return nil, err
}
return &SSHClientSFTP{
Client: sftpClient,
}, nil
}
// SSHClientSFTP SSH客户端SFTP对象
type SSHClientSFTP struct {
Client *gosftp.Client
}
// Close 关闭会话
func (s *SSHClientSFTP) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// CopyDirRemoteToLocal 复制目录-远程到本地
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
// 列出远程目录中的文件和子目录
remoteFiles, err := s.Client.ReadDir(remoteDir)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 创建本地目录
err = os.MkdirAll(localDir, 0775)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error())
return err
}
// 遍历远程文件和子目录并复制到本地
for _, remoteFile := range remoteFiles {
remotePath := filepath.Join(remoteDir, remoteFile.Name())
localPath := filepath.Join(localDir, remoteFile.Name())
if remoteFile.IsDir() {
// 如果是子目录,则递归复制子目录
err = s.CopyDirRemoteToLocal(remotePath, localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error())
continue
}
} else {
// 如果是文件,则复制文件内容
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error())
continue
}
defer remoteFile.Close()
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error())
continue
}
defer localFile.Close()
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error())
continue
}
}
}
return nil
}
// CopyDirRemoteToLocal 复制目录-本地到远程
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error {
// 创建远程目录
err := s.Client.MkdirAll(remoteDir)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 遍历本地目录中的文件和子目录并复制到远程
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 生成远程路径
remotePath := filepath.Join(remoteDir, localPath[len(localDir):])
if info.IsDir() {
// 如果是子目录,则创建远程目录
err := s.Client.MkdirAll(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error())
return nil
}
} else {
// 如果是文件,则复制文件内容
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error())
return nil
}
defer localFile.Close()
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error())
return nil
}
defer remoteFile.Close()
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error())
return nil
}
}
return nil
})
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-远程到本地
func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error {
// 打开远程文件
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
// if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
// ext := filepath.Ext(localPath)
// name := localPath[0 : len(localPath)-len(ext)]
// newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
// err := os.Rename(localPath, newName)
// if err != nil {
// return err
// }
// }
// 创建本地文件
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 复制文件内容
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-本地到远程
func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error {
// 打开本地文件
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 创建远程文件
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
// 复制文件内容
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error())
return err
}
return nil
}

View File

@@ -50,7 +50,13 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
// fmt.Fprintln(client, c.User)
// fmt.Fprintln(client, c.Password)
// 需要确保接收方理解并正确处理发送窗口大小设置命令
client.Write([]byte{255, 251, 31}) // 发送窗口大小选项
client.Write([]byte{255, 250, 31, 0, 128, 0, 120, 255, 240}) // 发送窗口行和列的大小
c.Client = &client
// 排空连接登录的信息
c.RunCMD("")
return c, nil
}
@@ -70,32 +76,14 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 排空连接登录的信息
for {
// 设置读取超时时间为100毫秒
conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
n, err := conn.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
buf.Reset()
// 写入命令
_, err := conn.Write([]byte(cmd))
if err != nil {
return "", err
if cmd != "" {
if _, err := conn.Write([]byte(cmd)); err != nil {
return "", err
}
}
// 读取本次响应命令消息
// 读取命令消息
for {
// 设置读取超时时间为1000毫秒
conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
@@ -119,35 +107,12 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
}
// NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession() (*TelnetClientSession, error) {
func (c *ConnTelnet) NewClientSession(cols, rows uint8) (*TelnetClientSession, error) {
if c.Client == nil {
return nil, fmt.Errorf("telnet client not connected")
}
conn := *c.Client
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 排空连接登录的信息
for {
// 设置读取超时时间为5毫秒
conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond))
n, err := conn.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
buf.Reset()
return &TelnetClientSession{
Client: conn,
Client: *c.Client,
}, nil
}

View File

@@ -11,6 +11,7 @@ import (
"be.ems/src/framework/logger"
redisCahe "be.ems/src/framework/redis"
"be.ems/src/framework/utils/generate"
"be.ems/src/framework/utils/machine"
"be.ems/src/framework/vo"
jwt "github.com/golang-jwt/jwt/v5"
@@ -74,7 +75,7 @@ func Create(loginUser *vo.LoginUser, ilobArgs ...string) string {
// 生成令牌设置密钥
secret := config.Get("jwt.secret").(string)
tokenStr, err := jwtToken.SignedString([]byte(secret))
tokenStr, err := jwtToken.SignedString([]byte(machine.Code + "@" + secret))
if err != nil {
logger.Infof("jwt sign err : %v", err)
return ""
@@ -118,7 +119,7 @@ func Verify(tokenString string) (jwt.MapClaims, error) {
// 判断加密算法是预期的加密算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
secret := config.Get("jwt.secret").(string)
return []byte(secret), nil
return []byte(machine.Code + "@" + secret), nil
}
return nil, jwt.ErrSignatureInvalid
})