174 lines
4.5 KiB
Go
174 lines
4.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var adminSecret string
|
|
|
|
// InitAuth 设置后台 token 签名密钥
|
|
func InitAuth(secret string) {
|
|
adminSecret = secret
|
|
}
|
|
|
|
func GetEnv(k, def string) string {
|
|
if v := os.Getenv(k); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
|
|
func SignToken(account string) string {
|
|
payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, account, time.Now().Add(24*time.Hour).Unix())
|
|
b64 := base64.StdEncoding.EncodeToString([]byte(payload))
|
|
mac := hmac.New(sha256.New, []byte(adminSecret))
|
|
mac.Write([]byte(b64))
|
|
sig := base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
return b64 + "." + sig
|
|
}
|
|
|
|
func SignCashGiftViewToken() string {
|
|
payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, "cash-gift-view", time.Now().Add(7*24*time.Hour).Unix())
|
|
b64 := base64.StdEncoding.EncodeToString([]byte(payload))
|
|
mac := hmac.New(sha256.New, []byte(adminSecret))
|
|
mac.Write([]byte(b64))
|
|
sig := base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
return b64 + "." + sig
|
|
}
|
|
|
|
func SignCashGiftEntryToken() string {
|
|
payload := fmt.Sprintf(`{"account":%q,"exp":%d}`, "cash-gift-entry", time.Now().Add(7*24*time.Hour).Unix())
|
|
b64 := base64.StdEncoding.EncodeToString([]byte(payload))
|
|
mac := hmac.New(sha256.New, []byte(adminSecret))
|
|
mac.Write([]byte(b64))
|
|
sig := base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
return b64 + "." + sig
|
|
}
|
|
|
|
func parseTokenClaims(token string) (account string, exp int64, ok bool) {
|
|
parts := strings.Split(token, ".")
|
|
if len(parts) != 2 {
|
|
return "", 0, false
|
|
}
|
|
mac := hmac.New(sha256.New, []byte(adminSecret))
|
|
mac.Write([]byte(parts[0]))
|
|
expected := base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
if !hmac.Equal([]byte(expected), []byte(parts[1])) {
|
|
return "", 0, false
|
|
}
|
|
raw, err := base64.StdEncoding.DecodeString(parts[0])
|
|
if err != nil {
|
|
return "", 0, false
|
|
}
|
|
var claims struct {
|
|
Account string `json:"account"`
|
|
Exp int64 `json:"exp"`
|
|
}
|
|
if err := json.Unmarshal(raw, &claims); err != nil {
|
|
return "", 0, false
|
|
}
|
|
if time.Now().Unix() > claims.Exp {
|
|
return "", 0, false
|
|
}
|
|
return claims.Account, claims.Exp, true
|
|
}
|
|
|
|
func VerifyToken(token string) bool {
|
|
_, _, ok := parseTokenClaims(token)
|
|
return ok
|
|
}
|
|
|
|
func VerifyCashGiftViewToken(token string) bool {
|
|
account, _, ok := parseTokenClaims(token)
|
|
return ok && account == "cash-gift-view"
|
|
}
|
|
|
|
func VerifyCashGiftEntryToken(token string) bool {
|
|
account, _, ok := parseTokenClaims(token)
|
|
return ok && account == "cash-gift-entry"
|
|
}
|
|
|
|
func BearerToken(c *gin.Context) string {
|
|
return strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
|
|
}
|
|
|
|
func RequireAdmin(c *gin.Context) bool {
|
|
if !VerifyToken(BearerToken(c)) {
|
|
c.JSON(401, gin.H{"error": "未授权,请先登录后台"})
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func CORSMiddleware() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT")
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Cash-Gift-Token, X-Cash-Gift-Entry-Token")
|
|
if c.Request.Method == "OPTIONS" {
|
|
c.AbortWithStatus(204)
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func EscapeMySQLComment(s string) string {
|
|
s = strings.ReplaceAll(s, `\`, `\\`)
|
|
s = strings.ReplaceAll(s, `'`, `''`)
|
|
return s
|
|
}
|
|
|
|
func CleanObjectName(name string) string {
|
|
name = filepath.Base(name)
|
|
name = strings.ReplaceAll(name, "\\", "_")
|
|
name = strings.ReplaceAll(name, "/", "_")
|
|
name = strings.TrimSpace(name)
|
|
if name == "" || name == "." {
|
|
return "upload"
|
|
}
|
|
return name
|
|
}
|
|
|
|
func BuildObjectKey(folder string, originalName string) string {
|
|
folder = strings.Trim(folder, "/ ")
|
|
name := CleanObjectName(originalName)
|
|
fileName := fmt.Sprintf("%s_%s", time.Now().Format("150405000000000"), name)
|
|
day := time.Now().Format("20060102")
|
|
if folder == "" {
|
|
return day + "/" + fileName
|
|
}
|
|
return folder + "/" + day + "/" + fileName
|
|
}
|
|
|
|
func EscapedObjectKey(key string) string {
|
|
parts := strings.Split(key, "/")
|
|
for i, part := range parts {
|
|
parts[i] = url.PathEscape(part)
|
|
}
|
|
return strings.Join(parts, "/")
|
|
}
|
|
|
|
func NormalizeEndpoint(endpoint string, region string) string {
|
|
endpoint = strings.TrimSpace(endpoint)
|
|
region = strings.TrimSpace(region)
|
|
if endpoint == "" && region != "" {
|
|
endpoint = "https://oss-" + region + ".aliyuncs.com"
|
|
}
|
|
if endpoint != "" && !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") {
|
|
endpoint = "https://" + endpoint
|
|
}
|
|
return endpoint
|
|
}
|