plugai_updsrv/pkg/utils/hash.go

159 lines
3.8 KiB
Go

package utils
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/civet148/log"
"net/url"
"reflect"
"sort"
"strings"
)
const (
TAG_VALUE_IGNORE = "-"
TAG_NAME_JSON = "json"
)
var tagNames = []string{TAG_NAME_JSON}
//MakeSignString make a sign string sort by alpha character
// obj can be url.Values, struct with json tag or map[string]interface{}
func MakeSignString(obj interface{}, excepts ...string) string {
var strSort string
if values, ok := obj.(url.Values); ok {
dic := make(map[string]interface{}, 0)
for k, v := range values {
if len(v) > 0 {
dic[k] = v[0]
}
}
strSort = makeSignStringByMap(dic, excepts...)
} else {
typ := reflect.TypeOf(obj)
val := reflect.ValueOf(obj)
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
switch typ.Kind() {
case reflect.String:
strSort = obj.(string)
case reflect.Map:
strSort = makeSignStringByMap(obj.(map[string]interface{}), excepts...)
case reflect.Struct:
strSort = makeSignStringByStruct(typ, val, excepts...)
default:
log.Errorf("object type [%s] not support", typ.Name())
}
}
return strSort
}
func MakeSignSHA256Hex(obj interface{}, excepts ...string) string {
strToSign := MakeSignString(obj, excepts...)
digestHash := sha256.Sum256([]byte(strToSign))
return hex.EncodeToString(digestHash[:])
}
func MakeSignSHA256(obj interface{}, excepts ...string) []byte {
strToSign := MakeSignString(obj, excepts...)
digestHash := sha256.Sum256([]byte(strToSign))
return digestHash[:]
}
func makeSignStringByStruct(typ reflect.Type, val reflect.Value, excepts ...string) string {
dic := parseStructFields(typ, val, tagNames...)
return makeSignStringByMap(dic, excepts...)
}
func makeSignStringByMap(dic map[string]interface{}, excepts ...string) string {
var keys, values []string
for _, v := range excepts {
delete(dic, v)
}
for k, _ := range dic {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
if strings.Compare(keys[i], keys[j]) < 0 {
return true
}
return false
})
for _, key := range keys {
v := fmt.Sprintf("%s=%v", key, dic[key])
values = append(values, v)
}
return strings.Join(values, "&")
}
// parse struct fields
func parseStructFields(typ reflect.Type, val reflect.Value, tagNames ...string) (dic map[string]interface{}) {
kind := typ.Kind()
dic = make(map[string]interface{}, 0)
if kind == reflect.Struct {
NumField := val.NumField()
for i := 0; i < NumField; i++ {
typField := typ.Field(i)
valField := val.Field(i)
if typField.Type.Kind() == reflect.Ptr {
typField.Type = typField.Type.Elem()
valField = valField.Elem()
}
if !valField.IsValid() || !valField.CanInterface() {
continue
}
saveValueByField(dic, typField, valField, tagNames...) // save field tag value and field value to map
}
}
return dic
}
//trim the field value's first and last blank character and save to map
func saveValueByField(dic map[string]interface{}, field reflect.StructField, val reflect.Value, tagNames ...string) {
if len(tagNames) == 0 {
log.Errorf("no tag to save value")
return
}
var tagVal string
for _, v := range tagNames {
strTagValue, ignore := getTag(field, v)
tagVal = handleTagValue(v, strTagValue)
if ignore {
break
}
if tagVal == "" {
tagVal = field.Name
}
dic[tagVal] = fmt.Sprintf("%v", val.Interface())
}
}
// get struct field's tag value
func getTag(sf reflect.StructField, tagName string) (strValue string, ignore bool) {
strValue = sf.Tag.Get(tagName)
if strValue == TAG_VALUE_IGNORE {
return "", true
}
return
}
func handleTagValue(strTagName, strTagValue string) string {
if strTagValue == "" {
return ""
}
if strTagName == TAG_NAME_JSON {
vs := strings.Split(strTagValue, ",")
strTagValue = vs[0]
}
return strTagValue
}