github.com/qiniu/go-sdk/v7@v7.27.0/sms/client/qiniumac.go (about)

     1  package client
     2  
     3  import (
     4  	"crypto/hmac"
     5  	"crypto/sha1"
     6  	"io"
     7  	"net/http"
     8  	"sort"
     9  
    10  	"github.com/qiniu/go-sdk/v7/sms/bytes/seekable"
    11  )
    12  
    13  const qiniuHeaderPrefix = "X-Qiniu-"
    14  
    15  // ---------------------------------------------------------------------------------------
    16  
    17  func incBody(req *http.Request, ctType string) bool {
    18  	return req.ContentLength != 0 && req.Body != nil && ctType != "" && ctType != "application/octet-stream"
    19  }
    20  
    21  func signQiniuHeaderValues(header http.Header, w io.Writer) {
    22  	var keys []string
    23  	for key := range header {
    24  		if len(key) > len(qiniuHeaderPrefix) && key[:len(qiniuHeaderPrefix)] == qiniuHeaderPrefix {
    25  			keys = append(keys, key)
    26  		}
    27  	}
    28  	if len(keys) == 0 {
    29  		return
    30  	}
    31  
    32  	if len(keys) > 1 {
    33  		sort.Sort(sortByHeaderKey(keys))
    34  	}
    35  	for _, key := range keys {
    36  		io.WriteString(w, "\n"+key+": "+header.Get(key))
    37  	}
    38  }
    39  
    40  // SignRequest sign request
    41  func SignRequest(sk []byte, req *http.Request) ([]byte, error) {
    42  	h := hmac.New(sha1.New, sk)
    43  
    44  	u := req.URL
    45  	data := req.Method + " " + u.Path
    46  	if u.RawQuery != "" {
    47  		data += "?" + u.RawQuery
    48  	}
    49  	io.WriteString(h, data+"\nHost: "+req.Host)
    50  
    51  	ctType := req.Header.Get("Content-Type")
    52  	if ctType != "" {
    53  		io.WriteString(h, "\nContent-Type: "+ctType)
    54  	}
    55  
    56  	signQiniuHeaderValues(req.Header, h)
    57  
    58  	io.WriteString(h, "\n\n")
    59  
    60  	if incBody(req, ctType) {
    61  		s2, err2 := seekable.New(req)
    62  		if err2 != nil {
    63  			return nil, err2
    64  		}
    65  		h.Write(s2.Bytes())
    66  	}
    67  
    68  	return h.Sum(nil), nil
    69  }
    70  
    71  // ---------------------------------------------------------------------------------------
    72  
    73  // RequestSigner request signer
    74  type RequestSigner struct{}
    75  
    76  // DefaultRequestSigner default request signer
    77  var DefaultRequestSigner RequestSigner
    78  
    79  // Sign access key and request
    80  func (p RequestSigner) Sign(sk []byte, req *http.Request) ([]byte, error) {
    81  	return SignRequest(sk, req)
    82  }
    83  
    84  // ---------------------------------------------------------------------------------------
    85  
    86  type sortByHeaderKey []string
    87  
    88  func (p sortByHeaderKey) Len() int           { return len(p) }
    89  func (p sortByHeaderKey) Less(i, j int) bool { return p[i] < p[j] }
    90  func (p sortByHeaderKey) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }