Initial commit (code only without large binaries)
This commit is contained in:
6
EdgePlus/pkg/const/const.go
Normal file
6
EdgePlus/pkg/const/const.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
PlusKey = "41100c93a65cfb71d5b0672c0d60d7ec"
|
||||
PlusIV = "70ba69d67bf7e61e17ac565c6093a325"
|
||||
)
|
||||
41
EdgePlus/pkg/encrypt/magic_key.go
Normal file
41
EdgePlus/pkg/encrypt/magic_key.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
)
|
||||
|
||||
const (
|
||||
MagicKey = "f1c8eafb543f03023e97b7be864a4e9b"
|
||||
)
|
||||
|
||||
// 加密特殊信息
|
||||
func MagicKeyEncode(data []byte) []byte {
|
||||
method, err := NewMethodInstance("aes-256-cfb", MagicKey, MagicKey[:16])
|
||||
if err != nil {
|
||||
logs.Println("[MagicKeyEncode]" + err.Error())
|
||||
return data
|
||||
}
|
||||
|
||||
dst, err := method.Encrypt(data)
|
||||
if err != nil {
|
||||
logs.Println("[MagicKeyEncode]" + err.Error())
|
||||
return data
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// 解密特殊信息
|
||||
func MagicKeyDecode(data []byte) []byte {
|
||||
method, err := NewMethodInstance("aes-256-cfb", MagicKey, MagicKey[:16])
|
||||
if err != nil {
|
||||
logs.Println("[MagicKeyEncode]" + err.Error())
|
||||
return data
|
||||
}
|
||||
|
||||
src, err := method.Decrypt(data)
|
||||
if err != nil {
|
||||
logs.Println("[MagicKeyEncode]" + err.Error())
|
||||
return data
|
||||
}
|
||||
return src
|
||||
}
|
||||
11
EdgePlus/pkg/encrypt/magic_key_test.go
Normal file
11
EdgePlus/pkg/encrypt/magic_key_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package encrypt
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestMagicKeyEncode(t *testing.T) {
|
||||
dst := MagicKeyEncode([]byte("Hello,World"))
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src := MagicKeyDecode(dst)
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
12
EdgePlus/pkg/encrypt/method.go
Normal file
12
EdgePlus/pkg/encrypt/method.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package encrypt
|
||||
|
||||
type MethodInterface interface {
|
||||
// Init 初始化
|
||||
Init(key []byte, iv []byte) error
|
||||
|
||||
// Encrypt 加密
|
||||
Encrypt(src []byte) (dst []byte, err error)
|
||||
|
||||
// Decrypt 解密
|
||||
Decrypt(dst []byte) (src []byte, err error)
|
||||
}
|
||||
73
EdgePlus/pkg/encrypt/method_aes_128_cfb.go
Normal file
73
EdgePlus/pkg/encrypt/method_aes_128_cfb.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
)
|
||||
|
||||
type AES128CFBMethod struct {
|
||||
iv []byte
|
||||
block cipher.Block
|
||||
}
|
||||
|
||||
func (this *AES128CFBMethod) Init(key, iv []byte) error {
|
||||
// 判断key是否为32长度
|
||||
l := len(key)
|
||||
if l > 16 {
|
||||
key = key[:16]
|
||||
} else if l < 16 {
|
||||
key = append(key, bytes.Repeat([]byte{' '}, 16-l)...)
|
||||
}
|
||||
|
||||
// 判断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
|
||||
|
||||
// block
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.block = block
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *AES128CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = RecoverMethodPanic(recover())
|
||||
}()
|
||||
|
||||
dst = make([]byte, len(src))
|
||||
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
|
||||
encrypter.XORKeyStream(dst, src)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (this *AES128CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
|
||||
if len(dst) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = RecoverMethodPanic(recover())
|
||||
}()
|
||||
|
||||
src = make([]byte, len(dst))
|
||||
encrypter := cipher.NewCFBDecrypter(this.block, this.iv)
|
||||
encrypter.XORKeyStream(src, dst)
|
||||
|
||||
return
|
||||
}
|
||||
92
EdgePlus/pkg/encrypt/method_aes_128_cfb_test.go
Normal file
92
EdgePlus/pkg/encrypt/method_aes_128_cfb_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAES128CFBMethod_Encrypt(t *testing.T) {
|
||||
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := []byte("Hello, World")
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst = dst[:len(src)]
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src = make([]byte, len(src))
|
||||
src, err = method.Decrypt(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
|
||||
func TestAES128CFBMethod_Encrypt2(t *testing.T) {
|
||||
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sources := [][]byte{}
|
||||
|
||||
{
|
||||
a := []byte{1}
|
||||
_, err = method.Encrypt(a)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
src := []byte(strings.Repeat("Hello", 1))
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sources = append(sources, dst)
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
a := []byte{1}
|
||||
_, err = method.Decrypt(a)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, dst := range sources {
|
||||
dst2 := append([]byte{}, dst...)
|
||||
src2 := make([]byte, len(dst2))
|
||||
src2, err := method.Decrypt(dst2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(string(src2))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAES128CFBMethod_Encrypt(b *testing.B) {
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
src := []byte(strings.Repeat("Hello", 1024))
|
||||
for i := 0; i < b.N; i++ {
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_ = dst
|
||||
}
|
||||
}
|
||||
74
EdgePlus/pkg/encrypt/method_aes_192_cfb.go
Normal file
74
EdgePlus/pkg/encrypt/method_aes_192_cfb.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
)
|
||||
|
||||
type AES192CFBMethod struct {
|
||||
block cipher.Block
|
||||
iv []byte
|
||||
}
|
||||
|
||||
func (this *AES192CFBMethod) Init(key, iv []byte) error {
|
||||
// 判断key是否为24长度
|
||||
l := len(key)
|
||||
if l > 24 {
|
||||
key = key[:24]
|
||||
} else if l < 24 {
|
||||
key = append(key, bytes.Repeat([]byte{' '}, 24-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 *AES192CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = RecoverMethodPanic(recover())
|
||||
}()
|
||||
|
||||
dst = make([]byte, len(src))
|
||||
|
||||
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
|
||||
encrypter.XORKeyStream(dst, src)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (this *AES192CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
|
||||
if len(dst) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = RecoverMethodPanic(recover())
|
||||
}()
|
||||
|
||||
src = make([]byte, len(dst))
|
||||
|
||||
decrypter := cipher.NewCFBDecrypter(this.block, this.iv)
|
||||
decrypter.XORKeyStream(src, dst)
|
||||
|
||||
return
|
||||
}
|
||||
45
EdgePlus/pkg/encrypt/method_aes_192_cfb_test.go
Normal file
45
EdgePlus/pkg/encrypt/method_aes_192_cfb_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAES192CFBMethod_Encrypt(t *testing.T) {
|
||||
method, err := NewMethodInstance("aes-192-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := []byte("Hello, World")
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst = dst[:len(src)]
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src, err = method.Decrypt(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
|
||||
func BenchmarkAES192CFBMethod_Encrypt(b *testing.B) {
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
method, err := NewMethodInstance("aes-192-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
src := []byte(strings.Repeat("Hello", 1024))
|
||||
for i := 0; i < b.N; i++ {
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_ = dst
|
||||
}
|
||||
}
|
||||
72
EdgePlus/pkg/encrypt/method_aes_256_cfb.go
Normal file
72
EdgePlus/pkg/encrypt/method_aes_256_cfb.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package encrypt
|
||||
|
||||
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() {
|
||||
err = RecoverMethodPanic(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() {
|
||||
err = RecoverMethodPanic(recover())
|
||||
}()
|
||||
|
||||
src = make([]byte, len(dst))
|
||||
decrypter := cipher.NewCFBDecrypter(this.block, this.iv)
|
||||
decrypter.XORKeyStream(src, dst)
|
||||
|
||||
return
|
||||
}
|
||||
42
EdgePlus/pkg/encrypt/method_aes_256_cfb_test.go
Normal file
42
EdgePlus/pkg/encrypt/method_aes_256_cfb_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package encrypt
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAES256CFBMethod_Encrypt(t *testing.T) {
|
||||
method, err := NewMethodInstance("aes-256-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := []byte("Hello, World")
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst = dst[:len(src)]
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src, err = method.Decrypt(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
|
||||
func TestAES256CFBMethod_Encrypt2(t *testing.T) {
|
||||
method, err := NewMethodInstance("aes-256-cfb", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := []byte("Hello, World")
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src, err = method.Decrypt(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
26
EdgePlus/pkg/encrypt/method_raw.go
Normal file
26
EdgePlus/pkg/encrypt/method_raw.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package encrypt
|
||||
|
||||
type RawMethod struct {
|
||||
}
|
||||
|
||||
func (this *RawMethod) Init(key, iv []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *RawMethod) Encrypt(src []byte) (dst []byte, err error) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
dst = make([]byte, len(src))
|
||||
copy(dst, src)
|
||||
return
|
||||
}
|
||||
|
||||
func (this *RawMethod) Decrypt(dst []byte) (src []byte, err error) {
|
||||
if len(dst) == 0 {
|
||||
return
|
||||
}
|
||||
src = make([]byte, len(dst))
|
||||
copy(src, dst)
|
||||
return
|
||||
}
|
||||
23
EdgePlus/pkg/encrypt/method_raw_test.go
Normal file
23
EdgePlus/pkg/encrypt/method_raw_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package encrypt
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRawMethod_Encrypt(t *testing.T) {
|
||||
method, err := NewMethodInstance("raw", "abc", "123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := []byte("Hello, World")
|
||||
dst, err := method.Encrypt(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst = dst[:len(src)]
|
||||
t.Log("dst:", string(dst))
|
||||
|
||||
src, err = method.Decrypt(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("src:", string(src))
|
||||
}
|
||||
43
EdgePlus/pkg/encrypt/method_utils.go
Normal file
43
EdgePlus/pkg/encrypt/method_utils.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var methods = map[string]reflect.Type{
|
||||
"raw": reflect.TypeOf(new(RawMethod)).Elem(),
|
||||
"aes-128-cfb": reflect.TypeOf(new(AES128CFBMethod)).Elem(),
|
||||
"aes-192-cfb": reflect.TypeOf(new(AES192CFBMethod)).Elem(),
|
||||
"aes-256-cfb": reflect.TypeOf(new(AES256CFBMethod)).Elem(),
|
||||
}
|
||||
|
||||
func NewMethodInstance(method string, key string, iv string) (MethodInterface, error) {
|
||||
valueType, ok := methods[method]
|
||||
if !ok {
|
||||
return nil, errors.New("method '" + method + "' not found")
|
||||
}
|
||||
instance, ok := reflect.New(valueType).Interface().(MethodInterface)
|
||||
if !ok {
|
||||
return nil, errors.New("method '" + method + "' must implement MethodInterface")
|
||||
}
|
||||
err := instance.Init([]byte(key), []byte(iv))
|
||||
return instance, err
|
||||
}
|
||||
|
||||
func RecoverMethodPanic(err interface{}) error {
|
||||
if err != nil {
|
||||
s, ok := err.(string)
|
||||
if ok {
|
||||
return errors.New(s)
|
||||
}
|
||||
|
||||
e, ok := err.(error)
|
||||
if ok {
|
||||
return e
|
||||
}
|
||||
|
||||
return errors.New("unknown error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
8
EdgePlus/pkg/encrypt/method_utils_test.go
Normal file
8
EdgePlus/pkg/encrypt/method_utils_test.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package encrypt
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFindMethodInstance(t *testing.T) {
|
||||
t.Log(NewMethodInstance("a", "b", ""))
|
||||
t.Log(NewMethodInstance("aes-256-cfb", "123456", ""))
|
||||
}
|
||||
162
EdgePlus/pkg/utils/cmd.go
Normal file
162
EdgePlus/pkg/utils/cmd.go
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cmd struct {
|
||||
name string
|
||||
args []string
|
||||
env []string
|
||||
dir string
|
||||
|
||||
ctx context.Context
|
||||
timeout time.Duration
|
||||
cancelFunc func()
|
||||
|
||||
captureStdout bool
|
||||
captureStderr bool
|
||||
|
||||
stdout *bytes.Buffer
|
||||
stderr *bytes.Buffer
|
||||
|
||||
rawCmd *exec.Cmd
|
||||
}
|
||||
|
||||
func NewCmd(name string, args ...string) *Cmd {
|
||||
return &Cmd{
|
||||
name: name,
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTimeoutCmd(timeout time.Duration, name string, args ...string) *Cmd {
|
||||
return (&Cmd{
|
||||
name: name,
|
||||
args: args,
|
||||
}).WithTimeout(timeout)
|
||||
}
|
||||
|
||||
func (this *Cmd) WithTimeout(timeout time.Duration) *Cmd {
|
||||
this.timeout = timeout
|
||||
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
|
||||
this.ctx = ctx
|
||||
this.cancelFunc = cancelFunc
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cmd) WithStdout() *Cmd {
|
||||
this.captureStdout = true
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cmd) WithStderr() *Cmd {
|
||||
this.captureStderr = true
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cmd) WithEnv(env []string) *Cmd {
|
||||
this.env = env
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cmd) WithDir(dir string) *Cmd {
|
||||
this.dir = dir
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Cmd) Start() error {
|
||||
var cmd = this.compose()
|
||||
return cmd.Start()
|
||||
}
|
||||
|
||||
func (this *Cmd) Wait() error {
|
||||
var cmd = this.compose()
|
||||
return cmd.Wait()
|
||||
}
|
||||
|
||||
func (this *Cmd) Run() error {
|
||||
if this.cancelFunc != nil {
|
||||
defer this.cancelFunc()
|
||||
}
|
||||
|
||||
var cmd = this.compose()
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func (this *Cmd) RawStdout() string {
|
||||
if this.stdout != nil {
|
||||
return this.stdout.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Cmd) Stdout() string {
|
||||
return strings.TrimSpace(this.RawStdout())
|
||||
}
|
||||
|
||||
func (this *Cmd) RawStderr() string {
|
||||
if this.stderr != nil {
|
||||
return this.stderr.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Cmd) Stderr() string {
|
||||
return strings.TrimSpace(this.RawStderr())
|
||||
}
|
||||
|
||||
func (this *Cmd) String() string {
|
||||
if this.rawCmd != nil {
|
||||
return this.rawCmd.String()
|
||||
}
|
||||
var newCmd = exec.Command(this.name, this.args...)
|
||||
return newCmd.String()
|
||||
}
|
||||
|
||||
func (this *Cmd) Process() *os.Process {
|
||||
if this.rawCmd != nil {
|
||||
return this.rawCmd.Process
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Cmd) compose() *exec.Cmd {
|
||||
if this.rawCmd != nil {
|
||||
return this.rawCmd
|
||||
}
|
||||
|
||||
if this.ctx != nil {
|
||||
this.rawCmd = exec.CommandContext(this.ctx, this.name, this.args...)
|
||||
} else {
|
||||
this.rawCmd = exec.Command(this.name, this.args...)
|
||||
}
|
||||
|
||||
if this.env != nil {
|
||||
this.rawCmd.Env = this.env
|
||||
}
|
||||
|
||||
if len(this.dir) > 0 {
|
||||
this.rawCmd.Dir = this.dir
|
||||
}
|
||||
|
||||
if this.captureStdout {
|
||||
this.stdout = &bytes.Buffer{}
|
||||
this.rawCmd.Stdout = this.stdout
|
||||
}
|
||||
if this.captureStderr {
|
||||
this.stderr = &bytes.Buffer{}
|
||||
this.rawCmd.Stderr = this.stderr
|
||||
}
|
||||
|
||||
return this.rawCmd
|
||||
}
|
||||
98
EdgePlus/pkg/utils/components.go
Normal file
98
EdgePlus/pkg/utils/components.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils
|
||||
|
||||
type ComponentCode = string
|
||||
|
||||
const (
|
||||
ComponentCodeUser ComponentCode = "user"
|
||||
ComponentCodeScheduling ComponentCode = "scheduling"
|
||||
ComponentCodeMonitor ComponentCode = "monitor"
|
||||
ComponentCodeLog ComponentCode = "log"
|
||||
ComponentCodeReporter ComponentCode = "reporter"
|
||||
ComponentCodePlan ComponentCode = "plan"
|
||||
ComponentCodeFinance ComponentCode = "finance"
|
||||
ComponentCodeNS ComponentCode = "ns"
|
||||
ComponentCodeL2Node ComponentCode = "l2node"
|
||||
ComponentCodeTicket ComponentCode = "ticket"
|
||||
ComponentCodeAntiDDoS ComponentCode = "antiDDoS"
|
||||
ComponentCodeCloudNative ComponentCode = "cloudNative"
|
||||
)
|
||||
|
||||
type Edition = string
|
||||
|
||||
const (
|
||||
EditionBasic Edition = "basic" // 个人商业版
|
||||
EditionPro Edition = "pro" // 专业版
|
||||
EditionEnt Edition = "ent" // 企业版
|
||||
EditionMax Edition = "max" // [待命名]
|
||||
EditionUltra Edition = "ultra" // 旗舰版
|
||||
)
|
||||
|
||||
type ComponentDefinition struct {
|
||||
Name string `json:"name"`
|
||||
Code ComponentCode `json:"code"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func FindAllComponents() []*ComponentDefinition {
|
||||
return []*ComponentDefinition{
|
||||
{
|
||||
Name: "多租户",
|
||||
Code: ComponentCodeUser,
|
||||
},
|
||||
{
|
||||
Name: "智能调度",
|
||||
Code: ComponentCodeScheduling,
|
||||
},
|
||||
{
|
||||
Name: "监控",
|
||||
Code: ComponentCodeMonitor,
|
||||
},
|
||||
{
|
||||
Name: "日志",
|
||||
Code: ComponentCodeLog,
|
||||
},
|
||||
{
|
||||
Name: "区域监控",
|
||||
Code: ComponentCodeReporter,
|
||||
},
|
||||
{
|
||||
Name: "套餐",
|
||||
Code: ComponentCodePlan,
|
||||
},
|
||||
{
|
||||
Name: "财务",
|
||||
Code: ComponentCodeFinance,
|
||||
},
|
||||
{
|
||||
Name: "智能DNS",
|
||||
Code: ComponentCodeNS,
|
||||
},
|
||||
{
|
||||
Name: "L2节点",
|
||||
Code: ComponentCodeL2Node,
|
||||
},
|
||||
{
|
||||
Name: "工单系统",
|
||||
Code: ComponentCodeTicket,
|
||||
},
|
||||
{
|
||||
Name: "高防IP",
|
||||
Code: ComponentCodeAntiDDoS,
|
||||
},
|
||||
/**{
|
||||
Name: "云原生部署",
|
||||
Code: ComponentCodeCloudNative,
|
||||
},**/
|
||||
}
|
||||
}
|
||||
|
||||
func CheckComponent(code string) bool {
|
||||
for _, c := range FindAllComponents() {
|
||||
if c.Code == code {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
82
EdgePlus/pkg/utils/edition.go
Normal file
82
EdgePlus/pkg/utils/edition.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
type EditionDefinition struct {
|
||||
Name string `json:"name"`
|
||||
Code ComponentCode `json:"code"`
|
||||
MaxNodes int `json:"maxNodes"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func FindAllEditions() []*EditionDefinition {
|
||||
return []*EditionDefinition{
|
||||
{
|
||||
Name: "个人商业版",
|
||||
Code: EditionBasic,
|
||||
MaxNodes: 20,
|
||||
},
|
||||
{
|
||||
Name: "专业版",
|
||||
Code: EditionPro,
|
||||
MaxNodes: 100,
|
||||
},
|
||||
{
|
||||
Name: "企业版",
|
||||
Code: EditionEnt,
|
||||
MaxNodes: 500,
|
||||
},
|
||||
{
|
||||
Name: "豪华版",
|
||||
Code: EditionMax,
|
||||
MaxNodes: 1000, // TODO 未定
|
||||
},
|
||||
{
|
||||
Name: "旗舰版",
|
||||
Code: EditionUltra,
|
||||
MaxNodes: 1000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CheckEdition(edition Edition) bool {
|
||||
for _, e := range FindAllEditions() {
|
||||
if e.Code == edition {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CompareEdition(edition1 Edition, edition2 Edition) int {
|
||||
var index1 = -1
|
||||
var index2 = -1
|
||||
|
||||
for index, edition := range FindAllEditions() {
|
||||
if edition.Code == edition1 {
|
||||
index1 = index
|
||||
}
|
||||
if edition.Code == edition2 {
|
||||
index2 = index
|
||||
}
|
||||
}
|
||||
if index2 > index1 {
|
||||
return -1
|
||||
}
|
||||
if index2 == index1 {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func EditionName(edition Edition) string {
|
||||
if len(edition) == 0 {
|
||||
return ""
|
||||
}
|
||||
for _, e := range FindAllEditions() {
|
||||
if e.Code == edition {
|
||||
return e.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
14
EdgePlus/pkg/utils/edition_test.go
Normal file
14
EdgePlus/pkg/utils/edition_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCompareEdition(t *testing.T) {
|
||||
t.Log(CompareEdition("", ""))
|
||||
t.Log(CompareEdition("", "pro"))
|
||||
t.Log(CompareEdition("basic", "pro"))
|
||||
t.Log(CompareEdition("pro", "pro"))
|
||||
t.Log(CompareEdition("ent", "pro"))
|
||||
t.Log(CompareEdition("pro", "basic"))
|
||||
}
|
||||
130
EdgePlus/pkg/utils/encoder.go
Normal file
130
EdgePlus/pkg/utils/encoder.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgePlus/pkg/const"
|
||||
"github.com/TeaOSLab/EdgePlus/pkg/encrypt"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Encode 加密
|
||||
func Encode(data []byte) (string, error) {
|
||||
instance, err := encrypt.NewMethodInstance("aes-256-cfb", teaconst.PlusKey, teaconst.PlusIV)
|
||||
if err != nil {
|
||||
return "", errors.New("不支持选择的加密方式")
|
||||
}
|
||||
dist, err := instance.Encrypt(data)
|
||||
if err != nil {
|
||||
return "", errors.New("加密失败:" + err.Error())
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(dist), nil
|
||||
}
|
||||
|
||||
// EncodeMap 加密Map
|
||||
func EncodeMap(m maps.Map) (string, error) {
|
||||
m["updatedAt"] = time.Now().Unix() // 用来校验Authority服务是否已经更新
|
||||
|
||||
data, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Encode(data)
|
||||
}
|
||||
|
||||
// DecodeData 解密
|
||||
func DecodeData(data []byte) (maps.Map, error) {
|
||||
instance, err := encrypt.NewMethodInstance("aes-256-cfb", teaconst.PlusKey, teaconst.PlusIV)
|
||||
if err != nil {
|
||||
return nil, errors.New("encrypt method not supported")
|
||||
}
|
||||
source, err := base64.StdEncoding.DecodeString(string(bytes.TrimSpace(data)))
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: base64 decode failed: " + err.Error())
|
||||
}
|
||||
dist, err := instance.Decrypt(source)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: decrypt failed: " + err.Error())
|
||||
}
|
||||
var m = maps.Map{}
|
||||
err = json.Unmarshal(dist, &m)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: decode json failed: " + err.Error())
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func Decode(data []byte) (maps.Map, error) {
|
||||
m, err := DecodeData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 控制 STILL 用户权限
|
||||
if m.GetString("company") == "STILL" {
|
||||
m["components"] = []ComponentCode{
|
||||
ComponentCodeLog,
|
||||
ComponentCodeNS,
|
||||
ComponentCodeUser,
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.GetString("dayFrom")) == 0 || len(m.GetString("dayTo")) == 0 || m.GetInt("nodes") <= 0 {
|
||||
return nil, errors.New("invalid key")
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// EncodeKey 加密Key
|
||||
func EncodeKey(key *Key) (string, error) {
|
||||
key.UpdatedAt = time.Now().Unix() // 用来校验Authority服务是否已经更新
|
||||
data, err := json.Marshal(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Encode(data)
|
||||
}
|
||||
|
||||
// DecodeKey 解密Key
|
||||
func DecodeKey(data []byte) (*Key, error) {
|
||||
instance, err := encrypt.NewMethodInstance("aes-256-cfb", teaconst.PlusKey, teaconst.PlusIV)
|
||||
if err != nil {
|
||||
return nil, errors.New("encrypt method not supported")
|
||||
}
|
||||
source, err := base64.StdEncoding.DecodeString(string(bytes.TrimSpace(data)))
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: base64 decode failed: " + err.Error())
|
||||
}
|
||||
dist, err := instance.Decrypt(source)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: decrypt failed: " + err.Error())
|
||||
}
|
||||
|
||||
var result = &Key{}
|
||||
err = json.Unmarshal(dist, result)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode key failed: " + err.Error())
|
||||
}
|
||||
|
||||
// 这里不能限制节点,因为以往有不限节点的授权
|
||||
if len(result.DayFrom) == 0 || len(result.DayTo) == 0 {
|
||||
return nil, errors.New("invalid key")
|
||||
}
|
||||
|
||||
// 控制 STILL 用户权限
|
||||
if result.Company == "STILL" {
|
||||
result.Components = []ComponentCode{
|
||||
ComponentCodeLog,
|
||||
ComponentCodeNS,
|
||||
ComponentCodeUser,
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
46
EdgePlus/pkg/utils/encoder_test.go
Normal file
46
EdgePlus/pkg/utils/encoder_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncodeMap(t *testing.T) {
|
||||
{
|
||||
t.Log(Encode([]byte("123")))
|
||||
}
|
||||
{
|
||||
s, err := EncodeMap(maps.Map{"a": 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(s)
|
||||
|
||||
t.Log(Decode([]byte(s)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeKey(t *testing.T) {
|
||||
var key = &Key{
|
||||
DayFrom: "2020-10-10",
|
||||
DayTo: "2022-10-10",
|
||||
MacAddresses: []string{"*"},
|
||||
Hostname: "web001",
|
||||
Company: "STILL",
|
||||
Nodes: 10,
|
||||
}
|
||||
encodedString, err := EncodeKey(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("encoded:", encodedString)
|
||||
|
||||
key, err = DecodeKey([]byte(encodedString))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(key, t)
|
||||
}
|
||||
25
EdgePlus/pkg/utils/key.go
Normal file
25
EdgePlus/pkg/utils/key.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package utils
|
||||
|
||||
import timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
|
||||
type Key struct {
|
||||
Id string `json:"id"` // 用户ID
|
||||
DayFrom string `json:"dayFrom"` // 开始日期
|
||||
DayTo string `json:"dayTo"` // 结束日期
|
||||
MacAddresses []string `json:"macAddresses"` // MAC地址,老的授权方式
|
||||
RequestCode string `json:"requestCode"` // 授权请求码
|
||||
Hostname string `json:"hostname"` // 主机名
|
||||
Company string `json:"company"` // 公司名
|
||||
Nodes int `json:"nodes"` // 节点数
|
||||
UpdatedAt int64 `json:"updatedAt"` // 更新时间
|
||||
Components []ComponentCode `json:"components"` // 组件
|
||||
Edition Edition `json:"edition"` // 授权版本
|
||||
Email string `json:"email"` // 联系人邮箱
|
||||
Method Method `json:"method"` // 验证方法
|
||||
}
|
||||
|
||||
func (this *Key) IsValid() bool {
|
||||
return this.DayTo >= timeutil.Format("Y-m-d")
|
||||
}
|
||||
24
EdgePlus/pkg/utils/method.go
Normal file
24
EdgePlus/pkg/utils/method.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
type Method = string
|
||||
|
||||
const (
|
||||
MethodLocal Method = "local"
|
||||
MethodRemote Method = "remote"
|
||||
)
|
||||
|
||||
func IsValidMethod(method string) bool {
|
||||
return method == MethodLocal || method == MethodRemote
|
||||
}
|
||||
|
||||
func MethodName(method Method) string {
|
||||
switch method {
|
||||
case MethodLocal:
|
||||
return "离线"
|
||||
case MethodRemote:
|
||||
return "远程"
|
||||
}
|
||||
return "离线"
|
||||
}
|
||||
288
EdgePlus/pkg/utils/request_key.go
Normal file
288
EdgePlus/pkg/utils/request_key.go
Normal file
@@ -0,0 +1,288 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RequestKey 申请码
|
||||
type RequestKey struct {
|
||||
MacAddresses []string `json:"macAddresses"` // MAC 排序后内容
|
||||
MachineId string `json:"machineId"` // /etc/machine-id
|
||||
HardwareUUID string `json:"hardwareUUID"` // hardware disk uuid
|
||||
}
|
||||
|
||||
// GenerateRequestKey 生成请求Key
|
||||
func GenerateRequestKey() (*RequestKey, error) {
|
||||
// mac addresses
|
||||
netInterfaces, err := findAllNetInterfaces()
|
||||
if err != nil {
|
||||
return nil, errors.New("could not generate request key (code: 001)")
|
||||
}
|
||||
|
||||
var macAddrs = []string{}
|
||||
for _, netInterface := range netInterfaces {
|
||||
var macAddr = strings.TrimSpace(netInterface.HardwareAddr.String())
|
||||
if len(macAddr) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !lists.ContainsString(macAddrs, macAddr) {
|
||||
macAddrs = append(macAddrs, macAddr)
|
||||
}
|
||||
}
|
||||
if len(macAddrs) == 0 {
|
||||
return nil, errors.New("could not generate request key (code: 002)")
|
||||
}
|
||||
sort.Strings(macAddrs)
|
||||
|
||||
// machine id
|
||||
var machineId = ""
|
||||
var machineIdFile = "/etc/machine-id"
|
||||
stat, err := os.Stat(machineIdFile)
|
||||
if err == nil && !stat.IsDir() {
|
||||
data, err := os.ReadFile(machineIdFile)
|
||||
data = bytes.TrimSpace(data)
|
||||
if err == nil && len(data) <= 32 {
|
||||
machineId = string(data)
|
||||
}
|
||||
}
|
||||
|
||||
return &RequestKey{
|
||||
MacAddresses: macAddrs,
|
||||
MachineId: machineId,
|
||||
HardwareUUID: generateHardwareUUID(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateRequestCode 生成请求Key代码
|
||||
func GenerateRequestCode() (string, error) {
|
||||
key, err := GenerateRequestKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
keyJSON, err := json.Marshal(key)
|
||||
if err != nil {
|
||||
return "", errors.New("could not generate request code (code: 001)")
|
||||
}
|
||||
return Encode(keyJSON)
|
||||
}
|
||||
|
||||
// DecodeRequestCode 解析请求Key代码
|
||||
func DecodeRequestCode(requestCode string) (*RequestKey, error) {
|
||||
requestCode = regexp.MustCompile(`\s+`).ReplaceAllString(requestCode, "")
|
||||
|
||||
if requestCode == "*" {
|
||||
return &RequestKey{
|
||||
MacAddresses: nil,
|
||||
MachineId: "",
|
||||
}, nil
|
||||
}
|
||||
m, err := DecodeData([]byte(requestCode))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonData, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var key = &RequestKey{}
|
||||
err = json.Unmarshal(jsonData, key)
|
||||
return key, err
|
||||
}
|
||||
|
||||
// ValidateRequestCode 校验请求Key代码
|
||||
func ValidateRequestCode(requestCode string) (ok bool, errorCode string) {
|
||||
requestCode = regexp.MustCompile(`\s+`).ReplaceAllString(requestCode, "")
|
||||
|
||||
if requestCode == "*" {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
key, err := DecodeRequestCode(requestCode)
|
||||
if err != nil {
|
||||
return false, "001"
|
||||
}
|
||||
|
||||
// check machine id
|
||||
if len(key.MachineId) > 0 {
|
||||
// machine id
|
||||
var machineId = ""
|
||||
var machineIdFile = "/etc/machine-id"
|
||||
stat, err := os.Stat(machineIdFile)
|
||||
if err == nil && !stat.IsDir() {
|
||||
data, err := os.ReadFile(machineIdFile)
|
||||
data = bytes.TrimSpace(data)
|
||||
if err == nil && len(data) <= 32 {
|
||||
machineId = string(data)
|
||||
}
|
||||
}
|
||||
if machineId != key.MachineId {
|
||||
return false, "004"
|
||||
}
|
||||
}
|
||||
|
||||
// hardware uuid
|
||||
if len(key.HardwareUUID) > 0 && key.HardwareUUID == generateHardwareUUID() {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// mac addresses
|
||||
netInterfaces, err := findAllNetInterfaces()
|
||||
if err != nil {
|
||||
return false, "002"
|
||||
}
|
||||
|
||||
// remove net interfaces related to docker
|
||||
{
|
||||
var cmd = NewTimeoutCmd(5*time.Second, "docker", "network", "ls")
|
||||
cmd.WithStdout()
|
||||
err = cmd.Run()
|
||||
if err == nil {
|
||||
var dockerIdRegexp = regexp.MustCompile(`^[0-9a-f]{12,}$`)
|
||||
var spaceRegexp = regexp.MustCompile(`\s+`)
|
||||
|
||||
var stdoutLines = strings.Split(cmd.Stdout(), "\n")
|
||||
var dockerInterfaceIds []string
|
||||
var dockerInterfaceNames []string
|
||||
for _, line := range stdoutLines {
|
||||
var pieces = spaceRegexp.Split(strings.TrimSpace(line), -1)
|
||||
if len(pieces) <= 3 {
|
||||
continue
|
||||
}
|
||||
var piece0 = strings.TrimSpace(pieces[0])
|
||||
if !dockerIdRegexp.MatchString(piece0) {
|
||||
continue
|
||||
}
|
||||
dockerInterfaceIds = append(dockerInterfaceIds, piece0)
|
||||
|
||||
var piece1 = strings.TrimSpace(pieces[1])
|
||||
if len(piece1) > 0 {
|
||||
dockerInterfaceNames = append(dockerInterfaceNames, piece1)
|
||||
}
|
||||
}
|
||||
|
||||
var newInterfaces []net.Interface
|
||||
for _, i := range netInterfaces {
|
||||
var skip bool
|
||||
for _, dockerInterfaceId := range dockerInterfaceIds {
|
||||
if strings.HasSuffix(i.Name, dockerInterfaceId) {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !skip {
|
||||
skip = lists.ContainsString(dockerInterfaceNames, i.Name)
|
||||
}
|
||||
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
newInterfaces = append(newInterfaces, i)
|
||||
}
|
||||
netInterfaces = newInterfaces
|
||||
}
|
||||
}
|
||||
|
||||
var allMACAddresses = []string{}
|
||||
for _, netInterface := range netInterfaces {
|
||||
var macAddr = strings.TrimSpace(netInterface.HardwareAddr.String())
|
||||
if len(macAddr) == 0 {
|
||||
continue
|
||||
}
|
||||
allMACAddresses = append(allMACAddresses, macAddr)
|
||||
}
|
||||
|
||||
// check mac addresses
|
||||
for _, macAddress := range allMACAddresses {
|
||||
if !lists.ContainsString(key.MacAddresses, macAddress) {
|
||||
return false, "003"
|
||||
}
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func findAllNetInterfaces() ([]net.Interface, error) {
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var dockerReg = regexp.MustCompile(`^docker\d+$`)
|
||||
var resultInterfaces []net.Interface
|
||||
for _, i := range interfaces {
|
||||
if i.Flags&net.FlagLoopback == net.FlagLoopback {
|
||||
continue
|
||||
}
|
||||
|
||||
// ignore docker
|
||||
if dockerReg.MatchString(i.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if i.Flags&net.FlagUp == net.FlagUp {
|
||||
resultInterfaces = append(resultInterfaces, i)
|
||||
}
|
||||
}
|
||||
|
||||
return resultInterfaces, nil
|
||||
}
|
||||
|
||||
func generateHardwareUUID() string {
|
||||
if runtime.GOOS != "linux" {
|
||||
return ""
|
||||
}
|
||||
|
||||
var diskUUID string
|
||||
{
|
||||
var cmd = NewCmd("ls", "/dev/disk/by-uuid")
|
||||
cmd.WithStdout()
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var stdout = strings.TrimSpace(cmd.Stdout())
|
||||
if len(stdout) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var pieces = regexp.MustCompile(`\s+`).Split(stdout, -1)
|
||||
sort.Strings(pieces)
|
||||
diskUUID = stringutil.Md5(strings.Join(pieces, "\n"))
|
||||
}
|
||||
|
||||
var hardwareUUID string
|
||||
{
|
||||
var cmd = NewCmd("dmidecode")
|
||||
cmd.WithStdout()
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var stdout = strings.TrimSpace(cmd.Stdout())
|
||||
if len(stdout) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
hardwareUUID = stringutil.Md5(stdout)
|
||||
}
|
||||
|
||||
return stringutil.Md5(diskUUID + hardwareUUID)
|
||||
}
|
||||
62
EdgePlus/pkg/utils/request_key_test.go
Normal file
62
EdgePlus/pkg/utils/request_key_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgePlus/pkg/utils"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateRequestKey(t *testing.T) {
|
||||
requestKey, err := utils.GenerateRequestKey()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("request key: %+v", requestKey)
|
||||
}
|
||||
|
||||
func TestGenerateRequestCode(t *testing.T) {
|
||||
requestCode, err := utils.GenerateRequestCode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("request code:", "["+types.String(len(requestCode))+"]", requestCode)
|
||||
requestKey, err := utils.DecodeRequestCode(requestCode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", requestKey)
|
||||
t.Log("mac addresses:", len(requestKey.MacAddresses))
|
||||
}
|
||||
|
||||
func TestDecodeRequestCode(t *testing.T) {
|
||||
var requestCode = `F4BqUMBxDHPFsd4mIDUiSfiRor473+ctxycygBwxZUyqDZppJrlAjnT5E6qyH7Yb64icvlkCqiEPYbOkxh9TUhWHuoqsGAKcO+6vFaelBeojnlVXkg==`
|
||||
requestKey, err := utils.DecodeRequestCode(requestCode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", requestKey)
|
||||
}
|
||||
|
||||
func TestValidateRequestCode(t *testing.T) {
|
||||
{
|
||||
ok, errorCode := utils.ValidateRequestCode("123456")
|
||||
t.Log("ok:", ok, "errorCode:", errorCode)
|
||||
}
|
||||
|
||||
{
|
||||
requestCode, err := utils.GenerateRequestCode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ok, errorCode := utils.ValidateRequestCode(requestCode)
|
||||
t.Log("ok:", ok, "errorCode:", errorCode)
|
||||
}
|
||||
|
||||
{
|
||||
var requestCode = "F4BqUMBxDHPFsd4mIDUiSfiRpr471egtmnMyhx0xbxQeuEsuqXRiFtveCJGaELzffDATN5ULoP+Q/Y3NxsXNsvtxl9VkTA4VFq1s7b83BJVy6h3hKgwvhVw9H2upOf9aouD26JFZwr0ncM+cQGda3z64wOg3TFj8KhoM+ixaFY9SO0o3fg+0R8tKxA6rjGn/Do/CgKJTb4fF/tGGZ6QFY3UbO4KObaDmJrAQWag9IGKE5/GGOyBYWI9S45Auf6ee39X5JToDJHVJt3BV1fNNu3D9OrS+mg2SKLHhQdps7E5zor+K7Shhx8KV85qkdEImR+BA2rrxEDfcJz6+lQ=="
|
||||
ok, errorCode := utils.ValidateRequestCode(requestCode)
|
||||
t.Log("ok:", ok, "errorCode:", errorCode)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user