From 70e32e7d8e0615325b277cb4dd324d2e26d16341 Mon Sep 17 00:00:00 2001 From: Yun Date: Sun, 12 Oct 2025 18:41:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AD=BE=E5=90=8D=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + api.go | 58 ++++++++------ api_test.go | 192 +++++++++++++++++++++++++++++++++++++++++++++++ errorx.go | 3 + go.mod | 36 ++++++++- go.sum | 91 +++++++++++++++++++++- option.go | 46 ++++++++++++ platform.go | 36 +++++---- platform_test.go | 7 +- 9 files changed, 426 insertions(+), 44 deletions(-) create mode 100644 .gitignore create mode 100644 api_test.go create mode 100644 option.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/api.go b/api.go index 3a890b5..a79c802 100644 --- a/api.go +++ b/api.go @@ -1,37 +1,49 @@ package bopx import ( + "context" "crypto/md5" "fmt" "sort" "strings" "code.yun.ink/pkg/convx" + "github.com/yuninks/loggerx" ) -// 缺点 -// 1.值必须是字符串,数组/对象这些不允许,或者需要通过一定规则转成字符串 - -type apix struct { - ingoreKey []string - signKey string -} - -func NewApi(ignoreKey []string, signKey string) *apix { - return &apix{ - ingoreKey: ignoreKey, - signKey: signKey, - } -} - // 签名规则 // 1.除掉不参与签名的用户参数 // 1.所有参数的key根据字典排序 // 2.根据key=val&key2=val2的格式组装字符串 // 3.后面拼接用户签名key `&key=xxxx`得道新字符串 // 4.把新字符串用md5加密并转大写的道签名的值 -func (l *apix) GetSign(params map[string]interface{}) (sign string, err error) { - for _, val := range l.ingoreKey { + +// 缺点 +// 1.值必须是字符串,数组/对象这些不允许,或者需要通过一定规则转成字符串 + +type apix struct { + logger loggerx.LoggerInterface + ignoreKeys []string +} + +func NewApi(opts ...Option) *apix { + options := newOptions(opts...) + return &apix{ + logger: options.logger, + ignoreKeys: options.ignoreKeys, + } +} + +// 计算签名值 +func (l *apix) GetSign(ctx context.Context, signKey string, params map[string]any) (sign string, err error) { + if signKey == "" { + return "", ErrorSignKeyIsEmpty + } + if len(params) == 0 { + return "", ErrorSignParamIsEmpty + } + + for _, val := range l.ignoreKeys { delete(params, val) } @@ -48,21 +60,19 @@ func (l *apix) GetSign(params map[string]interface{}) (sign string, err error) { if k > 0 { str = str + "&" } - val, err := convx.ToString(params[v]) - if err != nil { - return "", err - } + val := convx.ToString(params[v]) str = str + v + "=" + val } - str = str + "&key=" + l.signKey + str = str + "&key=" + signKey data := []byte(str) has := md5.Sum(data) md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 sign = strings.ToUpper(md5str1) + l.logger.Infof(ctx, "bopx sign Str:%s sign:%s", str, sign) return sign, nil } -func (l *apix) Verify(params map[string]interface{}) error { +func (l *apix) Verify(ctx context.Context, signKey string, params map[string]interface{}) error { sign, ok := params["sign"] if !ok { @@ -72,7 +82,7 @@ func (l *apix) Verify(params map[string]interface{}) error { if !ok { return ErrorSignMustBeString } - g_sign, err := l.GetSign(params) + g_sign, err := l.GetSign(ctx, signKey, params) if err != nil { return err } diff --git a/api_test.go b/api_test.go new file mode 100644 index 0000000..0b14482 --- /dev/null +++ b/api_test.go @@ -0,0 +1,192 @@ +package bopx_test + +import ( + "context" + "testing" + + "code.yun.ink/pkg/bopx" + "github.com/stretchr/testify/assert" +) + +// TestApiGetSign 测试API签名生成 +func TestApiGetSign(t *testing.T) { + // 测试用例1: 基本参数签名 + params := map[string]interface{}{ + "name": "huang", + "age": 18, + } + + api := bopx.NewApi() + sign, err := api.GetSign(context.Background(), "huangxinyun", params) + if err != nil { + t.Errorf("GetSign returned error: %v", err) + } + + expectedSign := "F84C5DF671D8279B57AC6EED2C140407" // 根据算法计算得出的预期值 + if sign != expectedSign { + t.Errorf("GetSign() = %v, want %v", sign, expectedSign) + } + + // 记录生成的签名值 + t.Logf("Generated sign: %s", sign) +} + +// TestApiVerify 测试API签名验证 +func TestApiVerify(t *testing.T) { + // 测试用例1: 正确签名验证 + params := map[string]interface{}{ + "name": "huang", + "age": 18, + } + + api := bopx.NewApi() + sign, err := api.GetSign(context.Background(), "huangxinyun", params) + if err != nil { + t.Errorf("GetSign returned error: %v", err) + } + + params["sign"] = sign + err = api.Verify(context.Background(), "huangxinyun", params) + if err != nil { + t.Errorf("Verify returned error: %v", err) + } + + // 测试用例2: 签名参数不存在 + paramsWithoutSign := map[string]interface{}{ + "name": "huang", + "age": 18, + } + + err = api.Verify(context.Background(), "huangxinyun", paramsWithoutSign) + if err != bopx.ErrorSignParamNotExist { + t.Errorf("Verify should return ErrorSignParamNotExist, got: %v", err) + } + + // 测试用例3: 签名参数不是字符串 + paramsWithInvalidSign := map[string]interface{}{ + "name": "huang", + "age": 18, + "sign": 12345, // 非字符串类型 + } + + err = api.Verify(context.Background(), "huangxinyun", paramsWithInvalidSign) + if err != bopx.ErrorSignMustBeString { + t.Errorf("Verify should return ErrorSignMustBeString, got: %v", err) + } + + // 测试用例4: 签名不匹配 + paramsWithWrongSign := map[string]interface{}{ + "name": "huang", + "age": 18, + "sign": "WRONGSIGN", + } + + err = api.Verify(context.Background(), "huangxinyun", paramsWithWrongSign) + if err != bopx.ErrorSignFail { + t.Errorf("Verify should return ErrorSignFail, got: %v", err) + } +} + +// TestApiIgnoreKeys 测试忽略键功能 +func TestApiIgnoreKeys(t *testing.T) { + params := map[string]interface{}{ + "name": "huang", + "age": 18, + "platform_key": "ignored", + "sign": "ignored", + "key": "ignored", + } + + api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key")) + sign, err := api.GetSign(context.Background(), "huangxinyun", params) + if err != nil { + t.Errorf("GetSign returned error: %v", err) + } + + // 验证忽略的键不影响签名结果 + paramsWithoutIgnored := map[string]interface{}{ + "name": "huang", + "age": 18, + } + + signWithoutIgnored, err := api.GetSign(context.Background(), "huangxinyun", paramsWithoutIgnored) + if err != nil { + t.Errorf("GetSign returned error: %v", err) + } + + if sign != signWithoutIgnored { + t.Errorf("Signatures with/without ignored keys should be equal. With ignored: %s, without: %s", sign, signWithoutIgnored) + } +} + +// TestApiEmptyParams 测试空参数 +func TestApiEmptyParams(t *testing.T) { + params := map[string]interface{}{} + + api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key")) + sign, err := api.GetSign(context.Background(), "huangxinyun", params) + + assert.NotNil(t, err) + + assert.Equal(t, bopx.ErrorSignParamIsEmpty, err) + assert.Equal(t, "", sign) + +} + +// TestApiSpecialValues 测试特殊值 +func TestApiSpecialValues(t *testing.T) { + params := map[string]interface{}{ + "empty_string": "", + "nil_value": nil, + "zero": 0, + "special_chars": "!@#$%^&*()_+-=[]{}|;':\",./<>?", + } + + api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key")) + sign, err := api.GetSign(context.Background(), "testkey", params) + if err != nil { + t.Errorf("GetSign returned error: %v", err) + } + + if sign == "" { + t.Error("Sign should not be empty for special values") + } + + params["sign"] = sign + err = api.Verify(context.Background(), "testkey", params) + if err != nil { + t.Errorf("Verify returned error: %v", err) + } +} + +// TestApiConsistentResults 测试签名一致性 +func TestApiConsistentResults(t *testing.T) { + params1 := map[string]interface{}{ + "c": "third", + "a": "first", + "b": "second", + } + + params2 := map[string]interface{}{ + "b": "second", + "c": "third", + "a": "first", + } + + api := bopx.NewApi() + + sign1, err := api.GetSign(context.Background(), "consistentkey", params1) + if err != nil { + t.Errorf("GetSign for params1 returned error: %v", err) + } + + sign2, err := api.GetSign(context.Background(), "consistentkey", params2) + if err != nil { + t.Errorf("GetSign for params2 returned error: %v", err) + } + + // 由于参数排序,两种不同顺序的map应该产生相同的签名 + if sign1 != sign2 { + t.Errorf("Signatures should be consistent regardless of parameter order. sign1: %s, sign2: %s", sign1, sign2) + } +} diff --git a/errorx.go b/errorx.go index f5d1602..80fc111 100644 --- a/errorx.go +++ b/errorx.go @@ -6,4 +6,7 @@ var ( ErrorSignParamNotExist = errors.New("签名参数不存在") ErrorSignMustBeString = errors.New("sign必须是字符串") ErrorSignFail = errors.New("验签失败") + ErrorSignParamEmpty = errors.New("签名参数为空") + ErrorSignParamIsEmpty = errors.New("签名参数不能为空") + ErrorSignKeyIsEmpty = errors.New("签名key不能为空") ) diff --git a/go.mod b/go.mod index be0dd71..93c16fb 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,38 @@ module code.yun.ink/pkg/bopx go 1.20 -require code.yun.ink/pkg/convx v1.0.1 +require ( + code.yun.ink/pkg/convx v1.0.3 + github.com/stretchr/testify v1.8.3 + github.com/yuninks/loggerx v1.0.13 +) + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index fe3664f..e440063 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,89 @@ -code.yun.ink/pkg/convx v1.0.1 h1:T6yIVqyC1nQc9CO0C7iHn5rs7GxbaulmrJtxwg95q9Y= -code.yun.ink/pkg/convx v1.0.1/go.mod h1:6xqmUend1kwarRvJ0TQlfzzS4QCWdRrXQiUY/ggzYqo= +code.yun.ink/pkg/convx v1.0.3 h1:pH8dUOgsoaBYVQ3+4C2+uVua561nDxq6/GpaQ9wnCew= +code.yun.ink/pkg/convx v1.0.3/go.mod h1:6xqmUend1kwarRvJ0TQlfzzS4QCWdRrXQiUY/ggzYqo= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuninks/loggerx v1.0.13 h1:NVb0oHoZeJ59ZAaU5HqcpY7TfZlLaXQEzkRhdOTthiA= +github.com/yuninks/loggerx v1.0.13/go.mod h1:+QFoywQ1ICh4v40zj6OHM8GBZHEqV0yvRbkZjZUe2o4= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/option.go b/option.go new file mode 100644 index 0000000..98082c0 --- /dev/null +++ b/option.go @@ -0,0 +1,46 @@ +package bopx + +import ( + "context" + + "github.com/yuninks/loggerx" +) + +type Options struct { + logger loggerx.LoggerInterface // 日志接口 + ignoreKeys []string // 忽略签名的key +} + +type Option func(*Options) + +func newOptions(opts ...Option) *Options { + options := defaultOptions() + for _, opt := range opts { + opt(options) + } + return options +} + +func defaultOptions() *Options { + return &Options{ + logger: loggerx.NewLogger( + context.Background(), + loggerx.SetEscapeHTML(false), + ), + ignoreKeys: []string{ + "sign", + }, + } +} + +func WithLogger(logger loggerx.LoggerInterface) Option { + return func(o *Options) { + o.logger = logger + } +} + +func WithIgnoreKeys(keys ...string) Option { + return func(o *Options) { + o.ignoreKeys = keys + } +} diff --git a/platform.go b/platform.go index c1b229f..6becc7b 100644 --- a/platform.go +++ b/platform.go @@ -2,28 +2,39 @@ package bopx import ( + "context" "crypto/md5" "fmt" "sort" "strings" "code.yun.ink/pkg/convx" + "github.com/yuninks/loggerx" ) type platform struct { - ingoreKey []string - signKey string + ingoreKeys []string + logger loggerx.LoggerInterface } -func NewPlatform(ignoreKey []string, signKey string) *platform { +func NewPlatform(opts ...Option) *platform { + options := newOptions(opts...) return &platform{ - ingoreKey: ignoreKey, - signKey: signKey, + ingoreKeys: options.ignoreKeys, + logger: options.logger, } } -func (l *platform) GetSign(params map[string]interface{}) (sign string, err error) { - for _, val := range l.ingoreKey { +func (l *platform) GetSign(ctx context.Context, signKey string, params map[string]any) (sign string, err error) { + + if signKey == "" { + return "", ErrorSignKeyIsEmpty + } + if len(params) == 0 { + return "", ErrorSignParamIsEmpty + } + + for _, val := range l.ingoreKeys { delete(params, val) } @@ -40,13 +51,10 @@ func (l *platform) GetSign(params map[string]interface{}) (sign string, err erro if k > 0 { str = str + "&" } - val, err := convx.ToString(params[v]) - if err != nil { - return "", err - } + val := convx.ToString(params[v]) str = str + v + "=" + val } - str = str + "&key=" + l.signKey + str = str + "&key=" + signKey data := []byte(str) has := md5.Sum(data) md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 @@ -54,7 +62,7 @@ func (l *platform) GetSign(params map[string]interface{}) (sign string, err erro return sign, nil } -func (l *platform) VerifySign(params map[string]interface{}) error { +func (l *platform) VerifySign(ctx context.Context, signKey string, params map[string]interface{}) error { sign, ok := params["sign"] if !ok { return ErrorSignParamNotExist @@ -63,7 +71,7 @@ func (l *platform) VerifySign(params map[string]interface{}) error { if !ok { return ErrorSignMustBeString } - g_sign, err := l.GetSign(params) + g_sign, err := l.GetSign(ctx, signKey, params) if err != nil { return err } diff --git a/platform_test.go b/platform_test.go index 332eb54..24f9945 100644 --- a/platform_test.go +++ b/platform_test.go @@ -1,6 +1,7 @@ package bopx_test import ( + "context" "testing" "code.yun.ink/pkg/bopx" @@ -16,14 +17,14 @@ func TestGetSign(t *testing.T) { // delete(params, "sign") // delete(params, "key") - s := bopx.NewPlatform([]string{"platform_key", "sign", "key"}, "huangxinyun") - sign, err := s.GetSign(params) + s := bopx.NewPlatform() + sign, err := s.GetSign(context.Background(), "huangxinyun", params) if err != nil { t.Error(err) } t.Log(sign) params["sign"] = sign - err = s.VerifySign(params) + err = s.VerifySign(context.Background(), "huangxinyun", params) if err != nil { t.Error(err) }