mirror of
https://github.com/eolinker/apinto
synced 2025-09-26 21:01:19 +08:00
132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
package aksk
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
|
)
|
|
|
|
const dateHeader = "x-gateway-date"
|
|
|
|
// buildToSign 构建待加密的签名所需字符串
|
|
func buildToSign(ctx http_service.IHttpContext, encType string, signedHeaders []string) string {
|
|
toSign := strings.Builder{}
|
|
toSign.WriteString(encType + "\n")
|
|
dh := ctx.Request().Header().GetHeader(dateHeader)
|
|
toSign.WriteString(dh + "\n")
|
|
|
|
cr := buildHexCanonicalRequest(ctx, signedHeaders)
|
|
toSign.WriteString(strings.ToLower(cr))
|
|
return toSign.String()
|
|
}
|
|
|
|
// buildHexCanonicalRequest 构建规范消息头
|
|
func buildHexCanonicalRequest(ctx http_service.IHttpContext, signedHeaders []string) string {
|
|
cr := strings.Builder{}
|
|
|
|
cr.WriteString(strings.ToUpper(ctx.Request().Method()) + "\n")
|
|
cr.WriteString(buildPath(ctx.Request().URI().Path()) + "\n")
|
|
// 对query参数排序
|
|
rawQuery := ctx.Request().URI().RawQuery()
|
|
query := url.Values{}
|
|
queryArgs := strings.Split(strings.TrimSpace(rawQuery), "&")
|
|
for i := 0; i < len(queryArgs); i++ {
|
|
params := strings.Split(queryArgs[i], "=")
|
|
if len(params) != 2 {
|
|
//query.SetProvider(params[0], "")
|
|
continue
|
|
}
|
|
query.Set(params[0], params[1])
|
|
}
|
|
cr.WriteString(query.Encode() + "\n")
|
|
//cr.WriteString(ctx.Request().URI().RawQuery() + "\n")
|
|
|
|
for _, header := range signedHeaders {
|
|
if strings.ToLower(header) == "host" {
|
|
cr.WriteString(buildHeaders(header, ctx.Request().Header().Host()) + "\n")
|
|
continue
|
|
}
|
|
v := ctx.Request().Header().GetHeader(header)
|
|
cr.WriteString(buildHeaders(header, v) + "\n")
|
|
}
|
|
cr.WriteString("\n")
|
|
cr.WriteString(strings.Join(signedHeaders, ";") + "\n")
|
|
body, _ := ctx.Request().Body().RawBody()
|
|
cr.WriteString(hexEncode(body))
|
|
|
|
return hexEncode([]byte(cr.String()))
|
|
}
|
|
|
|
func buildPath(path string) string {
|
|
return strings.TrimSuffix(path, "/") + "/"
|
|
}
|
|
|
|
func buildHeaders(hk, hv string) string {
|
|
return fmt.Sprintf("%s:%s", hk, strings.TrimSpace(hv))
|
|
}
|
|
|
|
func hexEncode(data []byte) string {
|
|
sha := sha256.New()
|
|
sha.Write(data)
|
|
return hex.EncodeToString(sha.Sum(nil))
|
|
}
|
|
|
|
func hMaxBySHA256(secretKey, toSign string) string {
|
|
// 创建对应的sha256哈希加密算法
|
|
hm := hmac.New(sha256.New, []byte(secretKey))
|
|
//写入加密数据
|
|
hm.Write([]byte(toSign))
|
|
return hex.EncodeToString(hm.Sum(nil))
|
|
}
|
|
|
|
func parseAuthorization(token string) (encType string, accessKey string, signHeaders []string, signature string, err error) {
|
|
|
|
infos := strings.Split(token, ",")
|
|
if len(infos) < 3 {
|
|
err = errors.New("invalid authorization")
|
|
return
|
|
}
|
|
encType, accessKey, err = parseAccessKey(infos[0])
|
|
if err != nil {
|
|
return
|
|
}
|
|
signHeaders = parseSignHeaders(infos[1])
|
|
|
|
signature = parseSignature(infos[2])
|
|
|
|
return
|
|
}
|
|
|
|
func parseAccessKey(info string) (string, string, error) {
|
|
info = strings.TrimSpace(info)
|
|
akInfos := strings.Split(info, " ")
|
|
encType := ""
|
|
accessKey := ""
|
|
if len(akInfos) < 1 {
|
|
return "", "", errors.New("error access key")
|
|
} else if len(akInfos) == 1 {
|
|
accessKey = strings.Replace(akInfos[0], "Access=", "", 1)
|
|
} else if len(akInfos) == 2 {
|
|
encType = akInfos[0]
|
|
accessKey = strings.Replace(akInfos[1], "Access=", "", 1)
|
|
}
|
|
return encType, accessKey, nil
|
|
}
|
|
|
|
func parseSignHeaders(info string) []string {
|
|
info = strings.Replace(strings.TrimSpace(info), "SignedHeaders=", "", 1)
|
|
headers := strings.Split(strings.ToLower(info), ";")
|
|
return headers
|
|
}
|
|
|
|
func parseSignature(info string) string {
|
|
info = strings.Replace(strings.TrimSpace(info), "Signature=", "", 1)
|
|
return info
|
|
}
|