utils.go raw

   1  package base
   2  
   3  import (
   4  	"crypto/md5"
   5  	"encoding/base64"
   6  	"encoding/hex"
   7  	"encoding/json"
   8  	"fmt"
   9  	"math/rand"
  10  	"net/http"
  11  	"net/url"
  12  	"reflect"
  13  	"strconv"
  14  	"strings"
  15  	"time"
  16  
  17  	"github.com/google/uuid"
  18  )
  19  
  20  var (
  21  	letterRunes                 = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
  22  	defaultRetryTimes    uint64 = 2
  23  	defaultRetryInterval        = 1 * time.Second
  24  )
  25  
  26  func init() {
  27  	rand.Seed(time.Now().Unix())
  28  }
  29  
  30  func createTempAKSK() (accessKeyId string, plainSk string, err error) {
  31  	if accessKeyId, err = generateAccessKeyId("AKTP"); err != nil {
  32  		return
  33  	}
  34  
  35  	plainSk, err = generateSecretKey()
  36  	if err != nil {
  37  		return
  38  	}
  39  	return
  40  }
  41  
  42  func generateAccessKeyId(prefix string) (string, error) {
  43  	uuid := uuid.New()
  44  
  45  	uidBase64 := base64.StdEncoding.EncodeToString([]byte(strings.Replace(uuid.String(), "-", "", -1)))
  46  
  47  	s := strings.Replace(uidBase64, "=", "", -1)
  48  	s = strings.Replace(s, "/", "", -1)
  49  	s = strings.Replace(s, "+", "", -1)
  50  	s = strings.Replace(s, "-", "", -1)
  51  	return prefix + s, nil
  52  }
  53  
  54  func randStringRunes(n int) string {
  55  	b := make([]rune, n)
  56  	for i := range b {
  57  		b[i] = letterRunes[rand.Intn(len(letterRunes))]
  58  	}
  59  	return string(b)
  60  }
  61  
  62  func generateSecretKey() (string, error) {
  63  	randString32 := randStringRunes(32)
  64  	return aesEncryptCBCWithBase64([]byte(randString32), []byte("bytedance-isgood"))
  65  }
  66  
  67  func createInnerToken(credentials Credentials, sts *SecurityToken2, inlinePolicy *Policy, t int64) (*InnerToken, error) {
  68  	var err error
  69  	innerToken := new(InnerToken)
  70  
  71  	innerToken.LTAccessKeyId = credentials.AccessKeyID
  72  	innerToken.AccessKeyId = sts.AccessKeyID
  73  	innerToken.ExpiredTime = t
  74  
  75  	key := md5.Sum([]byte(credentials.SecretAccessKey))
  76  	innerToken.SignedSecretAccessKey, err = aesEncryptCBCWithBase64([]byte(sts.SecretAccessKey), key[:])
  77  	if err != nil {
  78  		return nil, err
  79  	}
  80  
  81  	if inlinePolicy != nil {
  82  		b, _ := json.Marshal(inlinePolicy)
  83  		innerToken.PolicyString = string(b)
  84  	}
  85  
  86  	signStr := fmt.Sprintf("%s|%s|%d|%s|%s", innerToken.LTAccessKeyId, innerToken.AccessKeyId, innerToken.ExpiredTime, innerToken.SignedSecretAccessKey, innerToken.PolicyString)
  87  
  88  	innerToken.Signature = hex.EncodeToString(hmacSHA256(key[:], signStr))
  89  	return innerToken, nil
  90  }
  91  
  92  func getTimeout(serviceTimeout, apiTimeout, customTimeout time.Duration) time.Duration {
  93  	timeout := time.Second
  94  	if serviceTimeout != time.Duration(0) {
  95  		timeout = serviceTimeout
  96  	}
  97  	if apiTimeout != time.Duration(0) {
  98  		timeout = apiTimeout
  99  	}
 100  	if customTimeout != time.Duration(0) {
 101  		timeout = customTimeout
 102  	}
 103  	return timeout
 104  }
 105  
 106  func getRetrySetting(serviceRetrySettings, apiRetrySettings *RetrySettings) *RetrySettings {
 107  	retrySettings := &RetrySettings{
 108  		AutoRetry:     false,
 109  		RetryTimes:    new(uint64),
 110  		RetryInterval: new(time.Duration),
 111  	}
 112  	if !apiRetrySettings.AutoRetry || !serviceRetrySettings.AutoRetry {
 113  		return retrySettings
 114  	}
 115  	retrySettings.AutoRetry = true
 116  	if serviceRetrySettings.RetryTimes != nil {
 117  		retrySettings.RetryTimes = serviceRetrySettings.RetryTimes
 118  	} else if apiRetrySettings.RetryTimes != nil {
 119  		retrySettings.RetryTimes = apiRetrySettings.RetryTimes
 120  	} else {
 121  		retrySettings.RetryTimes = &defaultRetryTimes
 122  	}
 123  	if serviceRetrySettings.RetryInterval != nil {
 124  		retrySettings.RetryInterval = serviceRetrySettings.RetryInterval
 125  	} else if apiRetrySettings.RetryInterval != nil {
 126  		retrySettings.RetryInterval = apiRetrySettings.RetryInterval
 127  	} else {
 128  		retrySettings.RetryInterval = &defaultRetryInterval
 129  	}
 130  	return retrySettings
 131  }
 132  
 133  func mergeQuery(query1, query2 url.Values) (query url.Values) {
 134  	query = url.Values{}
 135  	if query1 != nil {
 136  		for k, vv := range query1 {
 137  			for _, v := range vv {
 138  				query.Add(k, v)
 139  			}
 140  		}
 141  	}
 142  
 143  	if query2 != nil {
 144  		for k, vv := range query2 {
 145  			for _, v := range vv {
 146  				query.Add(k, v)
 147  			}
 148  		}
 149  	}
 150  	return
 151  }
 152  
 153  func mergeHeader(header1, header2 http.Header) (header http.Header) {
 154  	header = http.Header{}
 155  	if header1 != nil {
 156  		for k, v := range header1 {
 157  			header.Set(k, strings.Join(v, ";"))
 158  		}
 159  	}
 160  	if header2 != nil {
 161  		for k, v := range header2 {
 162  			header.Set(k, strings.Join(v, ";"))
 163  		}
 164  	}
 165  
 166  	return
 167  }
 168  
 169  func NewAllowStatement(actions, resources []string) *Statement {
 170  	sts := new(Statement)
 171  	sts.Effect = "Allow"
 172  	sts.Action = actions
 173  	sts.Resource = resources
 174  
 175  	return sts
 176  }
 177  
 178  func NewDenyStatement(actions, resources []string) *Statement {
 179  	sts := new(Statement)
 180  	sts.Effect = "Deny"
 181  	sts.Action = actions
 182  	sts.Resource = resources
 183  
 184  	return sts
 185  }
 186  
 187  func ToUrlValues(i interface{}) (values url.Values) {
 188  	values = url.Values{}
 189  	iVal := reflect.ValueOf(i).Elem()
 190  	typ := iVal.Type()
 191  	for i := 0; i < iVal.NumField(); i++ {
 192  		f := iVal.Field(i)
 193  		// You ca use tags here...
 194  		// tag := typ.Field(i).Tag.Get("tagname")
 195  		// Convert each type into a string for the url.Values string map
 196  		var v string
 197  		switch f.Interface().(type) {
 198  		case int, int8, int16, int32, int64:
 199  			v = strconv.FormatInt(f.Int(), 10)
 200  		case uint, uint8, uint16, uint32, uint64:
 201  			v = strconv.FormatUint(f.Uint(), 10)
 202  		case float32:
 203  			v = strconv.FormatFloat(f.Float(), 'f', 4, 32)
 204  		case float64:
 205  			v = strconv.FormatFloat(f.Float(), 'f', 4, 64)
 206  		case []byte:
 207  			v = string(f.Bytes())
 208  		case bool:
 209  			v = strconv.FormatBool(f.Bool())
 210  		case string:
 211  			if f.Len() == 0 {
 212  				continue
 213  			}
 214  			v = f.String()
 215  		}
 216  		values.Set(typ.Field(i).Name, v)
 217  	}
 218  	return
 219  }
 220  
 221  func UnmarshalResultInto(data []byte, result interface{}) error {
 222  	resp := new(CommonResponse)
 223  	if err := json.Unmarshal(data, resp); err != nil {
 224  		return fmt.Errorf("fail to unmarshal response, %v", err)
 225  	}
 226  	errObj := resp.ResponseMetadata.Error
 227  	if errObj != nil && errObj.CodeN != 0 {
 228  		return fmt.Errorf("request %s error %s", resp.ResponseMetadata.RequestId, errObj.Message)
 229  	}
 230  
 231  	data, err := json.Marshal(resp.Result)
 232  	if err != nil {
 233  		return fmt.Errorf("fail to marshal result, %v", err)
 234  	}
 235  	if err = json.Unmarshal(data, result); err != nil {
 236  		return fmt.Errorf("fail to unmarshal result, %v", err)
 237  	}
 238  	return nil
 239  }
 240