diff --git a/README.md b/README.md index 7ac617b..a803458 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ pkg/ messageconfigs - 消息通知相关配置 monitorconfigs - 监控相关配置 nodeconfigs - 边缘节点相关配置 + nodeutils - 边缘节点相关函数 serverconfigs - 网站服务相关配置 systemconfigs - 系统全局配置 reporterconfigs - 区域监控终端配置 diff --git a/pkg/nodeutils/aes_256.go b/pkg/nodeutils/aes_256.go new file mode 100644 index 0000000..e4a966c --- /dev/null +++ b/pkg/nodeutils/aes_256.go @@ -0,0 +1,72 @@ +package nodeutils + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" +) + +type AES256CFBMethod struct { + block cipher.Block + iv []byte +} + +func (this *AES256CFBMethod) Init(key, iv []byte) error { + // 判断key是否为32长度 + l := len(key) + if l > 32 { + key = key[:32] + } else if l < 32 { + key = append(key, bytes.Repeat([]byte{' '}, 32-l)...) + } + + block, err := aes.NewCipher(key) + if err != nil { + return err + } + this.block = block + + // 判断iv长度 + l2 := len(iv) + if l2 > aes.BlockSize { + iv = iv[:aes.BlockSize] + } else if l2 < aes.BlockSize { + iv = append(iv, bytes.Repeat([]byte{' '}, aes.BlockSize-l2)...) + } + this.iv = iv + + return nil +} + +func (this *AES256CFBMethod) Encrypt(src []byte) (dst []byte, err error) { + if len(src) == 0 { + return + } + + defer func() { + _ = recover() + }() + + dst = make([]byte, len(src)) + + encrypter := cipher.NewCFBEncrypter(this.block, this.iv) + encrypter.XORKeyStream(dst, src) + + return +} + +func (this *AES256CFBMethod) Decrypt(dst []byte) (src []byte, err error) { + if len(dst) == 0 { + return + } + + defer func() { + _ = recover() + }() + + src = make([]byte, len(dst)) + decrypter := cipher.NewCFBDecrypter(this.block, this.iv) + decrypter.XORKeyStream(src, dst) + + return +} diff --git a/pkg/nodeutils/aes_utils.go b/pkg/nodeutils/aes_utils.go new file mode 100644 index 0000000..48a2428 --- /dev/null +++ b/pkg/nodeutils/aes_utils.go @@ -0,0 +1,75 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package nodeutils + +import ( + "encoding/base64" + "encoding/json" + "errors" + "github.com/iwind/TeaGo/maps" + "time" +) + +// EncryptData 加密 +func EncryptData(nodeUniqueId string, nodeSecret string, data maps.Map, timeout int32) (string, error) { + if data == nil { + data = maps.Map{} + } + + var expiresAt int64 + if timeout > 0 { + expiresAt = time.Now().Unix() + int64(timeout) + } + + dataJSON, err := json.Marshal(maps.Map{ + "expiresAt": expiresAt, + "data": data, + }) + if err != nil { + return "", errors.New("marshal data to json failed: " + err.Error()) + } + + var method = &AES256CFBMethod{} + err = method.Init([]byte(nodeUniqueId), []byte(nodeSecret)) + if err != nil { + return "", err + } + result, err := method.Encrypt(dataJSON) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(result), nil +} + +// DecryptData 解密 +func DecryptData(nodeUniqueId string, nodeSecret string, encodedString string) (maps.Map, error) { + var method = &AES256CFBMethod{} + err := method.Init([]byte(nodeUniqueId), []byte(nodeSecret)) + if err != nil { + return nil, err + } + + encodedData, err := base64.StdEncoding.DecodeString(encodedString) + if err != nil { + return nil, errors.New("base64 decode failed: " + err.Error()) + } + + dataJSON, err := method.Decrypt(encodedData) + if err != nil { + return nil, err + } + + var result = maps.Map{} + err = json.Unmarshal(dataJSON, &result) + if err != nil { + return nil, errors.New("unmarshal data failed: " + err.Error()) + } + + var expiresAt = result.GetInt64("expiresAt") + if expiresAt > 0 && expiresAt < time.Now().Unix() { + return nil, errors.New("data is expired") + } + + return result.GetMap("data"), nil +} diff --git a/pkg/nodeutils/aes_utils_test.go b/pkg/nodeutils/aes_utils_test.go new file mode 100644 index 0000000..ce43471 --- /dev/null +++ b/pkg/nodeutils/aes_utils_test.go @@ -0,0 +1,32 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package nodeutils + +import ( + "github.com/iwind/TeaGo/maps" + "testing" +) + +func TestEncryptData(t *testing.T) { + e, err := EncryptData("a", "b", maps.Map{ + "c": 1, + }, 5) + if err != nil { + t.Fatal(err) + } + t.Log("e:", e) + + s, err := DecryptData("a", "b", e) + if err != nil { + t.Fatal(err) + } + t.Log("s:", s) +} + +func BenchmarkEncryptData(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = EncryptData("a", "b", maps.Map{ + "c": 1, + }, 5) + } +} diff --git a/pkg/serverconfigs/health_check_config.go b/pkg/serverconfigs/health_check_config.go index 07d1bec..d2d9f76 100644 --- a/pkg/serverconfigs/health_check_config.go +++ b/pkg/serverconfigs/health_check_config.go @@ -5,20 +5,24 @@ import ( "github.com/iwind/TeaGo/maps" ) +const HealthCheckHeaderName = "Edge-Health-Check-Key" + // HealthCheckConfig 健康检查设置 type HealthCheckConfig struct { - IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启 - URL string `yaml:"url" json:"url"` // 读取的URL - Interval *shared.TimeDuration `yaml:"interval" json:"interval"` // 检测周期 - StatusCodes []int `yaml:"statusCodes" json:"statusCodes"` // 返回的状态码要求 - Timeout *shared.TimeDuration `yaml:"timeout" json:"timeout"` // 超时时间 - CountTries int64 `yaml:"countTries" json:"countTries"` // 尝试次数 - TryDelay *shared.TimeDuration `yaml:"tryDelay" json:"tryDelay"` // 尝试间隔 - FailActions []maps.Map `yaml:"failActions" json:"failActions"` // 失败采取的动作 TODO - RecoverActions []maps.Map `yaml:"recoverActions" json:"recoverActions"` // 恢复采取的动作 TODO - AutoDown bool `yaml:"autoDown" json:"autoDown"` // 是否自动下线 - CountUp int `yaml:"countUp" json:"countUp"` // 连续在线认定次数 - CountDown int `yaml:"countDown" json:"countDown"` // 连续离线认定次数 + IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启 + URL string `yaml:"url" json:"url"` // 读取的URL + Interval *shared.TimeDuration `yaml:"interval" json:"interval"` // 检测周期 + StatusCodes []int `yaml:"statusCodes" json:"statusCodes"` // 返回的状态码要求 + Timeout *shared.TimeDuration `yaml:"timeout" json:"timeout"` // 超时时间 + CountTries int64 `yaml:"countTries" json:"countTries"` // 尝试次数 + TryDelay *shared.TimeDuration `yaml:"tryDelay" json:"tryDelay"` // 尝试间隔 + FailActions []maps.Map `yaml:"failActions" json:"failActions"` // 失败采取的动作 TODO + RecoverActions []maps.Map `yaml:"recoverActions" json:"recoverActions"` // 恢复采取的动作 TODO + AutoDown bool `yaml:"autoDown" json:"autoDown"` // 是否自动下线 + CountUp int `yaml:"countUp" json:"countUp"` // 连续在线认定次数 + CountDown int `yaml:"countDown" json:"countDown"` // 连续离线认定次数 + UserAgent string `yaml:"userAgent" json:"userAgent"` // 发起请求用的UserAgent + OnlyBasicRequest bool `yaml:"onlyBasicRequest" json:"onlyBasicRequest"` // 只做基础的请求,不处理WAF、反向代理等 } // Init 初始化