voucher/internal/data/mixrepoimpl/cmb.go

427 lines
9.7 KiB
Go

package mixrepoimpl
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/go-kratos/kratos/v2/log"
http2 "github.com/go-kratos/kratos/v2/transport/http"
"io"
"net/http"
"net/url"
"time"
err2 "voucher/api/err"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/mixrepos"
"voucher/internal/biz/vo"
"voucher/internal/conf"
"voucher/internal/pkg/cmb"
"voucher/internal/pkg/cmbv2"
"voucher/internal/pkg/helper"
"voucher/internal/pkg/request"
)
type CmbMixRepoImpl struct {
bc *conf.Bootstrap
cmb *cmbv2.Cmb
voucher *cmbv2.Cmb
}
func NewCmbMixRepoImpl(bc *conf.Bootstrap) (mixrepos.CmbMixRepo, error) {
newCmb, err := cmbv2.NewCmb(bc.Cmb.CmbSm2Pik, bc.Cmb.CmbSm2Puk)
if err != nil {
return nil, err
}
voucher, err := cmbv2.NewCmb(bc.Cmb.Sm2Prk, bc.Cmb.Sm2Puk)
if err != nil {
return nil, err
}
return &CmbMixRepoImpl{bc: bc, cmb: newCmb, voucher: voucher}, nil
}
func (c *CmbMixRepoImpl) recordBody(ctx context.Context) {
httpRequest, ok := http2.RequestFromServerContext(ctx)
if !ok {
log.Errorf("read body not ok")
return
}
bodyBytes, err := io.ReadAll(httpRequest.Body)
if err != nil {
log.Errorf("read body not ok, %v", err)
return
}
log.Errorf("body %v", string(bodyBytes))
}
func (s *CmbMixRepoImpl) OrderVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbOrderRequest, error) {
bizStr, err := s.Verify(ctx, req)
if err != nil {
return nil, err2.ErrorCmbVerifyFail(err.Error())
}
if len(bizStr) == 0 {
s.recordBody(ctx)
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
var bizContent *v1.CmbOrderRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) QueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryRequest, error) {
bizStr, err := s.Verify(ctx, req)
if err != nil {
return nil, err2.ErrorCmbVerifyFail(err.Error())
}
if len(bizStr) == 0 {
s.recordBody(ctx)
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
var bizContent *v1.CmbQueryRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) ProductQueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryProductRequest, error) {
bizStr, err := s.Verify(ctx, req)
if err != nil {
return nil, err
}
if len(bizStr) == 0 {
s.recordBody(ctx)
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
var bizContent *v1.CmbQueryProductRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) Verify(_ context.Context, req *v1.CmbRequest) (string, error) {
str := cmb.SortStructStr(req)
b, err := s.voucher.Verify(str, req.Sign)
if err != nil {
return "", err2.ErrorCmbVerifyFail(err.Error())
}
if !b {
return "", err2.ErrorCmbVerifyFail("签名验证失败")
}
bizStr, err := s.cmb.Decrypt(req.EncryptBody)
if err != nil {
return "", err2.ErrorCmbBizContentDecryptFail(err.Error())
}
return bizStr, nil
}
func (s *CmbMixRepoImpl) Verify2(_ context.Context, req *v1.CmbRequest) (string, error) {
str := cmb.SortStructStr(req)
b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign)
if err != nil {
return "", err2.ErrorCmbVerifyFail(err.Error())
}
if !b {
return "", err2.ErrorCmbVerifyFail("签名验证失败")
}
bizStr, err := cmb.Decrypt(s.bc.Cmb.Sm2Prk, req.EncryptBody)
if err != nil {
return "", err2.ErrorCmbBizContentDecryptFail(err.Error())
}
return bizStr, nil
}
func (s *CmbMixRepoImpl) GetRequest(_ context.Context, reqBo *bo.CmbRequestBo) (*v1.CmbRequest, error) {
// 用他们的公钥加密
encryptBody, err := s.cmb.Encrypt([]byte(reqBo.BizContent))
if err != nil {
return nil, err
}
req := &v1.CmbRequest{
Mid: s.bc.Cmb.Mid,
Aid: s.bc.Cmb.Aid,
Date: time.Now().Format("20060102150405"),
Random: string(cmb.RandomBytes(16)),
KeyAlias: s.bc.Cmb.KeyAlias,
CmbKeyAlias: s.bc.Cmb.CmbKeyAlias,
EncryptBody: encryptBody,
Sign: "",
}
str := fmt.Sprintf("%s?%s", reqBo.FuncName, cmb.SortStructStr(req))
// 用自己的私钥签名
sing, err := s.voucher.Sign([]byte(str))
if err != nil {
return nil, err
}
req.Sign = sing
return req, nil
}
func (s *CmbMixRepoImpl) GetRequest2(_ context.Context, reqBo *bo.CmbRequestBo) (*v1.CmbRequest, error) {
encryptBody, err := cmb.Encrypt(s.bc.Cmb.CmbSm2Puk, reqBo.BizContent)
if err != nil {
return nil, err
}
req := &v1.CmbRequest{
Mid: s.bc.Cmb.Mid,
Aid: s.bc.Cmb.Aid,
Date: time.Now().Format("20060102150405"),
Random: string(cmb.RandomBytes(16)),
KeyAlias: s.bc.Cmb.KeyAlias,
CmbKeyAlias: s.bc.Cmb.CmbKeyAlias,
EncryptBody: encryptBody,
Sign: "",
}
str := fmt.Sprintf("%s?%s", reqBo.FuncName, cmb.SortStructStr(req))
sing, err := cmb.Sign(s.bc.Cmb.Sm2Prk, str)
if err != nil {
return nil, err
}
req.Sign = sing
return req, nil
}
func (s *CmbMixRepoImpl) GetMockRequest(_ context.Context, bizContent string) (*v1.CmbRequest, error) {
if len(s.bc.Cmb.Sm2Puk) == 0 {
return nil, errors.New("mock sm2 puk is empty")
}
if len(s.bc.Cmb.CmbSm2Pik) == 0 {
return nil, errors.New("mock cmb sm2 pik is empty")
}
// 用他们的公钥加密
encryptBody, err := s.cmb.Encrypt([]byte(bizContent))
if err != nil {
return nil, err
}
req := &v1.CmbRequest{
Mid: s.bc.Cmb.Mid,
Aid: s.bc.Cmb.Aid,
Date: time.Now().Format("20060102150405"),
Random: string(cmb.RandomBytes(16)),
KeyAlias: s.bc.Cmb.KeyAlias,
CmbKeyAlias: s.bc.Cmb.CmbKeyAlias,
EncryptBody: encryptBody,
Sign: "",
}
// 用我们的私钥签名
sign, err := s.voucher.Sign([]byte(cmb.SortStructStr(req)))
if err != nil {
return nil, err
}
req.Sign = sign
return req, nil
}
func (s *CmbMixRepoImpl) VerifyResponse(_ context.Context, req *v1.CmbReply) error {
str := cmb.SortStructStr(req)
// 用他们的公钥验签
b, err := s.cmb.Verify(str, req.Sign)
if err != nil {
return err
}
if !b {
return errors.New("签名验证失败")
}
return nil
}
func (s *CmbMixRepoImpl) VerifyResponse2(_ context.Context, req *v1.CmbReply) error {
str := cmb.SortStructStr(req)
b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign)
if err != nil {
return err
}
if !b {
return errors.New("签名验证失败")
}
return nil
}
func (s *CmbMixRepoImpl) GetResponse(_ context.Context, reqBo *bo.CmbResponseBo) (*v1.CmbReply, error) {
reply := &v1.CmbReply{
RespCode: reqBo.RespCode,
RespMsg: reqBo.RespMsg,
Date: time.Now().Format("20060102150405"),
KeyAlias: s.bc.Cmb.KeyAlias,
CmbKeyAlias: s.bc.Cmb.CmbKeyAlias,
EncryptBody: "",
Sign: "",
}
if len(reqBo.BizContent) > 0 {
encryptBody, err := s.cmb.Encrypt([]byte(reqBo.BizContent))
if err != nil {
return nil, err
}
reply.EncryptBody = encryptBody
}
sign, err := s.voucher.Sign([]byte(cmb.SortStructStr(reply)))
if err != nil {
return nil, err
}
reply.Sign = sign
return reply, nil
}
func (s *CmbMixRepoImpl) GetResponse2(_ context.Context, reqBo *bo.CmbResponseBo) (*v1.CmbReply, error) {
reply := &v1.CmbReply{
RespCode: reqBo.RespCode,
RespMsg: reqBo.RespMsg,
Date: time.Now().Format("20060102150405"),
KeyAlias: s.bc.Cmb.KeyAlias,
CmbKeyAlias: s.bc.Cmb.CmbKeyAlias,
EncryptBody: "",
Sign: "",
}
if len(reqBo.BizContent) > 0 {
encryptBody, err := cmb.Encrypt(s.bc.Cmb.CmbSm2Puk, reqBo.BizContent)
if err != nil {
return nil, err
}
reply.EncryptBody = encryptBody
}
sign, err := cmb.Sign(s.bc.Cmb.Sm2Prk, cmb.SortStructStr(reply))
if err != nil {
return nil, err
}
reply.Sign = sign
return reply, nil
}
func (s *CmbMixRepoImpl) Request(ctx context.Context, req *v1.CmbRequest, uri string) (*v1.CmbReply, error) {
kvRows := helper.SortStructFieldsByKey(req)
uv := url.Values{}
for _, kv := range kvRows {
uv.Set(kv.Key, fmt.Sprintf("%v", kv.Value))
}
h := http.Header{
"Content-Type": []string{"application/x-www-form-urlencoded"},
}
r := uri + "?" + uv.Encode()
_, bodyBytes, err := request.Post(ctx, r, nil, request.WithHeaders(h))
if err != nil {
log.Errorf("请求掌上生活报错,url=%s,err=%v", r, err)
return nil, err
}
log.Warnf("请求掌上生活响应结果,url:%s,bodyBytes:%s", r, string(bodyBytes))
var response *v1.CmbReply
if err = json.Unmarshal(bodyBytes, &response); err != nil {
log.Errorf("请求掌上生活返回数据解析报错,err:%s", string(bodyBytes), err.Error())
return nil, err
}
if response.RespCode != vo.CmbResponseStatusSuccess.GetValue() {
log.Errorf("请求掌上生活返回报错,err:%s", r, response.RespMsg)
return nil, fmt.Errorf(response.RespMsg)
}
return response, nil
}
func (s *CmbMixRepoImpl) Decrypt(_ context.Context, encryptBody string) (string, error) {
if len(s.bc.Cmb.CmbSm2Pik) == 0 {
return "", errors.New("mock CmbSm2Pik is empty")
}
return s.cmb.Decrypt(encryptBody)
}
func (s *CmbMixRepoImpl) Decrypt2(_ context.Context, encryptBody string) (string, error) {
if len(s.bc.Cmb.CmbSm2Pik) == 0 {
return "", errors.New("mock CmbSm2Pik is empty")
}
return cmb.Decrypt(s.bc.Cmb.CmbSm2Pik, encryptBody)
}