feat: 从黄果 NET hgdjnet-server 9bfbafe 导入 HKDJ 官网后端

来源:hgdjnet-server 9bfbafe10d417deea959bd53117bc88a10e60a83
项目身份 HKDJ / JHA-216,独立官网仓库,Jenkins 守卫键 hkdjnet
测试目录 /server/hkdj_net,App/Web API 30331/30332

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 11:20:04 +08:00
co-authored by Claude Opus 4.7
parent 99a4854def
commit 85c0071fd8
653 changed files with 85000 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
package api_security
import (
"github.com/gin-gonic/gin"
)
func BodyDump() gin.HandlerFunc {
return func(ctx *gin.Context) {
// fmt.Println("=========================== 1")
// fmt.Printf("%+v\n", ctx.Request.Header)
// data, e := ioutil.ReadAll(ctx.Request.Body)
// if e != nil {
// ctx.AbortWithStatusJSON(500, "protosign: read data failed")
// return
// }
// fmt.Println("=========================== 3")
// fmt.Println(hex.Dump(data))
// fmt.Println("=========================== 4")
// ctx.Request.Body = &signReader{
// *bytes.NewReader(data),
// ctx.Request.Body,
// }
// fmt.Println("=========================== 5")
// ctx.Next()
// fmt.Println("=========================== 6")
}
}
+5
View File
@@ -0,0 +1,5 @@
package api_security
const XProtoSign = "X-Proto-Sign"
const XProtoNonce = "X-Proto-Nonce"
const XProtoTimestamp = "X-Proto-Timestamp"
+25
View File
@@ -0,0 +1,25 @@
package api_security
import (
"crypto/sha256"
"math/rand"
)
func GenerateKey(secret string) []byte {
key := sha256.Sum256([]byte(secret))
return key[:]
}
func GenerateIV(secret, salt string) []byte {
return GenerateKey(secret + salt)[:16]
}
const strPool = "012345679qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM"
func GenerateIVSalt() string {
var n [16]byte
for i := 0; i < 16; i++ {
n[i] = byte(strPool[rand.Intn(len(strPool))])
}
return string(n[:])
}
+95
View File
@@ -0,0 +1,95 @@
package api_security
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"sort"
"strings"
"github.com/gin-gonic/gin"
)
type signReader struct {
bytes.Reader
RC io.ReadCloser
}
func (thiz *signReader) Close() error {
return thiz.RC.Close()
}
func calcSign(kv map[string][]byte) string {
keys := make([]string, 0, len(kv))
for k := range kv {
keys = append(keys, k)
}
sort.Strings(keys)
h := sha256.New()
for _, k := range keys {
_, _ = h.Write([]byte(k))
_, _ = h.Write(kv[k])
}
return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}
func ProtoSign(secret []byte,
shouldCrypto ShouldCryptoChecker) gin.HandlerFunc {
return func(ctx *gin.Context) {
if shouldCrypto != nil && !shouldCrypto(ctx) {
ctx.Next()
return
}
sign := ctx.GetHeader(XProtoSign)
nonce := ctx.GetHeader(XProtoNonce)
ts := ctx.GetHeader(XProtoTimestamp)
if len(sign) != 64 || len(nonce) < 10 || len(ts) < 6 {
ctx.AbortWithStatusJSON(500, "protosign: argument invalid")
return
}
data, e := ioutil.ReadAll(ctx.Request.Body)
if e != nil {
ctx.AbortWithStatusJSON(500, "protosign: read data failed")
return
}
kv := make(map[string][]byte)
kv[XProtoNonce] = []byte(nonce)
kv[XProtoTimestamp] = []byte(ts)
kv["_METHOD_"] = []byte(ctx.Request.Method)
kv["_PATH_"] = []byte(ctx.Request.URL.Path)
kv["_SECRET_"] = secret
queries := map[string][]string(ctx.Request.URL.Query())
for k, v := range queries {
if len(v) > 0 {
kv[fmt.Sprintf("_QUERY_%s_", strings.ToUpper(k))] = []byte(v[0])
}
}
if len(data) > 0 {
kv["_BODY_"] = []byte(data)
}
if calcSign(kv) != sign {
ctx.AbortWithStatusJSON(500, "protosign: verify sign failed")
return
}
ctx.Request.Body = &signReader{
*bytes.NewReader(data),
ctx.Request.Body,
}
ctx.Next()
}
}
+38
View File
@@ -0,0 +1,38 @@
package api_security
import (
"crypto/cipher"
"io"
"github.com/gin-gonic/gin"
)
type ShouldCryptoChecker func(ctx *gin.Context) bool
type cryptoReader struct {
S cipher.Stream
RC io.ReadCloser
}
func (r *cryptoReader) Read(dst []byte) (n int, err error) {
n, err = r.RC.Read(dst)
r.S.XORKeyStream(dst[:n], dst[:n])
return
}
func (r *cryptoReader) Close() error {
return r.RC.Close()
}
type cryptoWriter struct {
gin.ResponseWriter
writer *cipher.StreamWriter
}
func (g *cryptoWriter) WriteString(s string) (int, error) {
return g.writer.Write([]byte(s))
}
func (g *cryptoWriter) Write(data []byte) (int, error) {
return g.writer.Write(data)
}