1
2
5 package service
6
7 import (
8 "bytes"
9 "crypto"
10 "crypto/hmac"
11 "crypto/rand"
12 "crypto/rsa"
13 "crypto/sha1"
14 "crypto/sha256"
15 "crypto/x509"
16 "encoding/base64"
17 "encoding/hex"
18 "encoding/json"
19 "encoding/pem"
20 "errors"
21 "fmt"
22 "hash"
23 "io"
24 "net/http"
25 "net/textproto"
26 "net/url"
27 "reflect"
28 "sort"
29 "strconv"
30 "strings"
31 "time"
32
33 util "github.com/alibabacloud-go/tea-utils/service"
34 "github.com/alibabacloud-go/tea/tea"
35 "github.com/tjfoc/gmsm/sm3"
36 )
37
38 const (
39 PEM_BEGIN = "-----BEGIN RSA PRIVATE KEY-----\n"
40 PEM_END = "\n-----END RSA PRIVATE KEY-----"
41 )
42
43 type Sorter struct {
44 Keys []string
45 Vals []string
46 }
47
48 func newSorter(m map[string]string) *Sorter {
49 hs := &Sorter{
50 Keys: make([]string, 0, len(m)),
51 Vals: make([]string, 0, len(m)),
52 }
53
54 for k, v := range m {
55 hs.Keys = append(hs.Keys, k)
56 hs.Vals = append(hs.Vals, v)
57 }
58 return hs
59 }
60
61
62 func (hs *Sorter) Sort() {
63 sort.Sort(hs)
64 }
65
66
67 func (hs *Sorter) Len() int {
68 return len(hs.Vals)
69 }
70
71
72 func (hs *Sorter) Less(i, j int) bool {
73 return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
74 }
75
76
77 func (hs *Sorter) Swap(i, j int) {
78 hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
79 hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
80 }
81
82
88 func Convert(body interface{}, content interface{}) {
89 res := make(map[string]interface{})
90 val := reflect.ValueOf(body).Elem()
91 dataType := val.Type()
92 for i := 0; i < dataType.NumField(); i++ {
93 field := dataType.Field(i)
94 name, _ := field.Tag.Lookup("json")
95 name = strings.Split(name, ",omitempty")[0]
96 _, ok := val.Field(i).Interface().(io.Reader)
97 if !ok {
98 res[name] = val.Field(i).Interface()
99 }
100 }
101 byt, _ := json.Marshal(res)
102 json.Unmarshal(byt, content)
103 }
104
105
110 func GetStringToSign(request *tea.Request) (_result *string) {
111 return tea.String(getStringToSign(request))
112 }
113
114 func getStringToSign(request *tea.Request) string {
115 resource := tea.StringValue(request.Pathname)
116 queryParams := request.Query
117
118 var queryKeys []string
119 for key := range queryParams {
120 queryKeys = append(queryKeys, key)
121 }
122 sort.Strings(queryKeys)
123 tmp := ""
124 for i := 0; i < len(queryKeys); i++ {
125 queryKey := queryKeys[i]
126 v := tea.StringValue(queryParams[queryKey])
127 if v != "" {
128 tmp = tmp + "&" + queryKey + "=" + v
129 } else {
130 tmp = tmp + "&" + queryKey
131 }
132 }
133 if tmp != "" {
134 tmp = strings.TrimLeft(tmp, "&")
135 resource = resource + "?" + tmp
136 }
137 return getSignedStr(request, resource)
138 }
139
140 func getSignedStr(req *tea.Request, canonicalizedResource string) string {
141 temp := make(map[string]string)
142
143 for k, v := range req.Headers {
144 if strings.HasPrefix(strings.ToLower(k), "x-acs-") {
145 temp[strings.ToLower(k)] = tea.StringValue(v)
146 }
147 }
148 hs := newSorter(temp)
149
150
151 hs.Sort()
152
153
154 canonicalizedOSSHeaders := ""
155 for i := range hs.Keys {
156 canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
157 }
158
159
160
161 date := tea.StringValue(req.Headers["date"])
162 accept := tea.StringValue(req.Headers["accept"])
163 contentType := tea.StringValue(req.Headers["content-type"])
164 contentMd5 := tea.StringValue(req.Headers["content-md5"])
165
166 signStr := tea.StringValue(req.Method) + "\n" + accept + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
167 return signStr
168 }
169
170
176 func GetROASignature(stringToSign *string, secret *string) (_result *string) {
177 h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(tea.StringValue(secret)))
178 io.WriteString(h, tea.StringValue(stringToSign))
179 signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
180 return tea.String(signedStr)
181 }
182
183 func GetEndpoint(endpoint *string, server *bool, endpointType *string) *string {
184 if tea.StringValue(endpointType) == "internal" {
185 strs := strings.Split(tea.StringValue(endpoint), ".")
186 strs[0] += "-internal"
187 endpoint = tea.String(strings.Join(strs, "."))
188 }
189 if tea.BoolValue(server) && tea.StringValue(endpointType) == "accelerate" {
190 return tea.String("oss-accelerate.aliyuncs.com")
191 }
192
193 return endpoint
194 }
195
196 func HexEncode(raw []byte) *string {
197 return tea.String(hex.EncodeToString(raw))
198 }
199
200 func Hash(raw []byte, signatureAlgorithm *string) []byte {
201 signType := tea.StringValue(signatureAlgorithm)
202 if signType == "ACS3-HMAC-SHA256" || signType == "ACS3-RSA-SHA256" {
203 h := sha256.New()
204 h.Write(raw)
205 return h.Sum(nil)
206 } else if signType == "ACS3-HMAC-SM3" {
207 h := sm3.New()
208 h.Write(raw)
209 return h.Sum(nil)
210 }
211 return nil
212 }
213
214 func GetEncodePath(path *string) *string {
215 uri := tea.StringValue(path)
216 strs := strings.Split(uri, "/")
217 for i, v := range strs {
218 strs[i] = url.QueryEscape(v)
219 }
220 uri = strings.Join(strs, "/")
221 uri = strings.Replace(uri, "+", "%20", -1)
222 uri = strings.Replace(uri, "*", "%2A", -1)
223 uri = strings.Replace(uri, "%7E", "~", -1)
224 return tea.String(uri)
225 }
226
227 func GetEncodeParam(param *string) *string {
228 uri := tea.StringValue(param)
229 uri = url.QueryEscape(uri)
230 uri = strings.Replace(uri, "+", "%20", -1)
231 uri = strings.Replace(uri, "*", "%2A", -1)
232 uri = strings.Replace(uri, "%7E", "~", -1)
233 return tea.String(uri)
234 }
235
236 func GetAuthorization(request *tea.Request, signatureAlgorithm, payload, acesskey, secret *string) *string {
237 canonicalURI := tea.StringValue(request.Pathname)
238 if canonicalURI == "" {
239 canonicalURI = "/"
240 }
241
242 canonicalURI = strings.Replace(canonicalURI, "+", "%20", -1)
243 canonicalURI = strings.Replace(canonicalURI, "*", "%2A", -1)
244 canonicalURI = strings.Replace(canonicalURI, "%7E", "~", -1)
245
246 method := tea.StringValue(request.Method)
247 canonicalQueryString := getCanonicalQueryString(request.Query)
248 canonicalheaders, signedHeaders := getCanonicalHeaders(request.Headers)
249
250 canonicalRequest := method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalheaders + "\n" +
251 strings.Join(signedHeaders, ";") + "\n" + tea.StringValue(payload)
252 signType := tea.StringValue(signatureAlgorithm)
253 StringToSign := signType + "\n" + tea.StringValue(HexEncode(Hash([]byte(canonicalRequest), signatureAlgorithm)))
254 signature := tea.StringValue(HexEncode(SignatureMethod(tea.StringValue(secret), StringToSign, signType)))
255 auth := signType + " Credential=" + tea.StringValue(acesskey) + ",SignedHeaders=" +
256 strings.Join(signedHeaders, ";") + ",Signature=" + signature
257 return tea.String(auth)
258 }
259
260 func SignatureMethod(secret, source, signatureAlgorithm string) []byte {
261 if signatureAlgorithm == "ACS3-HMAC-SHA256" {
262 h := hmac.New(sha256.New, []byte(secret))
263 h.Write([]byte(source))
264 return h.Sum(nil)
265 } else if signatureAlgorithm == "ACS3-HMAC-SM3" {
266 h := hmac.New(sm3.New, []byte(secret))
267 h.Write([]byte(source))
268 return h.Sum(nil)
269 } else if signatureAlgorithm == "ACS3-RSA-SHA256" {
270 return rsaSign(source, secret)
271 }
272 return nil
273 }
274
275 func rsaSign(content, secret string) []byte {
276 h := crypto.SHA256.New()
277 h.Write([]byte(content))
278 hashed := h.Sum(nil)
279 priv, err := parsePrivateKey(secret)
280 if err != nil {
281 return nil
282 }
283 sign, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed)
284 if err != nil {
285 return nil
286 }
287 return sign
288 }
289
290 func parsePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
291 privateKey = formatPrivateKey(privateKey)
292 block, _ := pem.Decode([]byte(privateKey))
293 if block == nil {
294 return nil, errors.New("PrivateKey is invalid")
295 }
296 priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
297 if err != nil {
298 return nil, err
299 }
300 switch priKey.(type) {
301 case *rsa.PrivateKey:
302 return priKey.(*rsa.PrivateKey), nil
303 default:
304 return nil, nil
305 }
306 }
307
308 func formatPrivateKey(privateKey string) string {
309 if !strings.HasPrefix(privateKey, PEM_BEGIN) {
310 privateKey = PEM_BEGIN + privateKey
311 }
312
313 if !strings.HasSuffix(privateKey, PEM_END) {
314 privateKey += PEM_END
315 }
316 return privateKey
317 }
318
319 func getCanonicalHeaders(headers map[string]*string) (string, []string) {
320 tmp := make(map[string]string)
321 tmpHeader := http.Header{}
322 for k, v := range headers {
323 if strings.HasPrefix(strings.ToLower(k), "x-acs-") || strings.ToLower(k) == "host" ||
324 strings.ToLower(k) == "content-type" {
325 tmp[strings.ToLower(k)] = strings.TrimSpace(tea.StringValue(v))
326 tmpHeader.Add(strings.ToLower(k), strings.TrimSpace(tea.StringValue(v)))
327 }
328 }
329 hs := newSorter(tmp)
330
331
332 hs.Sort()
333 canonicalheaders := ""
334 for _, key := range hs.Keys {
335 vals := tmpHeader[textproto.CanonicalMIMEHeaderKey(key)]
336 sort.Strings(vals)
337 canonicalheaders += key + ":" + strings.Join(vals, ",") + "\n"
338 }
339
340 return canonicalheaders, hs.Keys
341 }
342
343 func getCanonicalQueryString(query map[string]*string) string {
344 canonicalQueryString := ""
345 if tea.BoolValue(util.IsUnset(query)) {
346 return canonicalQueryString
347 }
348 tmp := make(map[string]string)
349 for k, v := range query {
350 tmp[k] = tea.StringValue(v)
351 }
352
353 hs := newSorter(tmp)
354
355
356 hs.Sort()
357 for i := range hs.Keys {
358 if hs.Vals[i] != "" {
359 canonicalQueryString += "&" + hs.Keys[i] + "=" + url.QueryEscape(hs.Vals[i])
360 } else {
361 canonicalQueryString += "&" + hs.Keys[i] + "="
362 }
363 }
364 canonicalQueryString = strings.Replace(canonicalQueryString, "+", "%20", -1)
365 canonicalQueryString = strings.Replace(canonicalQueryString, "*", "%2A", -1)
366 canonicalQueryString = strings.Replace(canonicalQueryString, "%7E", "~", -1)
367
368 if canonicalQueryString != "" {
369 canonicalQueryString = strings.TrimLeft(canonicalQueryString, "&")
370 }
371 return canonicalQueryString
372 }
373
374
379 func ToForm(filter map[string]interface{}) (_result *string) {
380 tmp := make(map[string]interface{})
381 byt, _ := json.Marshal(filter)
382 d := json.NewDecoder(bytes.NewReader(byt))
383 d.UseNumber()
384 _ = d.Decode(&tmp)
385
386 result := make(map[string]*string)
387 for key, value := range tmp {
388 filterValue := reflect.ValueOf(value)
389 flatRepeatedList(filterValue, result, key)
390 }
391
392 m := util.AnyifyMapValue(result)
393 return util.ToFormString(m)
394 }
395
396 func flatRepeatedList(dataValue reflect.Value, result map[string]*string, prefix string) {
397 if !dataValue.IsValid() {
398 return
399 }
400
401 dataType := dataValue.Type()
402 if dataType.Kind().String() == "slice" {
403 handleRepeatedParams(dataValue, result, prefix)
404 } else if dataType.Kind().String() == "map" {
405 handleMap(dataValue, result, prefix)
406 } else {
407 result[prefix] = tea.String(fmt.Sprintf("%v", dataValue.Interface()))
408 }
409 }
410
411 func handleRepeatedParams(repeatedFieldValue reflect.Value, result map[string]*string, prefix string) {
412 if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() {
413 for m := 0; m < repeatedFieldValue.Len(); m++ {
414 elementValue := repeatedFieldValue.Index(m)
415 key := prefix + "." + strconv.Itoa(m+1)
416 fieldValue := reflect.ValueOf(elementValue.Interface())
417 if fieldValue.Kind().String() == "map" {
418 handleMap(fieldValue, result, key)
419 } else {
420 result[key] = tea.String(fmt.Sprintf("%v", fieldValue.Interface()))
421 }
422 }
423 }
424 }
425
426 func handleMap(valueField reflect.Value, result map[string]*string, prefix string) {
427 if valueField.IsValid() && valueField.String() != "" {
428 valueFieldType := valueField.Type()
429 if valueFieldType.Kind().String() == "map" {
430 var byt []byte
431 byt, _ = json.Marshal(valueField.Interface())
432 cache := make(map[string]interface{})
433 d := json.NewDecoder(bytes.NewReader(byt))
434 d.UseNumber()
435 _ = d.Decode(&cache)
436 for key, value := range cache {
437 pre := ""
438 if prefix != "" {
439 pre = prefix + "." + key
440 } else {
441 pre = key
442 }
443 fieldValue := reflect.ValueOf(value)
444 flatRepeatedList(fieldValue, result, pre)
445 }
446 }
447 }
448 }
449
450
454 func GetTimestamp() (_result *string) {
455 gmt := time.FixedZone("GMT", 0)
456 return tea.String(time.Now().In(gmt).Format("2006-01-02T15:04:05Z"))
457 }
458
459
464 func Query(filter interface{}) (_result map[string]*string) {
465 tmp := make(map[string]interface{})
466 byt, _ := json.Marshal(filter)
467 d := json.NewDecoder(bytes.NewReader(byt))
468 d.UseNumber()
469 _ = d.Decode(&tmp)
470
471 result := make(map[string]*string)
472 for key, value := range tmp {
473 filterValue := reflect.ValueOf(value)
474 flatRepeatedList(filterValue, result, key)
475 }
476
477 return result
478 }
479
480
487 func GetRPCSignature(signedParams map[string]*string, method *string, secret *string) (_result *string) {
488 stringToSign := buildRpcStringToSign(signedParams, tea.StringValue(method))
489 signature := sign(stringToSign, tea.StringValue(secret), "&")
490 return tea.String(signature)
491 }
492
493
500 func ArrayToStringWithSpecifiedStyle(array interface{}, prefix *string, style *string) (_result *string) {
501 if tea.BoolValue(util.IsUnset(array)) {
502 return tea.String("")
503 }
504
505 sty := tea.StringValue(style)
506 if sty == "repeatList" {
507 tmp := map[string]interface{}{
508 tea.StringValue(prefix): array,
509 }
510 return flatRepeatList(tmp)
511 } else if sty == "simple" || sty == "spaceDelimited" || sty == "pipeDelimited" {
512 return flatArray(array, sty)
513 } else if sty == "json" {
514 return util.ToJSONString(array)
515 }
516 return tea.String("")
517 }
518
519 func ParseToMap(in interface{}) map[string]interface{} {
520 if tea.BoolValue(util.IsUnset(in)) {
521 return nil
522 }
523
524 tmp := make(map[string]interface{})
525 byt, _ := json.Marshal(in)
526 d := json.NewDecoder(bytes.NewReader(byt))
527 d.UseNumber()
528 err := d.Decode(&tmp)
529 if err != nil {
530 return nil
531 }
532 return tmp
533 }
534
535 func flatRepeatList(filter map[string]interface{}) (_result *string) {
536 tmp := make(map[string]interface{})
537 byt, _ := json.Marshal(filter)
538 d := json.NewDecoder(bytes.NewReader(byt))
539 d.UseNumber()
540 _ = d.Decode(&tmp)
541
542 result := make(map[string]*string)
543 for key, value := range tmp {
544 filterValue := reflect.ValueOf(value)
545 flatRepeatedList(filterValue, result, key)
546 }
547
548 res := make(map[string]string)
549 for k, v := range result {
550 res[k] = tea.StringValue(v)
551 }
552 hs := newSorter(res)
553
554 hs.Sort()
555
556
557 t := ""
558 for i := range hs.Keys {
559 if i == len(hs.Keys)-1 {
560 t += hs.Keys[i] + "=" + hs.Vals[i]
561 } else {
562 t += hs.Keys[i] + "=" + hs.Vals[i] + "&&"
563 }
564 }
565 return tea.String(t)
566 }
567
568 func flatArray(array interface{}, sty string) *string {
569 t := reflect.ValueOf(array)
570 strs := make([]string, 0)
571 for i := 0; i < t.Len(); i++ {
572 tmp := t.Index(i)
573 if tmp.Kind() == reflect.Ptr || tmp.Kind() == reflect.Interface {
574 tmp = tmp.Elem()
575 }
576
577 if tmp.Kind() == reflect.Ptr {
578 tmp = tmp.Elem()
579 }
580 if tmp.Kind() == reflect.String {
581 strs = append(strs, tmp.String())
582 } else {
583 inter := tmp.Interface()
584 byt, _ := json.Marshal(inter)
585 strs = append(strs, string(byt))
586 }
587 }
588 str := ""
589 if sty == "simple" {
590 str = strings.Join(strs, ",")
591 } else if sty == "spaceDelimited" {
592 str = strings.Join(strs, " ")
593 } else if sty == "pipeDelimited" {
594 str = strings.Join(strs, "|")
595 }
596 return tea.String(str)
597 }
598
599 func buildRpcStringToSign(signedParam map[string]*string, method string) (stringToSign string) {
600 signParams := make(map[string]string)
601 for key, value := range signedParam {
602 signParams[key] = tea.StringValue(value)
603 }
604
605 stringToSign = getUrlFormedMap(signParams)
606 stringToSign = strings.Replace(stringToSign, "+", "%20", -1)
607 stringToSign = strings.Replace(stringToSign, "*", "%2A", -1)
608 stringToSign = strings.Replace(stringToSign, "%7E", "~", -1)
609 stringToSign = url.QueryEscape(stringToSign)
610 stringToSign = method + "&%2F&" + stringToSign
611 return
612 }
613
614 func getUrlFormedMap(source map[string]string) (urlEncoded string) {
615 urlEncoder := url.Values{}
616 for key, value := range source {
617 urlEncoder.Add(key, value)
618 }
619 urlEncoded = urlEncoder.Encode()
620 return
621 }
622
623 func sign(stringToSign, accessKeySecret, secretSuffix string) string {
624 secret := accessKeySecret + secretSuffix
625 signedBytes := shaHmac1(stringToSign, secret)
626 signedString := base64.StdEncoding.EncodeToString(signedBytes)
627 return signedString
628 }
629
630 func shaHmac1(source, secret string) []byte {
631 key := []byte(secret)
632 hmac := hmac.New(sha1.New, key)
633 hmac.Write([]byte(source))
634 return hmac.Sum(nil)
635 }
636
View as plain text