Files
xk-hy-transit-go/internal/fileauth/parts.go
2026-05-28 17:03:08 +08:00

129 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package fileauth
import (
"encoding/base64"
"encoding/json"
"errors"
"strings"
)
// UploadTokenParts 上传凭证分步结果FileAuth.javaAccessKey:encodedSign:policyB64
type UploadTokenParts struct {
AccessKey string
PolicyJSON string
EncodedPutPolicy string // 第三段policy JSON 的 URL-safe Base64
SignInput string // HMAC 输入policy JSON 明文
EncodedSign string
UploadToken string
DeadlineUnix int64
ExpiresSec int64
Algorithm string
}
// FormatCheck 单条 uploadToken 格式校验结果。
type FormatCheck struct {
ID string `json:"id"`
OK bool `json:"ok"`
Detail string `json:"detail"`
}
// BuildUploadTokenParts 分步生成上传凭证(生产 upload profilescope=仅 bucket
func BuildUploadTokenParts(accessKey, secret, bucket string, deadlineUnix int64) (UploadTokenParts, error) {
return BuildUploadTokenPartsForUpload(accessKey, secret, bucket, deadlineUnix)
}
// SplitUploadToken 按前两处英文冒号拆分为 accessKey、encodedSign、encodedPutPolicy。
func SplitUploadToken(token string) (accessKey, encodedSign, encodedPutPolicy string, ok bool) {
token = strings.TrimSpace(token)
i := strings.Index(token, ":")
if i <= 0 {
return "", "", "", false
}
rest := token[i+1:]
j := strings.Index(rest, ":")
if j <= 0 {
return "", "", "", false
}
ak := token[:i]
sign := rest[:j]
pol := rest[j+1:]
if ak == "" || sign == "" || pol == "" {
return "", "", "", false
}
return ak, sign, pol, true
}
// ValidateUploadTokenFormat 校验 token 是否符合 AccessKey:sign:policyB64expectedAccessKey 非空时校验首段。
func ValidateUploadTokenFormat(token, expectedAccessKey string) (allOK bool, checks []FormatCheck) {
ak, sign, pol, ok := SplitUploadToken(token)
checks = []FormatCheck{
{
ID: "three_parts",
OK: ok,
Detail: "uploadToken = AccessKey + ':' + encodedSign + ':' + policyB64按前两处冒号拆分",
},
{
ID: "access_key_non_empty",
OK: ok && ak != "",
Detail: "第 1 段 AccessKey 非空",
},
{
ID: "encoded_sign_non_empty",
OK: ok && sign != "",
Detail: "第 2 段 encodedSignURL-safe Base64 HMAC非空",
},
{
ID: "encoded_policy_non_empty",
OK: ok && pol != "",
Detail: "第 3 段 policyB64URL-safe Base64 policy JSON非空",
},
}
if expectedAccessKey != "" {
exp := strings.TrimSpace(expectedAccessKey)
match := ok && ak == exp
checks = append(checks, FormatCheck{
ID: "access_key_match",
OK: match,
Detail: "第 1 段与当前 AccessKey 一致",
})
}
_, decErr := DecodePutPolicyB64(pol)
checks = append(checks, FormatCheck{
ID: "policy_b64_decodable",
OK: ok && decErr == nil,
Detail: "第 3 段可 URL-safe Base64 解码为 JSON",
})
allOK = true
for _, c := range checks {
if !c.OK {
allOK = false
break
}
}
return allOK, checks
}
// DecodePutPolicyB64 解码 policyB64 为 JSON 字符串(美化缩进)。
func DecodePutPolicyB64(encoded string) (string, error) {
encoded = strings.TrimSpace(encoded)
if encoded == "" {
return "", errors.New("empty encoded policy")
}
raw, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
raw, err = base64.URLEncoding.DecodeString(encoded)
if err != nil {
return "", err
}
}
var pretty interface{}
if err := json.Unmarshal(raw, &pretty); err != nil {
return string(raw), nil
}
out, err := json.MarshalIndent(pretty, "", " ")
if err != nil {
return string(raw), nil
}
return string(out), nil
}