// This file is auto-generated, don't edit it. Thanks. package utils import ( "bytes" "crypto" "crypto/hmac" "crypto/md5" "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" "encoding/pem" "errors" "fmt" "hash" "io" "io/ioutil" mathRand "math/rand" "net/http" "net/textproto" "net/url" "reflect" "runtime" "sort" "strconv" "strings" "sync/atomic" "time" models "github.com/alibabacloud-go/darabonba-openapi/v2/models" "github.com/alibabacloud-go/tea/dara" "github.com/tjfoc/gmsm/sm3" ) var defaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Core/%s TeaDSL/2", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), "0.01") var seqId int64 = 0 var processStartTime int64 = time.Now().UnixNano() / 1e6 const ( PEM_BEGIN = "-----BEGIN RSA PRIVATE KEY-----\n" PEM_END = "\n-----END RSA PRIVATE KEY-----" ) type Config = models.Config type GlobalParameters = models.GlobalParameters type Params = models.Params type OpenApiRequest = models.OpenApiRequest type Sorter struct { Keys []string Vals []string } func newSorter(m map[string]string) *Sorter { hs := &Sorter{ Keys: make([]string, 0, len(m)), Vals: make([]string, 0, len(m)), } for k, v := range m { hs.Keys = append(hs.Keys, k) hs.Vals = append(hs.Vals, v) } return hs } // Sort is an additional function for function SignHeader. func (hs *Sorter) Sort() { sort.Sort(hs) } // Len is an additional function for function SignHeader. func (hs *Sorter) Len() int { return len(hs.Vals) } // Less is an additional function for function SignHeader. func (hs *Sorter) Less(i, j int) bool { return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0 } // Swap is an additional function for function SignHeader. func (hs *Sorter) Swap(i, j int) { hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i] hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i] } // Description: // // This is for OpenApi Util // Description: // // # Convert all params of body other than type of readable into content // // @param body - source Model // // @param content - target Model // // @return void func Convert(body interface{}, content interface{}) { res := make(map[string]interface{}) val := reflect.ValueOf(body).Elem() dataType := val.Type() for i := 0; i < dataType.NumField(); i++ { field := dataType.Field(i) name, _ := field.Tag.Lookup("json") name = strings.Split(name, ",omitempty")[0] _, ok := val.Field(i).Interface().(io.Reader) if !ok { res[name] = val.Field(i).Interface() } } byt, _ := json.Marshal(res) json.Unmarshal(byt, content) } // Description: // // # Get throttling param // // @param the - response headers // // @return time left func GetThrottlingTimeLeft(headers map[string]*string) (_result *int64) { rateLimitForUserApi := headers["x-ratelimit-user-api"] rateLimitForUser := headers["x-ratelimit-user"] timeLeftForUserApi := getTimeLeft(rateLimitForUserApi) timeLeftForUser := getTimeLeft(rateLimitForUser) if dara.Int64Value(timeLeftForUserApi) > dara.Int64Value(timeLeftForUser) { return timeLeftForUserApi } else { return timeLeftForUser } } // Description: // // # Hash the raw data with signatureAlgorithm // // @param raw - hashing data // // @param signatureAlgorithm - the autograph method // // @return hashed bytes func Hash(raw []byte, signatureAlgorithm *string) (_result []byte) { signType := dara.StringValue(signatureAlgorithm) if signType == "ACS3-HMAC-SHA256" || signType == "ACS3-RSA-SHA256" { h := sha256.New() h.Write(raw) return h.Sum(nil) } else if signType == "ACS3-HMAC-SM3" { h := sm3.New() h.Write(raw) return h.Sum(nil) } return nil } func getGID() uint64 { // https://blog.sgmansfield.com/2015/12/goroutine-ids/ b := make([]byte, 64) b = b[:runtime.Stack(b, false)] b = bytes.TrimPrefix(b, []byte("goroutine ")) b = b[:bytes.IndexByte(b, ' ')] n, _ := strconv.ParseUint(string(b), 10, 64) return n } // Description: // // # Generate a nonce string // // @return the nonce string func GetNonce() (_result *string) { routineId := getGID() currentTime := time.Now().UnixNano() / 1e6 seq := atomic.AddInt64(&seqId, 1) randNum := mathRand.Int63() msg := fmt.Sprintf("%d-%d-%d-%d-%d", processStartTime, routineId, currentTime, seq, randNum) h := md5.New() h.Write([]byte(msg)) ret := hex.EncodeToString(h.Sum(nil)) return &ret } // Description: // // # Get the string to be signed according to request // // @param request - which contains signed messages // // @return the signed string func GetStringToSign(request *dara.Request) (_result *string) { return dara.String(getStringToSign(request)) } func getStringToSign(request *dara.Request) string { // sort QueryParams by key var queryKeys []string resource := dara.StringValue(request.Pathname) queryParams := request.Query for key := range queryParams { queryKeys = append(queryKeys, key) } sort.Strings(queryKeys) tmp := "" for i := 0; i < len(queryKeys); i++ { queryKey := queryKeys[i] v := dara.StringValue(queryParams[queryKey]) if v != "" { tmp = tmp + "&" + queryKey + "=" + v } else { tmp = tmp + "&" + queryKey } } if tmp != "" { tmp = strings.TrimLeft(tmp, "&") resource = resource + "?" + tmp } return getSignedStr(request, resource) } func getSignedStr(req *dara.Request, canonicalizedResource string) string { temp := make(map[string]string) for k, v := range req.Headers { if strings.HasPrefix(strings.ToLower(k), "x-acs-") { temp[strings.ToLower(k)] = dara.StringValue(v) } } hs := newSorter(temp) // Sort the temp by the ascending order hs.Sort() // Get the canonicalizedOSSHeaders canonicalizedOSSHeaders := "" for i := range hs.Keys { canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" } // Give other parameters values // when sign URL, date is expires date := dara.StringValue(req.Headers["date"]) accept := dara.StringValue(req.Headers["accept"]) contentType := dara.StringValue(req.Headers["content-type"]) contentMd5 := dara.StringValue(req.Headers["content-md5"]) signStr := dara.StringValue(req.Method) + "\n" + accept + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource return signStr } // Description: // // # Get signature according to stringToSign, secret // // @param stringToSign - the signed string // // @param secret - accesskey secret // // @return the signature func GetROASignature(stringToSign *string, secret *string) (_result *string) { h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(dara.StringValue(secret))) io.WriteString(h, dara.StringValue(stringToSign)) signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) return dara.String(signedStr) } // Description: // // # Parse filter into a form string // // @param filter - object // // @return the string func ToForm(filter map[string]interface{}) (_result *string) { tmp := make(map[string]interface{}) byt, _ := json.Marshal(filter) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() _ = d.Decode(&tmp) result := make(map[string]*string) for key, value := range tmp { filterValue := reflect.ValueOf(value) flatRepeatedList(filterValue, result, key) } m := make(map[string]interface{}) for key, value := range result { m[key] = dara.StringValue(value) } return dara.String(dara.ToFormString(m)) } func flatRepeatedList(dataValue reflect.Value, result map[string]*string, prefix string) { if !dataValue.IsValid() { return } dataType := dataValue.Type() if dataType.Kind().String() == "slice" { handleRepeatedParams(dataValue, result, prefix) } else if dataType.Kind().String() == "map" { handleMap(dataValue, result, prefix) } else { result[prefix] = dara.String(fmt.Sprintf("%v", dataValue.Interface())) } } func handleRepeatedParams(repeatedFieldValue reflect.Value, result map[string]*string, prefix string) { if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() { for m := 0; m < repeatedFieldValue.Len(); m++ { elementValue := repeatedFieldValue.Index(m) key := prefix + "." + strconv.Itoa(m+1) fieldValue := reflect.ValueOf(elementValue.Interface()) if fieldValue.Kind().String() == "map" { handleMap(fieldValue, result, key) } else { result[key] = dara.String(fmt.Sprintf("%v", fieldValue.Interface())) } } } } func handleMap(valueField reflect.Value, result map[string]*string, prefix string) { var byt []byte if valueField.IsValid() && valueField.String() != "" { valueFieldType := valueField.Type() if valueFieldType.Kind().String() == "map" { byt, _ = json.Marshal(valueField.Interface()) cache := make(map[string]interface{}) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() _ = d.Decode(&cache) for key, value := range cache { pre := "" if prefix != "" { pre = prefix + "." + key } else { pre = key } fieldValue := reflect.ValueOf(value) flatRepeatedList(fieldValue, result, pre) } } } } // Description: // // # Get timestamp // // @return the timestamp string func GetTimestamp() (_result *string) { gmt := time.FixedZone("GMT", 0) return dara.String(time.Now().In(gmt).Format("2006-01-02T15:04:05Z")) } // Description: // // # Get UTC string // // @return the UTC string func GetDateUTCString() (_result *string) { return dara.String(time.Now().UTC().Format(http.TimeFormat)) } // Description: // // Parse filter into a object which's type is map[string]string // // @param filter - query param // // @return the object func Query(filter interface{}) (_result map[string]*string) { tmp := make(map[string]interface{}) byt, _ := json.Marshal(filter) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() _ = d.Decode(&tmp) result := make(map[string]*string) for key, value := range tmp { filterValue := reflect.ValueOf(value) flatRepeatedList(filterValue, result, key) } return result } // Description: // // # Get signature according to signedParams, method and secret // // @param signedParams - params which need to be signed // // @param method - http method e.g. GET // // @param secret - AccessKeySecret // // @return the signature func GetRPCSignature(signedParams map[string]*string, method *string, secret *string) (_result *string) { stringToSign := buildRpcStringToSign(signedParams, dara.StringValue(method)) signature := sign(stringToSign, dara.StringValue(secret), "&") return dara.String(signature) } // Description: // // # Parse array into a string with specified style // // @param array - the array // // @param prefix - the prefix string // // @return the string func ArrayToStringWithSpecifiedStyle(array interface{}, prefix *string, style *string) (_result *string) { if dara.IsNil(array) { return dara.String("") } sty := dara.StringValue(style) if sty == "repeatList" { tmp := map[string]interface{}{ dara.StringValue(prefix): array, } return flatRepeatList(tmp) } else if sty == "simple" || sty == "spaceDelimited" || sty == "pipeDelimited" { return flatArray(array, sty) } else if sty == "json" { return dara.String(dara.Stringify(array)) } return dara.String("") } // Description: // // # Get the authorization // // @param request - request params // // @param signatureAlgorithm - the autograph method // // @param payload - the hashed request // // @param accessKey - the accessKey string // // @param accessKeySecret - the accessKeySecret string // // @return authorization string func GetAuthorization(request *dara.Request, signatureAlgorithm *string, payload *string, accessKey *string, accessKeySecret *string) (_result *string) { canonicalURI := dara.StringValue(request.Pathname) if canonicalURI == "" { canonicalURI = "/" } canonicalURI = strings.Replace(canonicalURI, "+", "%20", -1) canonicalURI = strings.Replace(canonicalURI, "*", "%2A", -1) canonicalURI = strings.Replace(canonicalURI, "%7E", "~", -1) method := dara.StringValue(request.Method) canonicalQueryString := getCanonicalQueryString(request.Query) canonicalheaders, signedHeaders := getCanonicalHeaders(request.Headers) canonicalRequest := method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalheaders + "\n" + strings.Join(signedHeaders, ";") + "\n" + dara.StringValue(payload) signType := dara.StringValue(signatureAlgorithm) StringToSign := signType + "\n" + hex.EncodeToString(Hash([]byte(canonicalRequest), signatureAlgorithm)) signature := hex.EncodeToString(SignatureMethod(dara.StringValue(accessKeySecret), StringToSign, signType)) auth := signType + " Credential=" + dara.StringValue(accessKey) + ",SignedHeaders=" + strings.Join(signedHeaders, ";") + ",Signature=" + signature return dara.String(auth) } func GetUserAgent(userAgent *string) (_result *string) { if userAgent != nil && dara.StringValue(userAgent) != "" { return dara.String(defaultUserAgent + " " + dara.StringValue(userAgent)) } return dara.String(defaultUserAgent) } func SignatureMethod(secret, source, signatureAlgorithm string) []byte { if signatureAlgorithm == "ACS3-HMAC-SHA256" { h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(source)) return h.Sum(nil) } else if signatureAlgorithm == "ACS3-HMAC-SM3" { h := hmac.New(sm3.New, []byte(secret)) h.Write([]byte(source)) return h.Sum(nil) } else if signatureAlgorithm == "ACS3-RSA-SHA256" { return rsaSign(source, secret) } return nil } func flatRepeatList(filter map[string]interface{}) (_result *string) { tmp := make(map[string]interface{}) byt, _ := json.Marshal(filter) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() _ = d.Decode(&tmp) result := make(map[string]*string) for key, value := range tmp { filterValue := reflect.ValueOf(value) flatRepeatedList(filterValue, result, key) } res := make(map[string]string) for k, v := range result { res[k] = dara.StringValue(v) } hs := newSorter(res) hs.Sort() // Get the canonicalizedOSSHeaders t := "" for i := range hs.Keys { if i == len(hs.Keys)-1 { t += hs.Keys[i] + "=" + hs.Vals[i] } else { t += hs.Keys[i] + "=" + hs.Vals[i] + "&&" } } return dara.String(t) } func flatArray(array interface{}, sty string) *string { t := reflect.ValueOf(array) strs := make([]string, 0) for i := 0; i < t.Len(); i++ { tmp := t.Index(i) if tmp.Kind() == reflect.Ptr || tmp.Kind() == reflect.Interface { tmp = tmp.Elem() } if tmp.Kind() == reflect.Ptr { tmp = tmp.Elem() } if tmp.Kind() == reflect.String { strs = append(strs, tmp.String()) } else { inter := tmp.Interface() byt, _ := json.Marshal(inter) strs = append(strs, string(byt)) } } str := "" if sty == "simple" { str = strings.Join(strs, ",") } else if sty == "spaceDelimited" { str = strings.Join(strs, " ") } else if sty == "pipeDelimited" { str = strings.Join(strs, "|") } return dara.String(str) } func buildRpcStringToSign(signedParam map[string]*string, method string) (stringToSign string) { signParams := make(map[string]string) for key, value := range signedParam { signParams[key] = dara.StringValue(value) } stringToSign = getUrlFormedMap(signParams) stringToSign = strings.Replace(stringToSign, "+", "%20", -1) stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) stringToSign = url.QueryEscape(stringToSign) stringToSign = method + "&%2F&" + stringToSign return } func getUrlFormedMap(source map[string]string) (urlEncoded string) { urlEncoder := url.Values{} for key, value := range source { urlEncoder.Add(key, value) } urlEncoded = urlEncoder.Encode() return } func sign(stringToSign, accessKeySecret, secretSuffix string) string { secret := accessKeySecret + secretSuffix signedBytes := shaHmac1(stringToSign, secret) signedString := base64.StdEncoding.EncodeToString(signedBytes) return signedString } func shaHmac1(source, secret string) []byte { key := []byte(secret) hmac := hmac.New(sha1.New, key) hmac.Write([]byte(source)) return hmac.Sum(nil) } func getTimeLeft(rateLimit *string) (_result *int64) { if rateLimit != nil { pairs := strings.Split(dara.StringValue(rateLimit), ",") for _, pair := range pairs { kv := strings.Split(pair, ":") if len(kv) == 2 { key, value := kv[0], kv[1] if key == "TimeLeft" { timeLeftValue, err := strconv.ParseInt(value, 10, 64) if err != nil { return nil } return dara.Int64(timeLeftValue) } } } } return nil } func rsaSign(content, secret string) []byte { h := crypto.SHA256.New() h.Write([]byte(content)) hashed := h.Sum(nil) priv, err := parsePrivateKey(secret) if err != nil { return nil } sign, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed) if err != nil { return nil } return sign } func parsePrivateKey(privateKey string) (*rsa.PrivateKey, error) { privateKey = formatPrivateKey(privateKey) block, _ := pem.Decode([]byte(privateKey)) if block == nil { return nil, errors.New("PrivateKey is invalid") } priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, err } switch priKey.(type) { case *rsa.PrivateKey: return priKey.(*rsa.PrivateKey), nil default: return nil, nil } } func formatPrivateKey(privateKey string) string { if !strings.HasPrefix(privateKey, PEM_BEGIN) { privateKey = PEM_BEGIN + privateKey } if !strings.HasSuffix(privateKey, PEM_END) { privateKey += PEM_END } return privateKey } func getCanonicalHeaders(headers map[string]*string) (string, []string) { tmp := make(map[string]string) tmpHeader := http.Header{} for k, v := range headers { if strings.HasPrefix(strings.ToLower(k), "x-acs-") || strings.ToLower(k) == "host" || strings.ToLower(k) == "content-type" { tmp[strings.ToLower(k)] = strings.TrimSpace(dara.StringValue(v)) tmpHeader.Add(strings.ToLower(k), strings.TrimSpace(dara.StringValue(v))) } } hs := newSorter(tmp) // Sort the temp by the ascending order hs.Sort() canonicalheaders := "" for _, key := range hs.Keys { vals := tmpHeader[textproto.CanonicalMIMEHeaderKey(key)] sort.Strings(vals) canonicalheaders += key + ":" + strings.Join(vals, ",") + "\n" } return canonicalheaders, hs.Keys } func getCanonicalQueryString(query map[string]*string) string { canonicalQueryString := "" if dara.IsNil(query) { return canonicalQueryString } tmp := make(map[string]string) for k, v := range query { tmp[k] = dara.StringValue(v) } hs := newSorter(tmp) // Sort the temp by the ascending order hs.Sort() for i := range hs.Keys { if hs.Vals[i] != "" { canonicalQueryString += "&" + hs.Keys[i] + "=" + url.QueryEscape(hs.Vals[i]) } else { canonicalQueryString += "&" + hs.Keys[i] + "=" } } canonicalQueryString = strings.Replace(canonicalQueryString, "+", "%20", -1) canonicalQueryString = strings.Replace(canonicalQueryString, "*", "%2A", -1) canonicalQueryString = strings.Replace(canonicalQueryString, "%7E", "~", -1) if canonicalQueryString != "" { canonicalQueryString = strings.TrimLeft(canonicalQueryString, "&") } return canonicalQueryString } func ParseToMap(in interface{}) map[string]interface{} { if dara.IsNil(in) { return nil } tmp := make(map[string]interface{}) byt, _ := json.Marshal(in) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() err := d.Decode(&tmp) if err != nil { return nil } return tmp } func GetEndpointRules(product, regionId, endpointType, network, suffix *string) (_result *string, _err error) { if dara.StringValue(endpointType) == "regional" { if dara.StringValue(regionId) == "" { _err = fmt.Errorf("RegionId is empty, please set a valid RegionId") return dara.String(""), _err } _result = dara.String(strings.Replace("..aliyuncs.com", "", dara.StringValue(regionId), 1)) } else { _result = dara.String(".aliyuncs.com") } _result = dara.String(strings.Replace(dara.StringValue(_result), "", strings.ToLower(dara.StringValue(product)), 1)) if dara.StringValue(network) == "" || dara.StringValue(network) == "public" { _result = dara.String(strings.Replace(dara.StringValue(_result), "", "", 1)) } else { _result = dara.String(strings.Replace(dara.StringValue(_result), "", "-"+dara.StringValue(network), 1)) } if dara.StringValue(suffix) == "" { _result = dara.String(strings.Replace(dara.StringValue(_result), "", "", 1)) } else { _result = dara.String(strings.Replace(dara.StringValue(_result), "", "-"+dara.StringValue(suffix), 1)) } return _result, nil } func ToArray(in interface{}) []map[string]interface{} { tmp := make([]map[string]interface{}, 0) if dara.IsNil(in) { return nil } byt, _ := json.Marshal(in) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() err := d.Decode(&tmp) if err != nil { return nil } return tmp } func GetEndpoint(endpoint *string, server *bool, endpointType *string) *string { if dara.StringValue(endpointType) == "internal" { strs := strings.Split(dara.StringValue(endpoint), ".") strs[0] += "-internal" endpoint = dara.String(strings.Join(strs, ".")) } if dara.BoolValue(server) && dara.StringValue(endpointType) == "accelerate" { return dara.String("oss-accelerate.aliyuncs.com") } return endpoint } func toJSONString(a interface{}) *string { switch v := a.(type) { case *string: return v case string: return dara.String(v) case []byte: return dara.String(string(v)) case io.Reader: byt, err := ioutil.ReadAll(v) if err != nil { return nil } return dara.String(string(byt)) } byt := bytes.NewBuffer([]byte{}) jsonEncoder := json.NewEncoder(byt) jsonEncoder.SetEscapeHTML(false) if err := jsonEncoder.Encode(a); err != nil { return nil } return dara.String(string(bytes.TrimSpace(byt.Bytes()))) } func StringifyMapValue(a map[string]interface{}) map[string]*string { res := make(map[string]*string) for key, value := range a { if value != nil { res[key] = toJSONString(value) } } return res }