gitee.com/larksuite/oapi-sdk-go/v3@v3.0.3/core/utils.go (about)

     1  /*
     2   * MIT License
     3   *
     4   * Copyright (c) 2022 Lark Technologies Pte. Ltd.
     5   *
     6   * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
     7   *
     8   * The above copyright notice and this permission notice, shall be included in all copies or substantial portions of the Software.
     9   *
    10   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    11   */
    12  
    13  package larkcore
    14  
    15  import (
    16  	"bytes"
    17  	"context"
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  	"crypto/rand"
    21  	"crypto/sha256"
    22  	"encoding/base64"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"io/ioutil"
    28  	"net/http"
    29  	"os"
    30  	"reflect"
    31  	"strings"
    32  )
    33  
    34  import "time"
    35  
    36  // StringPtr returns a pointer to the string value passed in.
    37  func StringPtr(v string) *string {
    38  	return &v
    39  }
    40  
    41  // StringValue returns the value of the string pointer passed in or
    42  // "" if the pointer is nil.
    43  func StringValue(v *string) string {
    44  	if v != nil {
    45  		return *v
    46  	}
    47  	return ""
    48  }
    49  
    50  // BoolPtr returns a pointer to the bool value passed in.
    51  func BoolPtr(v bool) *bool {
    52  	return &v
    53  }
    54  
    55  // BoolValue returns the value of the bool pointer passed in or
    56  // false if the pointer is nil.
    57  func BoolValue(v *bool) bool {
    58  	if v != nil {
    59  		return *v
    60  	}
    61  	return false
    62  }
    63  
    64  // IntPtr returns a pointer to the int value passed in.
    65  func IntPtr(v int) *int {
    66  	return &v
    67  }
    68  
    69  // IntValue returns the value of the int pointer passed in or
    70  // 0 if the pointer is nil.
    71  func IntValue(v *int) int {
    72  	if v != nil {
    73  		return *v
    74  	}
    75  	return 0
    76  }
    77  
    78  // Int8Ptr returns a pointer to the int8 value passed in.
    79  func Int8Ptr(v int8) *int8 {
    80  	return &v
    81  }
    82  
    83  // Int8Value returns the value of the int8 pointer passed in or
    84  // 0 if the pointer is nil.
    85  func Int8Value(v *int8) int8 {
    86  	if v != nil {
    87  		return *v
    88  	}
    89  	return 0
    90  }
    91  
    92  // Int16Ptr returns a pointer to the int16 value passed in.
    93  func Int16Ptr(v int16) *int16 {
    94  	return &v
    95  }
    96  
    97  // Int16Value returns the value of the int16 pointer passed in or
    98  // 0 if the pointer is nil.
    99  func Int16Value(v *int16) int16 {
   100  	if v != nil {
   101  		return *v
   102  	}
   103  	return 0
   104  }
   105  
   106  // Int32Ptr returns a pointer to the int32 value passed in.
   107  func Int32Ptr(v int32) *int32 {
   108  	return &v
   109  }
   110  
   111  // Int32Value returns the value of the int32 pointer passed in or
   112  // 0 if the pointer is nil.
   113  func Int32Value(v *int32) int32 {
   114  	if v != nil {
   115  		return *v
   116  	}
   117  	return 0
   118  }
   119  
   120  // Int64Ptr returns a pointer to the int64 value passed in.
   121  func Int64Ptr(v int64) *int64 {
   122  	return &v
   123  }
   124  
   125  // Int64Value returns the value of the int64 pointer passed in or
   126  // 0 if the pointer is nil.
   127  func Int64Value(v *int64) int64 {
   128  	if v != nil {
   129  		return *v
   130  	}
   131  	return 0
   132  }
   133  
   134  // Float32Ptr returns a pointer to the float32 value passed in.
   135  func Float32Ptr(v float32) *float32 {
   136  	return &v
   137  }
   138  
   139  // Float32Value returns the value of the float32 pointer passed in or
   140  // 0 if the pointer is nil.
   141  func Float32Value(v *float32) float32 {
   142  	if v != nil {
   143  		return *v
   144  	}
   145  	return 0
   146  }
   147  
   148  // Float64Ptr returns a pointer to the float64 value passed in.
   149  func Float64Ptr(v float64) *float64 {
   150  	return &v
   151  }
   152  
   153  // Float64Value returns the value of the float64 pointer passed in or
   154  // 0 if the pointer is nil.
   155  func Float64Value(v *float64) float64 {
   156  	if v != nil {
   157  		return *v
   158  	}
   159  	return 0
   160  }
   161  
   162  // TimePtr returns a pointer to the time.Time value passed in.
   163  func TimePtr(v time.Time) *time.Time {
   164  	return &v
   165  }
   166  
   167  // TimeValue returns the value of the time.Time pointer passed in or
   168  // time.Time{} if the pointer is nil.
   169  func TimeValue(v *time.Time) time.Time {
   170  	if v != nil {
   171  		return *v
   172  	}
   173  	return time.Time{}
   174  }
   175  
   176  // Prettify returns the string representation of a value.
   177  func Prettify(i interface{}) string {
   178  	var buf bytes.Buffer
   179  	prettify(reflect.ValueOf(i), 0, &buf)
   180  	return buf.String()
   181  }
   182  
   183  // DownloadFile returns the url of resource
   184  func DownloadFile(ctx context.Context, url string) ([]byte, error) {
   185  	r, err := downloadFileToStream(ctx, url)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	defer r.Close()
   190  	return ioutil.ReadAll(r)
   191  }
   192  
   193  type DecryptErr struct {
   194  	Message string
   195  }
   196  
   197  func newDecryptErr(message string) *DecryptErr {
   198  	return &DecryptErr{Message: message}
   199  }
   200  
   201  func (e DecryptErr) Error() string {
   202  	return e.Message
   203  }
   204  
   205  func downloadFileToStream(ctx context.Context, url string) (io.ReadCloser, error) {
   206  	request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	resp, err := http.DefaultClient.Do(request)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  	if resp.StatusCode != http.StatusOK {
   215  		return nil, fmt.Errorf("response status code:%d", resp.StatusCode)
   216  	}
   217  	return resp.Body, nil
   218  }
   219  
   220  // prettify will recursively walk value v to build a textual
   221  // representation of the value.
   222  func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
   223  	for v.Kind() == reflect.Ptr {
   224  		v = v.Elem()
   225  	}
   226  	switch v.Kind() {
   227  	case reflect.Struct:
   228  		strType := v.Type().String()
   229  		if strType == "time.Time" {
   230  			fmt.Fprintf(buf, "%s", v.Interface())
   231  			break
   232  		} else if strings.HasPrefix(strType, "io.") {
   233  			buf.WriteString("<buffer>")
   234  			break
   235  		}
   236  
   237  		buf.WriteString("{\n")
   238  
   239  		var names []string
   240  		for i := 0; i < v.Type().NumField(); i++ {
   241  			name := v.Type().Field(i).Name
   242  			f := v.Field(i)
   243  			if name[0:1] == strings.ToLower(name[0:1]) {
   244  				continue // ignore unexported fields
   245  			}
   246  			if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
   247  				continue // ignore unset fields
   248  			}
   249  			names = append(names, name)
   250  		}
   251  
   252  		for i, n := range names {
   253  			val := v.FieldByName(n)
   254  			buf.WriteString(strings.Repeat(" ", indent+2))
   255  			buf.WriteString(n + ": ")
   256  			prettify(val, indent+2, buf)
   257  
   258  			if i < len(names)-1 {
   259  				buf.WriteString(",\n")
   260  			}
   261  		}
   262  
   263  		buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
   264  	case reflect.Slice:
   265  		strType := v.Type().String()
   266  		if strType == "[]uint8" {
   267  			fmt.Fprintf(buf, "<binary> len %d", v.Len())
   268  			break
   269  		}
   270  
   271  		nl, id, id2 := "", "", ""
   272  		if v.Len() > 3 {
   273  			nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
   274  		}
   275  		buf.WriteString("[" + nl)
   276  		for i := 0; i < v.Len(); i++ {
   277  			buf.WriteString(id2)
   278  			prettify(v.Index(i), indent+2, buf)
   279  
   280  			if i < v.Len()-1 {
   281  				buf.WriteString("," + nl)
   282  			}
   283  		}
   284  
   285  		buf.WriteString(nl + id + "]")
   286  	case reflect.Map:
   287  		buf.WriteString("{\n")
   288  
   289  		for i, k := range v.MapKeys() {
   290  			buf.WriteString(strings.Repeat(" ", indent+2))
   291  			buf.WriteString(k.String() + ": ")
   292  			prettify(v.MapIndex(k), indent+2, buf)
   293  
   294  			if i < v.Len()-1 {
   295  				buf.WriteString(",\n")
   296  			}
   297  		}
   298  
   299  		buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
   300  	default:
   301  		if !v.IsValid() {
   302  			fmt.Fprint(buf, "<invalid value>")
   303  			return
   304  		}
   305  		format := "%v"
   306  		switch v.Interface().(type) {
   307  		case string:
   308  			format = "%q"
   309  		case io.ReadSeeker, io.Reader:
   310  			format = "buffer(%p)"
   311  		}
   312  		fmt.Fprintf(buf, format, v.Interface())
   313  	}
   314  }
   315  
   316  func StructToMap(val interface{}) (map[string]interface{}, error) {
   317  	m := make(map[string]interface{})
   318  	s := reflect.Indirect(reflect.ValueOf(val))
   319  	st := s.Type()
   320  	for i := 0; i < s.NumField(); i++ {
   321  		fieldDesc := st.Field(i)
   322  		fieldVal := s.Field(i)
   323  		if fieldDesc.Anonymous {
   324  			embeddedMap, err := StructToMap(fieldVal.Interface())
   325  			if err != nil {
   326  				return nil, err
   327  			}
   328  			for k, v := range embeddedMap {
   329  				m[k] = v
   330  			}
   331  			continue
   332  		}
   333  		jsonTag := fieldDesc.Tag.Get("json")
   334  		if jsonTag == "" {
   335  			continue
   336  		}
   337  		tag, err := parseJSONTag(jsonTag)
   338  		if err != nil {
   339  			return nil, err
   340  		}
   341  		if tag.ignore {
   342  			continue
   343  		}
   344  		if fieldDesc.Type.Kind() == reflect.Ptr && fieldVal.IsNil() {
   345  			continue
   346  		}
   347  		// nil maps are treated as empty maps.
   348  		if fieldDesc.Type.Kind() == reflect.Map && fieldVal.IsNil() {
   349  			continue
   350  		}
   351  		if fieldDesc.Type.Kind() == reflect.Slice && fieldVal.IsNil() {
   352  			continue
   353  		}
   354  		if tag.stringFormat {
   355  			m[tag.name] = formatAsString(fieldVal, fieldDesc.Type.Kind())
   356  		} else {
   357  			m[tag.name] = fieldVal.Interface()
   358  		}
   359  	}
   360  	return m, nil
   361  }
   362  
   363  func formatAsString(v reflect.Value, kind reflect.Kind) string {
   364  	if kind == reflect.Ptr && !v.IsNil() {
   365  		v = v.Elem()
   366  	}
   367  	return fmt.Sprintf("%v", v.Interface())
   368  }
   369  
   370  type jsonTag struct {
   371  	name         string
   372  	stringFormat bool
   373  	ignore       bool
   374  }
   375  
   376  func parseJSONTag(val string) (jsonTag, error) {
   377  	if val == "-" {
   378  		return jsonTag{ignore: true}, nil
   379  	}
   380  	var tag jsonTag
   381  	i := strings.Index(val, ",")
   382  	if i == -1 || val[:i] == "" {
   383  		return tag, fmt.Errorf("malformed json tag: %s", val)
   384  	}
   385  	tag = jsonTag{
   386  		name: val[:i],
   387  	}
   388  	switch val[i+1:] {
   389  	case "omitempty":
   390  	case "omitempty,string":
   391  		tag.stringFormat = true
   392  	default:
   393  		return tag, fmt.Errorf("malformed json tag: %s", val)
   394  	}
   395  	return tag, nil
   396  }
   397  
   398  func isEmptyValue(v reflect.Value) bool {
   399  	switch v.Kind() {
   400  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
   401  		return v.Len() == 0
   402  	case reflect.Bool:
   403  		return !v.Bool()
   404  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   405  		return v.Int() == 0
   406  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   407  		return v.Uint() == 0
   408  	case reflect.Float32, reflect.Float64:
   409  		return v.Float() == 0
   410  	case reflect.Interface, reflect.Ptr:
   411  		return v.IsNil()
   412  	}
   413  	return false
   414  }
   415  
   416  func userAgent() string {
   417  	return fmt.Sprintf("oapi-sdk-go/%s", version)
   418  }
   419  
   420  func readResponse(resp *http.Response) ([]byte, error) {
   421  	defer resp.Body.Close()
   422  	respBody, err := ioutil.ReadAll(resp.Body)
   423  	if err != nil {
   424  		return nil, err
   425  	}
   426  	return respBody, nil
   427  }
   428  
   429  func File2Bytes(fileName string) ([]byte, error) {
   430  	file, err := os.Open(fileName)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  	defer file.Close()
   435  
   436  	fileInfo, err := file.Stat()
   437  	if err != nil {
   438  		return nil, err
   439  	}
   440  
   441  	fileData := make([]byte, fileInfo.Size())
   442  	_, err = file.Read(fileData)
   443  	if err != nil {
   444  		return nil, err
   445  	}
   446  	return fileData, nil
   447  }
   448  
   449  func standardizeDataEn(data []byte) []byte {
   450  	appendingLen := aes.BlockSize - (len(data) % aes.BlockSize)
   451  	sd := make([]byte, len(data)+appendingLen)
   452  	copy(sd, data)
   453  	for i := 0; i < appendingLen; i++ {
   454  		sd[i+len(data)] = byte(appendingLen)
   455  	}
   456  	return sd
   457  }
   458  func cBCEncrypter(buf []byte, keyStr string) ([]byte, error) {
   459  	key := sha256.Sum256([]byte(keyStr))
   460  	plaintext := standardizeDataEn(buf)
   461  
   462  	if len(plaintext)%aes.BlockSize != 0 {
   463  		return nil, errors.New("plaintext is not a multiple of the block size")
   464  	}
   465  
   466  	block, err := aes.NewCipher(key[:sha256.Size])
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  
   471  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
   472  	iv := ciphertext[:aes.BlockSize]
   473  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   474  		return nil, err
   475  	}
   476  
   477  	mode := cipher.NewCBCEncrypter(block, iv)
   478  	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
   479  
   480  	if err != nil {
   481  		return nil, err
   482  	}
   483  
   484  	return ciphertext, nil
   485  }
   486  func EncryptedEventMsg(ctx context.Context, data interface{}, encryptKey string) (string, error) {
   487  	var bs []byte
   488  	var err error
   489  
   490  	switch data.(type) {
   491  	case string:
   492  		bs = []byte(data.(string))
   493  	case []byte:
   494  		bs = data.([]byte)
   495  	default:
   496  		bs, err = json.Marshal(data)
   497  	}
   498  
   499  	if err != nil {
   500  		return "", err
   501  	}
   502  
   503  	encryptedData, err := cBCEncrypter(bs, encryptKey)
   504  	if err != nil {
   505  		return "", err
   506  	}
   507  
   508  	return base64.StdEncoding.EncodeToString(encryptedData), nil
   509  }