From 1f520d95e3a11cb0849b22c8198fb88d3a89a997 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 19 Apr 2024 19:57:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A6=96=E6=AC=A1=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E8=AE=B0=E5=BD=95=E5=88=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=81=9A=E5=94=AF=E4=B8=80=E8=BA=AB=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.go | 6 +- src/framework/utils/machine/launch.go | 162 ++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 src/framework/utils/machine/launch.go diff --git a/src/app.go b/src/app.go index b6b73297..33735482 100644 --- a/src/app.go +++ b/src/app.go @@ -8,6 +8,7 @@ import ( "be.ems/src/framework/errorcatch" "be.ems/src/framework/middleware" "be.ems/src/framework/middleware/security" + "be.ems/src/framework/utils/machine" "be.ems/src/modules/chart" "be.ems/src/modules/common" "be.ems/src/modules/crontask" @@ -37,6 +38,9 @@ func AppEngine() *gin.Engine { // 设置程序内全局资源访问 config.SetAssetsDirFS(assetsDir) + // 首次安装启动记录 + machine.Launch() + // 读取服务配置 app.ForwardedByClientIP = config.Get("server.proxy").(bool) return app @@ -108,7 +112,7 @@ func initDefeat(app *gin.Engine) { app.NoRoute(func(c *gin.Context) { c.JSON(404, gin.H{ "code": 404, - "msg": fmt.Sprintf("%s Not Found", c.Request.RequestURI), + "msg": fmt.Sprintf("Not Found %s", c.Request.RequestURI), }) }) } diff --git a/src/framework/utils/machine/launch.go b/src/framework/utils/machine/launch.go new file mode 100644 index 00000000..701b0b9f --- /dev/null +++ b/src/framework/utils/machine/launch.go @@ -0,0 +1,162 @@ +package machine + +import ( + "crypto/rand" + "encoding/json" + "fmt" + "hash/fnv" + "os" + "runtime" + "time" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/crypto" + "be.ems/src/framework/utils/parse" + "github.com/shirou/gopsutil/mem" +) + +// 机器的唯一标识符 +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 + + // 获取内存信息 + memInfo, _ := mem.VirtualMemory() + machineID += fmt.Sprintf("%d", memInfo.Total) + + // 使用哈希函数生成机器码 + 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, // 机器码 + "firstTime": time.Now().UnixMilli(), // 首次启动使用时间 + + "sysGuide": true, // 首次引导 + "sysGuideTime": 0, // 引导完成时间 + } + codeFileWrite(LaunchInfo) + } else { + // 创建一个用于存储密钥的字节数组 + key := make([]byte, 32) + + // 使用crypto/rand包生成安全的随机字节序列 + _, err := rand.Read(key) + if err != nil { + fmt.Println("Error generating random key:", err) + return + } + + // 将随机生成的字节序列作为密钥打印出来 + fmt.Printf("Generated AES-256 key: %x\n", key) + // 读取记录文件 + 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", "firstTime"} + 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) +}