init: web_hgdjc_server
This commit is contained in:
@@ -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")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package api_security
|
||||
|
||||
const XProtoSign = "X-Proto-Sign"
|
||||
const XProtoNonce = "X-Proto-Nonce"
|
||||
const XProtoTimestamp = "X-Proto-Timestamp"
|
||||
@@ -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[:])
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateSalt(t *testing.T) {
|
||||
for i := 0; i < 5; i++ {
|
||||
fmt.Println(GenerateIVSalt())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGenerateSalt(b *testing.B) {
|
||||
GenerateIV("asdfasdfasdf", GenerateIVSalt())
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUrl(t *testing.T) {
|
||||
|
||||
u, _ := url.Parse("http://a.b.com/api/a/b/c?a=%20123")
|
||||
fmt.Printf("path: %s\n", u.Path)
|
||||
fmt.Printf("rawpath: %s\n", u.RawQuery)
|
||||
fmt.Printf("escapedpath: %s\n", u.EscapedPath())
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user