版本封存
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
module cmii-uav-watchdog-common
|
||||
|
||||
go 1.24
|
||||
|
||||
require cmii-uav-watchdog-otp v0.0.0
|
||||
|
||||
replace cmii-uav-watchdog-otp => ../cmii-uav-watchdog-otp
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//TIP <p>To run your code, right-click the code and select <b>Run</b>.</p> <p>Alternatively, click
|
||||
// the <icon src="AllIcons.Actions.Execute"/> icon in the gutter and select the <b>Run</b> menu item from here.</p>
|
||||
|
||||
func main() {
|
||||
//TIP <p>Press <shortcut actionId="ShowIntentionActions"/> when your caret is at the underlined text
|
||||
// to see how GoLand suggests fixing the warning.</p><p>Alternatively, if available, click the lightbulb to view possible fixes.</p>
|
||||
s := "gopher"
|
||||
fmt.Println("Hello and welcome, %s!", s)
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
//TIP <p>To start your debugging session, right-click your code in the editor and select the Debug option.</p> <p>We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint
|
||||
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>.</p>
|
||||
fmt.Println("i =", 100/i)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,32 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// AuthorizationFile 授权文件模型
|
||||
type AuthorizationFile struct {
|
||||
EncryptedHosts []string `json:"encrypted_hosts"` // 加密后的主机信息列表
|
||||
TOTPCode string `json:"totp_code"` // TOTP验证码
|
||||
CurrentTime time.Time `json:"current_time"` // 当前系统时间
|
||||
FirstAuthTime time.Time `json:"first_auth_time"` // 初次授权时间
|
||||
TimeOffset int64 `json:"time_offset"` // 授权时间偏移
|
||||
EncryptedHostMap map[string]HostInfo `json:"encrypted_host_map"` // 加密后的主机信息列表
|
||||
TOTPCode string `json:"totp_code"` // TOTP验证码
|
||||
CurrentTime string `json:"current_time"` // 当前系统时间
|
||||
FirstAuthTime string `json:"first_auth_time"` // 初次授权时间
|
||||
TimeOffset int64 `json:"time_offset"` // 授权时间偏移
|
||||
ProjectNamespace string `json:"project_namespace"` // 项目命名空间
|
||||
EncryptedNamespace string `json:"encrypted_namespace"` // 加密后的项目命名空间 防止信息篡改
|
||||
}
|
||||
|
||||
// AuthorizationCode 授权码模型
|
||||
type AuthorizationCode struct {
|
||||
TOTPCode string `json:"totp_code"` // TOTP验证码
|
||||
CurrentTime time.Time `json:"current_time"` // 当前系统时间
|
||||
EncryptedHosts []string `json:"encrypted_hosts"` // 授权主机的加密字符串列表
|
||||
TOTPCode string `json:"totp_code"` // TOTP验证码
|
||||
CurrentTime string `json:"current_time"` // 当前系统时间
|
||||
EncryptedHostMap map[string]HostInfo `json:"encrypted_host_map"` // 加密后的主机信息列表 防止信息篡改
|
||||
ProjectNamespace string `json:"project_namespace"` // 项目命名空间
|
||||
EncryptedNamespace string `json:"encrypted_namespace"` // 加密后的项目命名空间 防止信息篡改
|
||||
}
|
||||
|
||||
// AuthorizationStorage 授权存储信息
|
||||
type AuthorizationStorage struct {
|
||||
EncryptedCode string `json:"encrypted_code"` // 加密后的授权码
|
||||
FirstAuthTime time.Time `json:"first_auth_time"` // 初次授权时间
|
||||
TimeOffset int64 `json:"time_offset"` // 授权时间偏移
|
||||
AuthorizedHosts []string `json:"authorized_hosts"` // 已授权主机列表
|
||||
SecondTOTPSecret string `json:"second_totp_secret"` // 第二级的totp密钥
|
||||
EncryptedAuthrizationCode string `json:"encrypted_authrization_code"` // 加密后的授权码,防止信息篡改
|
||||
FirstAuthTime string `json:"first_auth_time"` // 初次授权时间
|
||||
TimeOffset int64 `json:"time_offset"` // 授权时间偏移
|
||||
AuthorizedHostMap map[string]HostInfo `json:"authorized_host_map"` // 已授权主机列表
|
||||
SecondTOTPSecret string `json:"second_totp_secret"` // 第二级的totp密钥
|
||||
ProjectNamespace string `json:"project_namespace"` // 项目命名空间
|
||||
EncryptedNamespace string `json:"encrypted_namespace"` // 加密后的项目命名空间 防止信息篡改
|
||||
}
|
||||
|
||||
@@ -2,10 +2,13 @@ package models
|
||||
|
||||
// CPUInfo 结构体用于存储 CPU 信息
|
||||
type CPUInfo struct {
|
||||
ModelName string `json:"model_name"`
|
||||
Cores int `json:"cores"`
|
||||
Architecture string `json:"architecture"`
|
||||
UUID string `json:"uuid"`
|
||||
ModelName string `json:"model_name"`
|
||||
Cores int `json:"cores"`
|
||||
Architecture string `json:"architecture"`
|
||||
Flags []string `json:"flags"`
|
||||
Hypervisor string `json:"hypervisor"`
|
||||
Virtualization string `json:"virtualization"`
|
||||
Frequency string `json:"frequency"`
|
||||
}
|
||||
|
||||
// MemoryInfo holds the memory information.
|
||||
@@ -49,22 +52,21 @@ type MotherboardInfo struct {
|
||||
}
|
||||
|
||||
type SystemInfo struct {
|
||||
MachineID string `json:"machine_id"` // 唯一标识符
|
||||
MachineID string `json:"machine_id"` // 主机唯一标识符
|
||||
MachineSerial string `json:"machine_serial"` // 主机序列号
|
||||
OS OSInfo `json:"os"` // 操作系统
|
||||
KernelVersion string `json:"kernel_version"` // 内核版本
|
||||
NodeName string `json:"node_name"` // 节点名称
|
||||
NodeIP string `json:"node_ip"` // 节点IP
|
||||
}
|
||||
|
||||
type OSInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
ID string `json:"id"`
|
||||
IDLike string `json:"id_like"`
|
||||
VersionID string `json:"version_id"`
|
||||
PrettyName string `json:"pretty_name"`
|
||||
HomeURL string `json:"home_url"`
|
||||
SupportURL string `json:"support_url"`
|
||||
BugReportURL string `json:"bug_report_url"`
|
||||
PrivacyURL string `json:"privacy_url"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
ID string `json:"id"`
|
||||
IDLike string `json:"id_like"`
|
||||
VersionID string `json:"version_id"`
|
||||
PrettyName string `json:"pretty_name"`
|
||||
}
|
||||
|
||||
// HostInfo 主机信息模型
|
||||
@@ -77,12 +79,32 @@ type HostInfo struct {
|
||||
MotherboardInfo MotherboardInfo `json:"motherboard_info"`
|
||||
}
|
||||
|
||||
// EnvInfo 环境信息
|
||||
type EnvInfo struct {
|
||||
K8S_NAMESPACE string `json:"k8s_namespace"` // 环境名称
|
||||
APPLICATION_NAME string `json:"application_name"` // 应用名称
|
||||
CUST_JAVA_OPTS string `json:"cust_java_opts"` // 自定义java参数
|
||||
BIZ_CONFIG_GROUP string `json:"biz_config_group"` // 业务配置组
|
||||
SYS_CONFIG_GROUP string `json:"sys_config_group"` // 系统配置组
|
||||
IMAGE_NAME string `json:"image_name"` // 镜像名称
|
||||
JAVA_VERSION string `json:"java_version"` // java版本
|
||||
GIT_COMMIT string `json:"git_commit"` // git commit
|
||||
GIT_BRANCH string `json:"git_branch"` // git branch
|
||||
NODE_NAME string `json:"node_name"` // 节点名称
|
||||
NODE_IP string `json:"node_ip"` // 节点ip
|
||||
POD_NAME string `json:"pod_name"` // pod名称
|
||||
LIMIT_CPU string `json:"limit_cpu"` // 限制cpu
|
||||
LIMIT_MEMORY string `json:"limit_memory"` // 限制内存
|
||||
REQUEST_CPU string `json:"request_cpu"` // 请求cpu
|
||||
REQUEST_MEMORY string `json:"request_memory"` // 请求内存
|
||||
}
|
||||
|
||||
// HeartbeatRequest 心跳请求
|
||||
type HeartbeatRequest struct {
|
||||
HostInfo HostInfo `json:"host_info"` // 主机信息
|
||||
EnvInfo EnvInfo `json:"env_info"` // 环境信息
|
||||
Timestamp int64 `json:"timestamp"` // 时间戳
|
||||
TOTPCode string `json:"totp_code"` // TOTP验证码
|
||||
AppName string `json:"app_name"` // 应用名称
|
||||
}
|
||||
|
||||
// HeartbeatResponse 心跳响应
|
||||
|
||||
22
cmii-uav-watchdog-common/models/project.go
Normal file
22
cmii-uav-watchdog-common/models/project.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
// Project 项目信息
|
||||
type Project struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Namespace string `json:"namespace" binding:"required"`
|
||||
Province string `json:"province"`
|
||||
City string `json:"city"`
|
||||
Domain string `json:"domain"`
|
||||
BusinessMan string `json:"business_man"`
|
||||
MarketMan string `json:"market_man" `
|
||||
TierOneSecret string `json:"tier_one_secret" `
|
||||
TierTwoSecret string `json:"tier_two_secret"`
|
||||
AuthTime string `json:"auth_time"`
|
||||
AuthFilePath string `json:"auth_file_path"`
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
|
||||
// ProjectPO 项目持久化对象
|
||||
type ProjectPO struct {
|
||||
Project
|
||||
}
|
||||
169
cmii-uav-watchdog-common/totp_tier_one/crypto.go
Normal file
169
cmii-uav-watchdog-common/totp_tier_one/crypto.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package totp_tier_one
|
||||
|
||||
import (
|
||||
"cmii-uav-watchdog-common/models"
|
||||
"cmii-uav-watchdog-common/wdd_log"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Encrypt 加密字符串
|
||||
// 保证使用相同的plaintext和key进行加密,在不同时间、不同机器上输出的加密字符串都是固定的
|
||||
func Encrypt(plaintext string, key string) (encryptedPlaintext string, encryptError error) {
|
||||
// 创建hash
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(key))
|
||||
keyBytes := hasher.Sum(nil)
|
||||
|
||||
// 创建cipher
|
||||
block, err := aes.NewCipher(keyBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 创建gcm
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 生成确定性nonce - 使用plaintext和key的组合生成,确保对相同输入产生相同nonce
|
||||
nonceHasher := sha256.New()
|
||||
nonceHasher.Write([]byte(key + "fixed_salt_for_deterministic_result" + plaintext[:min(10, len(plaintext))]))
|
||||
nonceSource := nonceHasher.Sum(nil)
|
||||
|
||||
// 创建合适大小的nonce
|
||||
nonce := nonceSource[:gcm.NonceSize()]
|
||||
|
||||
// 加密
|
||||
ciphertext := gcm.Seal(nil, nonce, []byte(plaintext), nil)
|
||||
|
||||
// 将nonce和密文连接起来
|
||||
result := append(nonce, ciphertext...)
|
||||
|
||||
// 编码为base64
|
||||
return base64.StdEncoding.EncodeToString(result), nil
|
||||
}
|
||||
|
||||
// Decrypt 解密字符串
|
||||
// 可以使用加密字符串和key在不同时间、不同机器上解密出原始plaintext
|
||||
func Decrypt(encrypted string, key string) (decryptedPlaintext string, decryptError error) {
|
||||
// 解码base64
|
||||
data, err := base64.StdEncoding.DecodeString(encrypted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 创建hash
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(key))
|
||||
keyBytes := hasher.Sum(nil)
|
||||
|
||||
// 创建cipher
|
||||
block, err := aes.NewCipher(keyBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 创建gcm
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 检查长度
|
||||
if len(data) < gcm.NonceSize() {
|
||||
return "", errors.New("密文太短")
|
||||
}
|
||||
|
||||
// 分离nonce和密文
|
||||
nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():]
|
||||
|
||||
// 解密
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
||||
// min 返回两个整数中较小的一个
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// EncryptHostInfo 加密主机信息
|
||||
func EncryptHostInfo(hostInfo models.HostInfo, key string) (encryptedHostInfo string, encryptError error) {
|
||||
|
||||
// 生成主机唯一标识作为加密密钥
|
||||
info := generateHostUniqueID(hostInfo)
|
||||
|
||||
// 加密主机信息
|
||||
encrypted, err := Encrypt(info, key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// DecryptHostInfo 解密主机信息
|
||||
func DecryptHostInfo(encrypted string, hostInfo models.HostInfo, key string) (decryptedOK bool, decryptError error) {
|
||||
|
||||
// 解密主机信息
|
||||
decryptedStr, err := Decrypt(encrypted, key)
|
||||
if err != nil {
|
||||
wdd_log.Error("[DecryptHostInfo] - Decrypt失败: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// wdd_log.Info("[DecryptHostInfo] - Decrypt成功: %s", decryptedStr)
|
||||
|
||||
// 生成主机唯一标识作为加密密钥
|
||||
hostUniqueID := generateHostUniqueID(hostInfo)
|
||||
if hostUniqueID != decryptedStr {
|
||||
wdd_log.Error("[DecryptHostInfo] - 主机信息篡改")
|
||||
return false, errors.New("主机信息篡改")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// generateHostUniqueID 生成主机唯一标识作为加密密钥
|
||||
func generateHostUniqueID(hostInfo models.HostInfo) string {
|
||||
// hostinfo.SystemInfo.MachineID
|
||||
machineID := hostInfo.SystemInfo.MachineID
|
||||
|
||||
// hostinfo.SystemInfo.KernelVersion
|
||||
kernelVersion := hostInfo.SystemInfo.KernelVersion
|
||||
|
||||
// 将CPU信息中的ModelName Cores Hypervisor 拼接起来
|
||||
cpuCores := hostInfo.CPUInfo.Cores
|
||||
cpuHypervisor := hostInfo.CPUInfo.Hypervisor
|
||||
cpuModelName := hostInfo.CPUInfo.ModelName
|
||||
|
||||
cpuInfo := fmt.Sprintf("%s-%d-%s", cpuModelName, cpuCores, cpuHypervisor)
|
||||
|
||||
// 不能使用 mac 地址,因为 每个Pod 的 mac 地址会变化
|
||||
|
||||
// hostinfo.SystemInfo.MachineSerial
|
||||
machineSerial := hostInfo.SystemInfo.MachineSerial
|
||||
|
||||
// 将memory中的total 和 used 拼接起来
|
||||
memoryTotal := hostInfo.MemoryInfo.Total
|
||||
|
||||
// 将上述的全部信息拼接起来
|
||||
info := strings.Join([]string{machineID, kernelVersion, cpuInfo, machineSerial, strconv.FormatUint(memoryTotal, 10)}, "==")
|
||||
|
||||
return info
|
||||
}
|
||||
218
cmii-uav-watchdog-common/totp_tier_one/crypto_test.go
Normal file
218
cmii-uav-watchdog-common/totp_tier_one/crypto_test.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package totp_tier_one
|
||||
|
||||
import (
|
||||
"cmii-uav-watchdog-common/models"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestEncryptDecrypt 测试加密和解密功能
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
plaintext string
|
||||
key string
|
||||
}{
|
||||
{
|
||||
name: "正常文本加密解密",
|
||||
plaintext: "这是一段测试文本",
|
||||
key: "测试密钥",
|
||||
},
|
||||
{
|
||||
name: "空文本加密解密",
|
||||
plaintext: "",
|
||||
key: "测试密钥",
|
||||
},
|
||||
{
|
||||
name: "特殊字符加密解密",
|
||||
plaintext: "!@#$%^&*()_+{}|:<>?",
|
||||
key: "!@#$%^&*()_+{}|:<>?",
|
||||
},
|
||||
{
|
||||
name: "长文本加密解密",
|
||||
plaintext: "这是一段非常长的测试文本,用于测试加密和解密功能是否能够正确处理长文本。这是一段非常长的测试文本,用于测试加密和解密功能是否能够正确处理长文本。",
|
||||
key: "测试密钥",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// 加密
|
||||
encrypted, err := Encrypt(tt.plaintext, tt.key)
|
||||
if err != nil {
|
||||
t.Fatalf("加密失败: %v", err)
|
||||
}
|
||||
|
||||
// 确保加密后的文本与原始文本不同
|
||||
if tt.plaintext != "" && encrypted == tt.plaintext {
|
||||
t.Errorf("加密后的文本与原始文本相同,可能未正确加密")
|
||||
}
|
||||
|
||||
// 解密
|
||||
decrypted, err := Decrypt(encrypted, tt.key)
|
||||
if err != nil {
|
||||
t.Fatalf("解密失败: %v", err)
|
||||
}
|
||||
|
||||
// 确保解密后的文本与原始文本相同
|
||||
if decrypted != tt.plaintext {
|
||||
t.Errorf("解密后的文本与原始文本不同,期望:%s,实际:%s", tt.plaintext, decrypted)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestDecryptWithWrongKey 测试使用错误密钥解密
|
||||
func TestDecryptWithWrongKey(t *testing.T) {
|
||||
plaintext := "这是一段测试文本"
|
||||
correctKey := "正确密钥"
|
||||
wrongKey := "错误密钥"
|
||||
|
||||
// 使用正确密钥加密
|
||||
encrypted, err := Encrypt(plaintext, correctKey)
|
||||
if err != nil {
|
||||
t.Fatalf("加密失败: %v", err)
|
||||
}
|
||||
|
||||
// 使用错误密钥解密,期望失败
|
||||
_, err = Decrypt(encrypted, wrongKey)
|
||||
fmt.Println("解密失败的 error :", err)
|
||||
if err == nil {
|
||||
t.Errorf("使用错误密钥解密应该失败,但成功了")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDecryptInvalidData 测试解密无效的数据
|
||||
func TestDecryptInvalidData(t *testing.T) {
|
||||
invalidEncrypted := "这不是有效的加密数据"
|
||||
key := "测试密钥"
|
||||
|
||||
_, err := Decrypt(invalidEncrypted, key)
|
||||
if err == nil {
|
||||
t.Errorf("解密无效数据应该失败,但成功了")
|
||||
}
|
||||
}
|
||||
|
||||
// createMockHostInfo 创建模拟的主机信息用于测试
|
||||
func createMockHostInfo() models.HostInfo {
|
||||
return models.HostInfo{
|
||||
SystemInfo: models.SystemInfo{
|
||||
MachineID: "test-machine-id",
|
||||
KernelVersion: "5.10.0-test",
|
||||
OS: models.OSInfo{
|
||||
Name: "TestOS",
|
||||
Version: "1.0",
|
||||
ID: "test",
|
||||
IDLike: "test",
|
||||
VersionID: "1.0",
|
||||
PrettyName: "Test OS 1.0",
|
||||
},
|
||||
},
|
||||
CPUInfo: models.CPUInfo{
|
||||
ModelName: "Test CPU",
|
||||
Cores: 4,
|
||||
Architecture: "x86_64",
|
||||
Flags: []string{},
|
||||
Hypervisor: "",
|
||||
Virtualization: "",
|
||||
Frequency: "",
|
||||
},
|
||||
DiskInfo: []models.DiskInfo{
|
||||
{
|
||||
Device: "/dev/sda1",
|
||||
Filesystem: "ext4",
|
||||
Type: "ext4",
|
||||
Size: 1000000,
|
||||
Used: 500000,
|
||||
Available: 500000,
|
||||
UsePercent: "50%",
|
||||
MountPoint: "/",
|
||||
PhysicalDevice: "/dev/sda",
|
||||
PhysicalSize: 2000000,
|
||||
},
|
||||
},
|
||||
MemoryInfo: models.MemoryInfo{
|
||||
Total: 8000000,
|
||||
Free: 4000000,
|
||||
Available: 4000000,
|
||||
Used: 4000000,
|
||||
Buffers: 1000000,
|
||||
Cached: 1000000,
|
||||
Shared: 500000,
|
||||
},
|
||||
NetInfo: []models.NetworkInterfaceInfo{
|
||||
{
|
||||
Name: "eth0",
|
||||
MACAddress: "00:11:22:33:44:55",
|
||||
IPAddresses: []string{"192.168.1.100", "fe80::1234"},
|
||||
},
|
||||
},
|
||||
MotherboardInfo: models.MotherboardInfo{
|
||||
Manufacturer: "Test Manufacturer",
|
||||
Product: "Test Product",
|
||||
Version: "1.0",
|
||||
Serial: "TEST123456",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncryptDecryptHostInfo 测试主机信息的加密和解密
|
||||
func TestEncryptDecryptHostInfo(t *testing.T) {
|
||||
hostInfo := createMockHostInfo()
|
||||
key := "test-key"
|
||||
|
||||
// 加密主机信息
|
||||
encrypted, err := EncryptHostInfo(hostInfo, key)
|
||||
fmt.Println("加密后的主机信息:", encrypted)
|
||||
if err != nil {
|
||||
t.Fatalf("加密主机信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 确保加密后的文本不为空
|
||||
if encrypted == "" {
|
||||
t.Errorf("加密后的主机信息为空")
|
||||
}
|
||||
|
||||
// 解密主机信息
|
||||
decrypted, err := DecryptHostInfo(encrypted, hostInfo, key)
|
||||
if err != nil {
|
||||
t.Fatalf("解密主机信息失败: %v", err)
|
||||
}
|
||||
|
||||
if !decrypted {
|
||||
t.Errorf("解密后的主机信息与原始主机信息不同")
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncryptDecryptHostInfoWithModifiedInfo 测试使用修改过的主机信息解密
|
||||
func TestEncryptDecryptHostInfoWithModifiedInfo(t *testing.T) {
|
||||
originalHostInfo := createMockHostInfo()
|
||||
key := "test-key"
|
||||
|
||||
// 加密主机信息
|
||||
encrypted, err := EncryptHostInfo(originalHostInfo, key)
|
||||
if err != nil {
|
||||
t.Fatalf("加密主机信息失败: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("加密后的主机信息: %s", encrypted)
|
||||
|
||||
// 创建修改过的主机信息
|
||||
modifiedHostInfo := originalHostInfo
|
||||
|
||||
// 加密修改过的主机信息
|
||||
encryptedModified, err := EncryptHostInfo(modifiedHostInfo, key)
|
||||
if err != nil {
|
||||
t.Fatalf("加密修改过的主机信息失败: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("加密修改后的主机信息: %s", encryptedModified)
|
||||
|
||||
// 使用修改过的主机信息尝试解密,期望失败
|
||||
isOK, err := DecryptHostInfo(encryptedModified, originalHostInfo, key)
|
||||
fmt.Println("解密后的主机信息 error :", err)
|
||||
|
||||
if isOK {
|
||||
t.Errorf("解密后的主机信息与修改后的主机信息相同, 不应该相同")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package totp_tier_one
|
||||
|
||||
import (
|
||||
otp "cmii-uav-watchdog-otp"
|
||||
"cmii-uav-watchdog-otp/totp"
|
||||
"time"
|
||||
)
|
||||
|
||||
var TierOneTOTPSecretOpts = totp.GenerateOpts{
|
||||
SecretSize: 64,
|
||||
Issuer: "cmii-uav-watchdog-center",
|
||||
AccountName: "cmii-uav-watchdog-center",
|
||||
Period: 30 * 2 * 30, // 30分钟
|
||||
Digits: otp.DigitsEight,
|
||||
Algorithm: otp.AlgorithmSHA256,
|
||||
}
|
||||
|
||||
// GenerateTierOneTOTPCode 生成一级TOTP验证码
|
||||
func GenerateTierOneTOTPCode(secret string) (string, error) {
|
||||
validateOpts := totp.ValidateOpts{}
|
||||
validateOpts.ConvertToValidateOpts(TierOneTOTPSecretOpts)
|
||||
|
||||
code, err := totp.GenerateCodeCustom(secret, time.Now(), validateOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// VerifyTierOneTOTPCode 验证一级TOTP验证码
|
||||
func VerifyTierOneTOTPCode(code string, secret string) bool {
|
||||
validateOpts := totp.ValidateOpts{}
|
||||
validateOpts.ConvertToValidateOpts(TierOneTOTPSecretOpts)
|
||||
valid, err := totp.ValidateCustom(code, secret, time.Now(), validateOpts)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return valid
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package totp_tier_two
|
||||
|
||||
import (
|
||||
"cmii-uav-watchdog-common/utils"
|
||||
"cmii-uav-watchdog-common/wdd_log"
|
||||
otp "cmii-uav-watchdog-otp"
|
||||
"cmii-uav-watchdog-otp/totp"
|
||||
)
|
||||
|
||||
var TierTwoTOTPSecretOpts = totp.GenerateOpts{
|
||||
SecretSize: 32,
|
||||
Issuer: "cmii-uav-watchdog",
|
||||
AccountName: "cmii-uav-watchdog",
|
||||
Period: 30,
|
||||
Secret: []byte{},
|
||||
Digits: otp.DigitsSix,
|
||||
Algorithm: otp.AlgorithmSHA1,
|
||||
Rand: nil,
|
||||
}
|
||||
|
||||
// GenerateTierTwoTOTPSecret 生成二级TOTP密钥
|
||||
func GenerateTierTwoTOTPSecret() (string, error) {
|
||||
secret, err := totp.Generate(TierTwoTOTPSecretOpts)
|
||||
if err != nil {
|
||||
wdd_log.Error("生成TOTP密钥失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
wdd_log.Info("生成TOTP密钥成功: %s", secret.Secret())
|
||||
return secret.Secret(), nil
|
||||
}
|
||||
|
||||
// GenerateTierTwoTOTPCode 生成二级TOTP验证码
|
||||
func GenerateTierTwoTOTPCode(secret string) (string, error) {
|
||||
validateOpts := totp.ValidateOpts{}
|
||||
validateOpts.ConvertToValidateOpts(TierTwoTOTPSecretOpts)
|
||||
code, err := totp.GenerateCodeCustom(secret, utils.CurentTime(), validateOpts)
|
||||
if err != nil {
|
||||
wdd_log.Error("TierTwo TOTP验证码生成失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// VerifyTierTwoTOTPCode 验证二级TOTP验证码
|
||||
func VerifyTierTwoTOTPCode(code string, secret string) bool {
|
||||
validateOpts := totp.ValidateOpts{}
|
||||
validateOpts.ConvertToValidateOpts(TierTwoTOTPSecretOpts)
|
||||
valid, err := totp.ValidateCustom(code, secret, utils.CurentTime(), validateOpts)
|
||||
if err != nil {
|
||||
wdd_log.Error("TierTwo TOTP验证失败: %v", err)
|
||||
return false
|
||||
}
|
||||
return valid
|
||||
}
|
||||
36
cmii-uav-watchdog-common/utils/time_utils.go
Normal file
36
cmii-uav-watchdog-common/utils/time_utils.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var CST = time.FixedZone("CST", 8*60*60)
|
||||
|
||||
// CurentTimeString 获取当前时间字符串 东八区时间
|
||||
func CurentTimeString() string {
|
||||
|
||||
return time.Now().In(CST).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// CurentTime 获取当前时间 东八区时间
|
||||
func CurentTime() time.Time {
|
||||
|
||||
return time.Now().In(CST)
|
||||
}
|
||||
|
||||
// CurentTimeUnix 获取当前时间戳 东八区时间
|
||||
func CurentTimeUnix() int64 {
|
||||
return CurentTime().Unix()
|
||||
}
|
||||
|
||||
// ParseTimeString 解析时间字符串 东八区时间
|
||||
func ParseTimeString(timeString string) (time.Time, error) {
|
||||
|
||||
return time.ParseInLocation("2006-01-02 15:04:05", timeString, CST)
|
||||
}
|
||||
|
||||
// ParseTimeUnix 解析时间戳 东八区时间
|
||||
func ParseTimeUnix(unix int64) (time.Time, error) {
|
||||
|
||||
return time.Unix(unix, 0).In(CST), nil
|
||||
}
|
||||
150
cmii-uav-watchdog-common/wdd_log/log_utils.go
Normal file
150
cmii-uav-watchdog-common/wdd_log/log_utils.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package wdd_log
|
||||
|
||||
import (
|
||||
"cmii-uav-watchdog-common/utils"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
colorReset = "\033[0m"
|
||||
colorRed = "\033[31m"
|
||||
colorGreen = "\033[32m"
|
||||
colorYellow = "\033[33m"
|
||||
colorBlue = "\033[34m"
|
||||
colorPurple = "\033[35m"
|
||||
colorCyan = "\033[36m"
|
||||
colorWhite = "\033[37m"
|
||||
)
|
||||
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
LevelDebug LogLevel = iota
|
||||
LevelInfo
|
||||
LevelWarn
|
||||
LevelError
|
||||
LevelFatal
|
||||
LogPrefix = "cmii-uav-watchdog"
|
||||
)
|
||||
|
||||
var logLevelColors = map[LogLevel]string{
|
||||
LevelDebug: colorCyan,
|
||||
LevelInfo: colorGreen,
|
||||
LevelWarn: colorYellow,
|
||||
LevelError: colorRed,
|
||||
LevelFatal: colorPurple,
|
||||
}
|
||||
|
||||
var logLevelNames = map[LogLevel]string{
|
||||
LevelDebug: "DEBUG",
|
||||
LevelInfo: "INFO",
|
||||
LevelWarn: "WARN",
|
||||
LevelError: "ERROR",
|
||||
LevelFatal: "FATAL",
|
||||
}
|
||||
|
||||
// Logger 日志单例结构体
|
||||
type Logger struct {
|
||||
// EnableDebug 是否启用Debug日志
|
||||
EnableDebug bool
|
||||
}
|
||||
|
||||
var (
|
||||
instance *Logger
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// GetInstance 获取Logger单例实例
|
||||
// 返回Logger的单例对象指针
|
||||
func GetInstance() *Logger {
|
||||
once.Do(func() {
|
||||
instance = &Logger{
|
||||
EnableDebug: false, // 默认不启用Debug日志
|
||||
}
|
||||
})
|
||||
return instance
|
||||
}
|
||||
|
||||
// SetEnableDebug 设置是否启用Debug日志
|
||||
// enable: true表示启用Debug日志,false表示禁用
|
||||
func (l *Logger) SetEnableDebug(enable bool) {
|
||||
l.EnableDebug = enable
|
||||
}
|
||||
|
||||
// Log 记录指定级别的日志
|
||||
// level: 日志级别
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Log(level LogLevel, format string, args ...interface{}) {
|
||||
// Debug级别日志在未启用时不输出
|
||||
if level == LevelDebug && !l.EnableDebug {
|
||||
return
|
||||
}
|
||||
|
||||
now := utils.CurentTimeString()
|
||||
color := logLevelColors[level]
|
||||
levelName := logLevelNames[level]
|
||||
message := fmt.Sprintf(format, args...)
|
||||
fmt.Printf("[%s] %s %s%s%s %s\n", LogPrefix, now, color, levelName, colorReset, message)
|
||||
}
|
||||
|
||||
// Debug 记录Debug级别日志
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Debug(format string, args ...interface{}) {
|
||||
l.Log(LevelDebug, format, args...)
|
||||
}
|
||||
|
||||
// Info 记录Info级别日志
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Info(format string, args ...interface{}) {
|
||||
l.Log(LevelInfo, format, args...)
|
||||
}
|
||||
|
||||
// Warn 记录Warn级别日志
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Warn(format string, args ...interface{}) {
|
||||
l.Log(LevelWarn, format, args...)
|
||||
}
|
||||
|
||||
// Error 记录Error级别日志
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Error(format string, args ...interface{}) {
|
||||
l.Log(LevelError, format, args...)
|
||||
}
|
||||
|
||||
// Fatal 记录Fatal级别日志
|
||||
// format: 日志格式
|
||||
// args: 格式化参数
|
||||
func (l *Logger) Fatal(format string, args ...interface{}) {
|
||||
l.Log(LevelFatal, format, args...)
|
||||
}
|
||||
|
||||
// 为了兼容原有代码,保留全局函数,但内部调用单例实例
|
||||
func Log(level LogLevel, format string, args ...interface{}) {
|
||||
GetInstance().Log(level, format, args...)
|
||||
}
|
||||
|
||||
func Debug(format string, args ...interface{}) {
|
||||
GetInstance().Debug(format, args...)
|
||||
}
|
||||
|
||||
func Info(format string, args ...interface{}) {
|
||||
GetInstance().Info(format, args...)
|
||||
}
|
||||
|
||||
func Warn(format string, args ...interface{}) {
|
||||
GetInstance().Warn(format, args...)
|
||||
}
|
||||
|
||||
func Error(format string, args ...interface{}) {
|
||||
GetInstance().Error(format, args...)
|
||||
}
|
||||
|
||||
func Fatal(format string, args ...interface{}) {
|
||||
GetInstance().Fatal(format, args...)
|
||||
}
|
||||
Reference in New Issue
Block a user