121 lines
4.3 KiB
Go
121 lines
4.3 KiB
Go
package logweb
|
||
|
||
import (
|
||
"net/http"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"xk-hy-transit-go/internal/fileauth"
|
||
syncer "xk-hy-transit-go/internal/sync"
|
||
)
|
||
|
||
// FileAuthGenerateResponse Web 上传凭证调试 API。
|
||
type FileAuthGenerateResponse struct {
|
||
AccessKey string `json:"accessKey"`
|
||
SecretSet bool `json:"secretSet"`
|
||
Bucket string `json:"bucket"`
|
||
Scope string `json:"scope"`
|
||
B64Mode string `json:"b64Mode"`
|
||
PolicyJSON string `json:"policyJson"`
|
||
EncodedPutPolicy string `json:"encodedPutPolicy"`
|
||
SignInput string `json:"signInput"`
|
||
EncodedSign string `json:"encodedSign"`
|
||
SignHex string `json:"signHex,omitempty"`
|
||
UploadToken string `json:"uploadToken"`
|
||
UploadTokenMasked string `json:"uploadTokenMasked"`
|
||
DeadlineUnix int64 `json:"deadlineUnix"`
|
||
ExpiresSec int64 `json:"expiresSec"`
|
||
Algorithm string `json:"algorithm"`
|
||
FormatOK bool `json:"formatOk"`
|
||
FormatChecks []fileauth.FormatCheck `json:"formatChecks"`
|
||
RunnerTokenMatch bool `json:"runnerTokenMatch"`
|
||
RunnerTokenPreview string `json:"runnerTokenPreview"`
|
||
}
|
||
|
||
func (s *Server) handleAPIFileAuthGenerate(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method != http.MethodGet && r.Method != http.MethodPost {
|
||
writeErr(w, 405, "GET or POST only")
|
||
return
|
||
}
|
||
sr := asSyncRunner(s.deps.Runner)
|
||
if sr == nil {
|
||
writeErr(w, 503, "未配置 Runner(请使用 transit serve)")
|
||
return
|
||
}
|
||
|
||
refresh := r.URL.Query().Get("refresh") == "1" || r.URL.Query().Get("refresh") == "true"
|
||
if refresh {
|
||
if err := sr.RegenerateUploadToken(); err != nil {
|
||
writeErr(w, 502, "刷新 Runner uploadToken 失败: "+err.Error())
|
||
return
|
||
}
|
||
}
|
||
|
||
snap := sr.ConfigSnapshot()
|
||
accessKey := strings.TrimSpace(snap.EffectiveAppKey)
|
||
secret := strings.TrimSpace(snap.EffectiveSecret)
|
||
bucket := strings.TrimSpace(r.URL.Query().Get("bucket"))
|
||
if bucket == "" {
|
||
bucket = strings.TrimSpace(snap.EffectiveFileBucket)
|
||
}
|
||
|
||
if accessKey == "" || secret == "" {
|
||
writeErr(w, 400, "生效 appKey/appSecret 未配置,请在 /config 重新拉取或配置 HY_APP_KEY/HY_APP_SECRET")
|
||
return
|
||
}
|
||
if bucket == "" {
|
||
writeErr(w, 400, "fileBucket(scope) 为空,请配置 HY_FILE_BUCKET")
|
||
return
|
||
}
|
||
|
||
deadlineUnix := time.Now().Unix() + 3600
|
||
if ds := strings.TrimSpace(r.URL.Query().Get("deadline")); ds != "" {
|
||
n, err := strconv.ParseInt(ds, 10, 64)
|
||
if err != nil || n <= 0 {
|
||
writeErr(w, 400, "invalid deadline (unix seconds)")
|
||
return
|
||
}
|
||
deadlineUnix = n
|
||
}
|
||
|
||
parts, err := fileauth.BuildUploadTokenPartsForUpload(accessKey, secret, bucket, deadlineUnix)
|
||
if err != nil {
|
||
writeErr(w, 500, err.Error())
|
||
return
|
||
}
|
||
|
||
formatOK, checks := fileauth.ValidateUploadTokenFormat(parts.UploadToken, accessKey)
|
||
runnerTok := strings.TrimSpace(sr.UploadToken())
|
||
runnerMatch := runnerTok != "" && runnerTok == parts.UploadToken
|
||
|
||
writeJSON(w, FileAuthGenerateResponse{
|
||
AccessKey: parts.AccessKey,
|
||
SecretSet: secret != "",
|
||
Bucket: bucket,
|
||
Scope: bucket,
|
||
B64Mode: fileauth.B64Mode(),
|
||
PolicyJSON: parts.PolicyJSON,
|
||
EncodedPutPolicy: parts.EncodedPutPolicy,
|
||
SignInput: parts.SignInput,
|
||
EncodedSign: parts.EncodedSign,
|
||
SignHex: fileauth.HMACSignHex(secret, parts.SignInput),
|
||
UploadToken: parts.UploadToken,
|
||
UploadTokenMasked: maskPreview(parts.UploadToken),
|
||
DeadlineUnix: parts.DeadlineUnix,
|
||
ExpiresSec: parts.ExpiresSec,
|
||
Algorithm: parts.Algorithm,
|
||
FormatOK: formatOK,
|
||
FormatChecks: checks,
|
||
RunnerTokenMatch: runnerMatch,
|
||
RunnerTokenPreview: maskPreview(runnerTok),
|
||
})
|
||
}
|
||
|
||
// RunnerCredentialsForFileAuth 供测试或扩展:从快照读取凭证。
|
||
func RunnerCredentialsForFileAuth(snap syncer.ConfigSnapshot) (accessKey, secret, bucket string) {
|
||
return strings.TrimSpace(snap.EffectiveAppKey),
|
||
strings.TrimSpace(snap.EffectiveSecret),
|
||
strings.TrimSpace(snap.EffectiveFileBucket)
|
||
}
|