Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
94 lines
2.1 KiB
Go
94 lines
2.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/md5"
|
|
"fmt"
|
|
"math/rand"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
nonceChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
nonceLength = 16
|
|
)
|
|
|
|
// Sign 按 WeKnoraCloud 参考实现生成请求头。
|
|
// appID: 上游 APPID
|
|
// apiKey: 上游 API Key(当前沿用 AppSecret 字段承载)
|
|
// requestID: 每次请求唯一的 UUID 字符串
|
|
// bodyJSON: 请求体 JSON 字符串,空请求体传 "{}"
|
|
func Sign(appID, apiKey, requestID, bodyJSON string) map[string]string {
|
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
|
nonce := generateNonce(nonceLength)
|
|
|
|
bodyForHash := bodyJSON
|
|
if bodyForHash == "" {
|
|
bodyForHash = "{}"
|
|
}
|
|
bodyMD5 := md5Hex(bodyForHash)
|
|
|
|
params := map[string]string{
|
|
"x-appid": appID,
|
|
"x-api-key": apiKey,
|
|
"x-request-id": requestID,
|
|
"x-timestamp": timestamp,
|
|
"x-nonce": nonce,
|
|
"body": bodyMD5,
|
|
}
|
|
|
|
keys := make([]string, 0, len(params))
|
|
for k := range params {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
parts := make([]string, 0, len(keys))
|
|
for _, k := range keys {
|
|
parts = append(parts, rfc3986Encode(k)+"="+rfc3986Encode(params[k]))
|
|
}
|
|
signature := md5Hex(strings.Join(parts, "&"))
|
|
|
|
return map[string]string{
|
|
"X-APPID": appID,
|
|
"X-API-Key": apiKey,
|
|
"X-Request-ID": requestID,
|
|
"X-Timestamp": timestamp,
|
|
"X-Nonce": nonce,
|
|
"X-Signature": signature,
|
|
}
|
|
}
|
|
|
|
func md5Hex(s string) string {
|
|
h := md5.New()
|
|
h.Write([]byte(s))
|
|
return fmt.Sprintf("%x", h.Sum(nil))
|
|
}
|
|
|
|
func generateNonce(length int) string {
|
|
b := make([]byte, length)
|
|
for i := range b {
|
|
b[i] = nonceChars[rand.Intn(len(nonceChars))]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// rfc3986Encode 对字符串做 RFC3986 编码
|
|
// 保留字符:A-Z a-z 0-9 - _ . ~
|
|
func rfc3986Encode(s string) string {
|
|
var buf bytes.Buffer
|
|
for _, r := range s {
|
|
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') ||
|
|
(r >= '0' && r <= '9') || r == '-' || r == '_' ||
|
|
r == '.' || r == '~' {
|
|
buf.WriteRune(r)
|
|
} else {
|
|
fmt.Fprintf(&buf, "%%%02X", r)
|
|
}
|
|
}
|
|
return buf.String()
|
|
}
|