2021-06-30 02:12:05 +00:00
|
|
|
|
package wxpay
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2021-11-01 03:32:23 +00:00
|
|
|
|
"context"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
"crypto"
|
2021-06-30 02:12:05 +00:00
|
|
|
|
"crypto/md5"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/rsa"
|
2022-08-12 02:41:33 +00:00
|
|
|
|
"crypto/tls"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
"crypto/x509"
|
|
|
|
|
b64 "encoding/base64"
|
2021-06-30 02:12:05 +00:00
|
|
|
|
"encoding/json"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
"encoding/pem"
|
2021-06-30 02:12:05 +00:00
|
|
|
|
"encoding/xml"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
2021-11-01 03:32:23 +00:00
|
|
|
|
"github.com/codinl/go-logger"
|
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/certificates"
|
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
2021-12-25 08:38:30 +00:00
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
2021-11-01 03:32:23 +00:00
|
|
|
|
wechatpayutils "github.com/wechatpay-apiv3/wechatpay-go/utils"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
2022-08-12 02:41:33 +00:00
|
|
|
|
mathrand "math/rand"
|
2021-06-30 02:12:05 +00:00
|
|
|
|
"mh-server/config"
|
|
|
|
|
"mh-server/lib/utils"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
"net/http"
|
|
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
//clientIp = "120.229.60.77"
|
|
|
|
|
clientIp = "39.108.188.218"
|
|
|
|
|
domain = "switch.deovo.com:8001"
|
|
|
|
|
//wxPayNotifyUrl = "api/v1/wxpay/notice"
|
|
|
|
|
wxPayNotifyUrl = "/api/v1/wxpay/notice"
|
|
|
|
|
|
2022-03-26 03:25:15 +00:00
|
|
|
|
WxPayMember = "member_pay" // 会员
|
|
|
|
|
WxPayRentCard = "rent_card_pay" // 租卡
|
|
|
|
|
WxPayDeposit = "deposit_pay" // 押金
|
2022-05-28 06:18:27 +00:00
|
|
|
|
WxPayBuyGoods = "buy_goods" // 购买商品
|
2022-03-26 03:25:15 +00:00
|
|
|
|
WxPayUpgradeMember = "upgrade_member" // 多级会员
|
|
|
|
|
WxPayMemberExpireDelay = "member_expire_delay" // 会员过期滞纳金
|
2022-06-03 03:30:03 +00:00
|
|
|
|
WxPayShareCardRetrieve = "share_card_retrieve" // 收回卡
|
2022-09-29 07:49:16 +00:00
|
|
|
|
WxPayPostagePackage = "postage_package" // 运费包
|
2021-06-30 02:12:05 +00:00
|
|
|
|
|
2022-05-28 06:18:27 +00:00
|
|
|
|
//WxPayExchangeGoods = "exchange_goods" // 兑换商品
|
2022-04-21 09:03:33 +00:00
|
|
|
|
//NotifyUrl = "https://switch.deovo.com:8001/api/v1/wxpay/notice" // 数据库配置 生产
|
|
|
|
|
//NotifyUrl = "https://dev.switch.deovo.com:8004/api/v1/wxpay/notice" // 测试
|
2021-11-01 03:32:23 +00:00
|
|
|
|
|
2021-12-25 08:38:30 +00:00
|
|
|
|
wxPayOrderRefundsUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
HmPayMerchantId = "664403000030115"
|
|
|
|
|
HmWxSubMerchantId = "546017470"
|
|
|
|
|
//HmPayUnifiedOrderUrl = "https://hmpay.sandpay.com.cn/gateway/api"
|
2022-11-30 01:43:36 +00:00
|
|
|
|
HmPayApiUrl = "https://hmpay.sandpay.com.cn/gateway/api"
|
2021-06-30 02:12:05 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//web 微信支付
|
2022-04-25 05:59:56 +00:00
|
|
|
|
func WebPay(orderId string, totalFee uint32, openId, profitSharing, attach, notifyUrl string) (*Sextuple, error) {
|
2021-06-30 02:12:05 +00:00
|
|
|
|
now := time.Now().Local()
|
|
|
|
|
strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
|
|
|
|
|
nonce := utils.GenRandStr(NonceStringLength)
|
|
|
|
|
|
2022-04-25 05:59:56 +00:00
|
|
|
|
//configInfo, err := model.PayConfigInfo()
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return nil, err
|
|
|
|
|
//}
|
|
|
|
|
//if configInfo.NotifyUrl == "" {
|
|
|
|
|
// logger.Error("NotifyUrl is null")
|
|
|
|
|
// return nil, errors.New("NotifyUrl is null")
|
|
|
|
|
//}
|
|
|
|
|
if notifyUrl == "" {
|
2021-12-25 08:38:30 +00:00
|
|
|
|
logger.Error("NotifyUrl is null")
|
|
|
|
|
return nil, errors.New("NotifyUrl is null")
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
logger.Info("MchId:", config.AppConfig.WxMchID)
|
|
|
|
|
logger.Info("AppId:", config.AppConfig.WxAppId)
|
|
|
|
|
logger.Info("MchSecret:", config.AppConfig.WxMchSecret)
|
|
|
|
|
|
|
|
|
|
unifiedOrderReq := UnifiedOrderReq{
|
|
|
|
|
DeviceInfo: "WEB",
|
|
|
|
|
NonceStr: nonce,
|
|
|
|
|
Sign: "",
|
|
|
|
|
SignType: "MD5",
|
|
|
|
|
Body: "创建订单",
|
|
|
|
|
OutTradeNo: orderId,
|
|
|
|
|
FeeType: "CNY",
|
|
|
|
|
TotalFee: strconv.Itoa(int(totalFee)),
|
|
|
|
|
//SpbillCreateIp: config.AppConfig.IP,
|
|
|
|
|
SpbillCreateIp: clientIp,
|
|
|
|
|
//NotifyUrl: "https://" + config.AppConfig.Domain + config.AppConfig.WxPayNotifyUrl,
|
|
|
|
|
//NotifyUrl: "https://" + domain + wxPayNotifyUrl,
|
2022-04-25 05:59:56 +00:00
|
|
|
|
//NotifyUrl: configInfo.NotifyUrl,
|
|
|
|
|
NotifyUrl: notifyUrl,
|
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
TradeType: "JSAPI",
|
|
|
|
|
MchId: config.AppConfig.WxMchID,
|
|
|
|
|
AppId: config.AppConfig.WxAppId,
|
|
|
|
|
OpenId: openId,
|
|
|
|
|
TimeStart: strTime,
|
|
|
|
|
ProfitSharing: profitSharing,
|
|
|
|
|
Attach: attach,
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-01 03:32:23 +00:00
|
|
|
|
fmt.Println("OutTradeNo:", unifiedOrderReq.OutTradeNo)
|
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
m, err := struct2Map(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mJson, _ := json.MarshalIndent(&m, "", " ")
|
|
|
|
|
//fmt.Println("mJson:", string(mJson))
|
|
|
|
|
|
|
|
|
|
sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.Sign = strings.ToUpper(sign)
|
|
|
|
|
|
|
|
|
|
//unifiedOrderReqJson, _ := json.Marshal(&unifiedOrderReq)
|
|
|
|
|
//fmt.Println("unifiedOrderReqJson:", string(unifiedOrderReqJson))
|
|
|
|
|
|
|
|
|
|
unifiedOrderResp, err := WxUnifiedOrder(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("WxUnifiedOrder unified order error %#v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sextuple Sextuple
|
|
|
|
|
sextuple.NonceStr = unifiedOrderResp.NonceStr
|
|
|
|
|
sextuple.AppId = unifiedOrderResp.AppId
|
|
|
|
|
sextuple.Timestamp = fmt.Sprintf("%d", time.Now().Unix())
|
|
|
|
|
sextuple.Package = "prepay_id=" + unifiedOrderResp.PrepayId
|
|
|
|
|
sextuple.SignType = "MD5"
|
|
|
|
|
//logger.Debugf("unified order sextuple: %#v", sextuple)
|
|
|
|
|
|
|
|
|
|
m, err = struct2Map(sextuple)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("struct to map error %#v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sextuple.PaySign, err = GenWxPaySign(m, config.AppConfig.WxMchSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("GenWxPaySign gen response sign error: %#v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &sextuple, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
NonceStringLength = 32
|
|
|
|
|
UnifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
//根据调用微信统一支付接口返回数据组装五元组
|
|
|
|
|
Sextuple struct {
|
|
|
|
|
AppId string `json:"appId"`
|
|
|
|
|
NonceStr string `json:"nonceStr,omitempty"`
|
|
|
|
|
Timestamp string `json:"timeStamp,omitempty"`
|
|
|
|
|
Package string `json:"package,omitempty"`
|
|
|
|
|
SignType string `json:"signType,omitempty"`
|
|
|
|
|
PaySign string `json:"paySign,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UnifiedOrderReq struct {
|
|
|
|
|
XMLName xml.Name `xml:"xml"` //xml标签
|
|
|
|
|
AppId string `xml:"appid" json:"appid"` //微信分配的小程序ID,必须
|
|
|
|
|
MchId string `xml:"mch_id" json:"mch_id"` //微信支付分配的商户号,必须
|
|
|
|
|
DeviceInfo string `xml:"device_info" json:"device_info"` //微信支付填"WEB",必须
|
|
|
|
|
NonceStr string `xml:"nonce_str" json:"nonce_str"` //随机字符串,必须
|
|
|
|
|
Sign string `xml:"sign" json:"sign"` //签名,必须
|
|
|
|
|
SignType string `xml:"sign_type" json:"sign_type"` //"HMAC-SHA256"或者"MD5",非必须,默认MD5
|
|
|
|
|
Body string `xml:"body" json:"body"` //商品简单描述,必须
|
|
|
|
|
Detail string `xml:"detail,omitempty" json:"detail,omitempty"` //商品详细列表,使用json格式
|
|
|
|
|
Attach string `xml:"attach" json:"attach"` //附加数据,如"贵阳分店",非必须
|
|
|
|
|
OutTradeNo string `xml:"out_trade_no" json:"out_trade_no"` //CRS订单号,必须
|
|
|
|
|
FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"` //默认人民币:CNY,非必须
|
|
|
|
|
TotalFee string `xml:"total_fee" json:"total_fee"` //订单金额,单位分,必须
|
|
|
|
|
SpbillCreateIp string `xml:"spbill_create_ip" json:"spbill_create_ip"` //支付提交客户端IP,如“123.123.123.123”,必须
|
|
|
|
|
TimeStart string `xml:"time_start,omitempty" json:"time_start,omitempty"` //订单生成时间,格式为yyyyMMddHHmmss,如20170324094700,非必须
|
|
|
|
|
TimeExpire string `xml:"time_expire,omitempty" json:"time_expire,omitempty"` //订单结束时间,格式同上,非必须
|
|
|
|
|
GoodsTag string `xml:"goods_tag,omitempty" json:"goods_tag,omitempty"` //商品标记,代金券或立减优惠功能的参数,非必须
|
|
|
|
|
NotifyUrl string `xml:"notify_url" json:"notify_url"` //接收微信支付异步通知回调地址,不能携带参数,必须
|
|
|
|
|
TradeType string `xml:"trade_type" json:"trade_type"` //交易类型,小程序写"JSAPI",必须
|
|
|
|
|
LimitPay string `xml:"limit_pay,omitempty" json:"limit_pay,omitempty"` //限制某种支付方式,非必须
|
|
|
|
|
OpenId string `xml:"openid" json:"openid"` //微信用户唯一标识,必须
|
|
|
|
|
ProfitSharing string `xml:"profit_sharing" json:"profit_sharing"` //是否需要分账
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZFWechatUnifiedOrderReq struct {
|
|
|
|
|
XMLName xml.Name `xml:"xml"` //xml标签
|
|
|
|
|
AppId string `xml:"appid" json:"appid"` //微信分配的小程序ID,必须
|
|
|
|
|
MchId string `xml:"mch_id" json:"mch_id"` //微信支付分配的商户号,必须
|
|
|
|
|
NonceStr string `xml:"nonce_str" json:"nonce_str"` //随机字符串,必须
|
|
|
|
|
Sign string `xml:"sign" json:"sign"` //签名,必须
|
|
|
|
|
Body string `xml:"body" json:"body"` //商品简单描述,必须
|
|
|
|
|
OutTradeNo string `xml:"out_trade_no" json:"out_trade_no"` //CRS订单号,必须
|
|
|
|
|
TotalFee string `xml:"total_fee" json:"total_fee"` //订单金额,单位分,必须
|
|
|
|
|
SpbillCreateIp string `xml:"spbill_create_ip" json:"spbill_create_ip"` //支付提交客户端IP,如“123.123.123.123”,必须
|
|
|
|
|
NotifyUrl string `xml:"notify_url" json:"notify_url"` //接收微信支付异步通知回调地址,不能携带参数,必须
|
|
|
|
|
TradeType string `xml:"trade_type" json:"trade_type"` //交易类型,小程序写"JSAPI",必须
|
|
|
|
|
OpenId string `xml:"openid" json:"openid"` //微信用户唯一标识,必须
|
|
|
|
|
Attach string `xml:"attach" json:"attach"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UnifiedOrderResp struct {
|
|
|
|
|
ReturnCode string `xml:"return_code"`
|
|
|
|
|
ReturnMsg string `xml:"return_msg"`
|
|
|
|
|
AppId string `xml:"appid"`
|
|
|
|
|
MchId string `xml:"mch_id"`
|
|
|
|
|
DeviceInfo string `xml:"device_info"`
|
|
|
|
|
NonceStr string `xml:"nonce_str"`
|
|
|
|
|
Sign string `xml:"sign"`
|
|
|
|
|
ResultCode string `xml:"result_code"`
|
|
|
|
|
ErrCode string `xml:"err_code"`
|
|
|
|
|
ErrCodeDes string `xml:"err_code_des"`
|
|
|
|
|
TradeType string `xml:"trade_type"`
|
|
|
|
|
PrepayId string `xml:"prepay_id"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WechatNotifyInfo struct {
|
|
|
|
|
ReturnCode string `xml:"return_code,CDATA" json:"return_code"`
|
|
|
|
|
ReturnMsg string `xml:"return_msg,CDATA" json:"return_msg"`
|
|
|
|
|
Appid string `xml:"appid,CDATA" json:"appid"`
|
|
|
|
|
MchId string `xml:"mch_id,CDATA" json:"mch_id"`
|
|
|
|
|
DeviceInfo string `xml:"device_info,CDATA" json:"device_info"`
|
|
|
|
|
NonceStr string `xml:"nonce_str,CDATA" json:"nonce_str"`
|
|
|
|
|
Sign string `xml:"sign,CDATA" json:"sign"` // 默认MD5
|
|
|
|
|
SignType string `xml:"sign_type,CDATA" json:"sign_type"` //可选
|
|
|
|
|
ResultCode string `xml:"result_code,CDATA" json:"result_code"`
|
|
|
|
|
ErrCode string `xml:"err_code,CDATA" json:"err_code"`
|
|
|
|
|
ErrCodeDes string `xml:"err_code_des,CDATA" json:"err_code_des"`
|
|
|
|
|
Openid string `xml:"openid,CDATA" json:"openid"`
|
|
|
|
|
IsSubscribe string `xml:"is_subscribe,CDATA" json:"is_subscribe"`
|
|
|
|
|
TradeType string `xml:"trade_type,CDATA" json:"trade_type"`
|
|
|
|
|
BankType string `xml:"bank_type,CDATA" json:"bank_type"`
|
|
|
|
|
TotalFee uint `xml:"total_fee,CDATA" json:"total_fee"`
|
|
|
|
|
SettlementTotalFee uint `xml:"settlement_total_fee" json:"settlement_total_fee"`
|
|
|
|
|
FeeType string `xml:"fee_type,CDATA" json:"fee_type"`
|
|
|
|
|
CashFee uint `xml:"cash_fee,CDATA" json:"cash_fee"`
|
|
|
|
|
CashFeeType string `xml:"cash_fee_type,CDATA" json:"cash_fee_type"`
|
2022-01-15 13:10:00 +00:00
|
|
|
|
|
2022-01-15 13:21:05 +00:00
|
|
|
|
CouponFee uint `xml:"coupon_fee,CDATA" json:"coupon_fee"`
|
|
|
|
|
CouponCount uint `xml:"coupon_count,CDATA" json:"coupon_count"`
|
2022-05-28 07:24:17 +00:00
|
|
|
|
CouponType0 uint `xml:"coupon_type_0,CDATA" json:"coupon_type_0"`
|
|
|
|
|
CouponId0 string `xml:"coupon_id_0,CDATA" json:"coupon_id_0"`
|
|
|
|
|
CouponFee0 uint `xml:"coupon_fee_0,CDATA" json:"coupon_fee_0"`
|
2022-01-15 13:10:00 +00:00
|
|
|
|
|
2022-01-15 13:21:05 +00:00
|
|
|
|
CouponFee1 uint `xml:"coupon_fee_1,CDATA" json:"coupon_fee_1"`
|
|
|
|
|
CouponId1 string `xml:"coupon_id_1,CDATA" json:"coupon_id_1"`
|
2022-01-29 02:21:38 +00:00
|
|
|
|
CouponFee2 uint `xml:"coupon_fee_2,CDATA" json:"coupon_fee_2"`
|
2022-01-15 13:21:05 +00:00
|
|
|
|
CouponId2 string `xml:"coupon_id_2,CDATA" json:"coupon_id_2"`
|
2022-01-29 02:21:38 +00:00
|
|
|
|
CouponFee3 uint `xml:"coupon_fee_3,CDATA" json:"coupon_fee_3"`
|
2022-01-15 13:21:05 +00:00
|
|
|
|
CouponId3 string `xml:"coupon_id_3,CDATA" json:"coupon_id_3"`
|
2022-01-29 02:21:38 +00:00
|
|
|
|
CouponFee4 uint `xml:"coupon_fee_4,CDATA" json:"coupon_fee_4"`
|
2022-01-15 13:21:05 +00:00
|
|
|
|
CouponId4 string `xml:"coupon_id_4,CDATA" json:"coupon_id_4"`
|
2022-05-28 07:24:17 +00:00
|
|
|
|
CouponFee5 uint `xml:"coupon_fee_5,CDATA" json:"coupon_fee_5"`
|
|
|
|
|
CouponId5 string `xml:"coupon_id_5,CDATA" json:"coupon_id_5"`
|
2022-01-15 13:21:05 +00:00
|
|
|
|
|
|
|
|
|
TransactionId string `xml:"transaction_id,CDATA" json:"transaction_id"`
|
|
|
|
|
OutTradeNo string `xml:"out_trade_no,CDATA" json:"out_trade_no"`
|
|
|
|
|
Attach string `xml:"attach,CDATA" json:"attach"`
|
|
|
|
|
TimeEnd string `xml:"time_end,CDATA" json:"time_end"`
|
2021-06-30 02:12:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WechatNotify struct {
|
|
|
|
|
ReturnCode string `xml:"return_code"`
|
|
|
|
|
ReturnMsg string `xml:"return_msg"` //签名失败 或者 参数格式校验错误
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NotifyResponseObject struct {
|
|
|
|
|
XMLName xml.Name `xml:"xml"`
|
|
|
|
|
WechatNotify
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AppWxPayRet struct {
|
|
|
|
|
AppId string `json:"appid,omitempty"`
|
|
|
|
|
PartnerId string `json:"partnerid,omitempty"`
|
|
|
|
|
PrepayId string `json:"prepayid,omitempty"`
|
|
|
|
|
Package string `json:"package,omitempty"`
|
|
|
|
|
NonceStr string `json:"noncestr,omitempty"`
|
|
|
|
|
Timestamp string `json:"timestamp,omitempty"`
|
|
|
|
|
Sign string `json:"sign,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2022-01-15 13:21:05 +00:00
|
|
|
|
type T struct {
|
|
|
|
|
CouponFee0 string `json:"coupon_fee_0"`
|
|
|
|
|
CouponFee1 string `json:"coupon_fee_1"`
|
|
|
|
|
CouponFee2 string `json:"coupon_fee_2"`
|
|
|
|
|
CouponFee3 string `json:"coupon_fee_3"`
|
|
|
|
|
CouponId0 string `json:"coupon_id_0"`
|
|
|
|
|
CouponId1 string `json:"coupon_id_1"`
|
|
|
|
|
CouponId2 string `json:"coupon_id_2"`
|
|
|
|
|
CouponId3 string `json:"coupon_id_3"`
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 07:12:09 +00:00
|
|
|
|
const (
|
|
|
|
|
DateTimeFormat = "2006-01-02"
|
|
|
|
|
TimeFormat = "2006-01-02 15:04:05"
|
|
|
|
|
)
|
|
|
|
|
|
2022-01-15 13:10:00 +00:00
|
|
|
|
//type T struct {
|
|
|
|
|
// Xml struct {
|
|
|
|
|
// Appid string `json:"appid"`
|
|
|
|
|
// Attach string `json:"attach"`
|
|
|
|
|
// BankType string `json:"bank_type"`
|
|
|
|
|
// CashFee string `json:"cash_fee"`
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// CouponCount string `json:"coupon_count"`
|
|
|
|
|
// CouponFee string `json:"coupon_fee"`
|
|
|
|
|
// CouponFee0 string `json:"coupon_fee_0"`
|
|
|
|
|
// CouponFee1 string `json:"coupon_fee_1"`
|
|
|
|
|
// CouponId0 string `json:"coupon_id_0"`
|
|
|
|
|
// CouponId1 string `json:"coupon_id_1"`
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// DeviceInfo string `json:"device_info"`
|
|
|
|
|
// FeeType string `json:"fee_type"`
|
|
|
|
|
// IsSubscribe string `json:"is_subscribe"`
|
|
|
|
|
// MchId string `json:"mch_id"`
|
|
|
|
|
// NonceStr string `json:"nonce_str"`
|
|
|
|
|
// Openid string `json:"openid"`
|
|
|
|
|
// OutTradeNo string `json:"out_trade_no"`
|
|
|
|
|
// ResultCode string `json:"result_code"`
|
|
|
|
|
// ReturnCode string `json:"return_code"`
|
|
|
|
|
// Sign string `json:"sign"`
|
|
|
|
|
// TimeEnd string `json:"time_end"`
|
|
|
|
|
// TotalFee string `json:"total_fee"`
|
|
|
|
|
// TradeType string `json:"trade_type"`
|
|
|
|
|
// TransactionId string `json:"transaction_id"`
|
|
|
|
|
// } `json:"xml"`
|
|
|
|
|
//}
|
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
////app 微信支付
|
|
|
|
|
////totalFee 单位是分
|
|
|
|
|
//func AppPay(totalFee int, openId string) (*AppWxPayRet, string, error) {
|
|
|
|
|
// now := time.Now()
|
|
|
|
|
// strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
|
|
|
|
|
// tradeNO := strTime + utils.RandomNumString(100000, 999999)
|
|
|
|
|
// nonce := utils.GenRandStr(NonceStringLength)
|
|
|
|
|
// unifiedOrderReq := UnifiedOrderReq{
|
|
|
|
|
// DeviceInfo: "WEB",
|
|
|
|
|
// NonceStr: nonce,
|
|
|
|
|
// Sign: "",
|
|
|
|
|
// SignType: "MD5",
|
|
|
|
|
// Body: "升级会员",
|
|
|
|
|
// OutTradeNo: tradeNO,
|
|
|
|
|
// FeeType: "CNY",
|
|
|
|
|
// TotalFee: strconv.Itoa(int(totalFee)),
|
|
|
|
|
// //SpbillCreateIp: config.AppConfig.IP,
|
|
|
|
|
// SpbillCreateIp: clientIp,
|
|
|
|
|
// //NotifyUrl: config.AppConfig.WxPayNotifyUrl,
|
|
|
|
|
// TradeType: "APP",
|
|
|
|
|
// AppId: "WechatAppId",
|
|
|
|
|
// MchId: "WechatMchId",
|
|
|
|
|
// OpenId: openId,
|
|
|
|
|
// TimeStart: strTime,
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// //生成签名
|
|
|
|
|
// m, err := struct2Map(unifiedOrderReq)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return nil, "", err
|
|
|
|
|
// }
|
|
|
|
|
// sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return nil, "", err
|
|
|
|
|
// }
|
|
|
|
|
// unifiedOrderReq.Sign = strings.ToUpper(sign)
|
|
|
|
|
//
|
|
|
|
|
// unifiedOrderResp, err := WxUnifiedOrder(unifiedOrderReq)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Errorf("WxUnifiedOrder unified order error %#v", err)
|
|
|
|
|
// return nil, "", err
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// var payret AppWxPayRet
|
|
|
|
|
// payret.AppId = unifiedOrderResp.AppId
|
|
|
|
|
// payret.PartnerId = unifiedOrderResp.MchId
|
|
|
|
|
// payret.PrepayId = unifiedOrderResp.PrepayId
|
|
|
|
|
// payret.Package = "Sign=WXPay"
|
|
|
|
|
// payret.NonceStr = unifiedOrderResp.NonceStr
|
|
|
|
|
// payret.Timestamp = fmt.Sprintf("%d", time.Now().Unix())
|
|
|
|
|
//
|
|
|
|
|
// m, err = struct2Map(payret)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Errorf("Pay struct to map error %#v", err)
|
|
|
|
|
// return nil, "", err
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// payret.Sign, err = GenWxPaySign(m, config.AppConfig.WxMchSecret)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Errorf("GenWxPaySign gen response sign error: %#v", err)
|
|
|
|
|
// return nil, "", err
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// return &payret, tradeNO, nil
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
func struct2Map(r interface{}) (s map[string]string, err error) {
|
|
|
|
|
var temp map[string]interface{}
|
|
|
|
|
var result = make(map[string]string)
|
|
|
|
|
|
|
|
|
|
bin, err := json.Marshal(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return result, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := json.Unmarshal(bin, &temp); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
for k, v := range temp {
|
|
|
|
|
switch v2 := v.(type) {
|
|
|
|
|
case string:
|
|
|
|
|
result[k] = v2
|
|
|
|
|
case uint, int8, uint8, int, int16, uint16, int32, uint32, int64, uint64:
|
2022-11-18 07:12:09 +00:00
|
|
|
|
result[k] = fmt.Sprintf("%d", v)
|
2021-06-30 02:12:05 +00:00
|
|
|
|
case float32, float64:
|
2022-11-18 07:12:09 +00:00
|
|
|
|
result[k] = fmt.Sprintf("%.02f", v)
|
2021-06-30 02:12:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GenWxPaySign(m map[string]string, payKey string) (string, error) {
|
|
|
|
|
delete(m, "sign")
|
|
|
|
|
var signData []string
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
if k == "openid" {
|
|
|
|
|
fmt.Println(k, ":", v)
|
|
|
|
|
}
|
|
|
|
|
if v != "" && v != "0" {
|
|
|
|
|
signData = append(signData, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
signDataJson, _ := json.MarshalIndent(&signData, "", " ")
|
|
|
|
|
fmt.Println("signDataJson1", string(signDataJson))
|
|
|
|
|
|
|
|
|
|
sort.Strings(signData)
|
|
|
|
|
|
|
|
|
|
signDataJson2, _ := json.MarshalIndent(&signData, "", " ")
|
|
|
|
|
fmt.Println("signDataJson2", string(signDataJson2))
|
|
|
|
|
|
|
|
|
|
signStr := strings.Join(signData, "&")
|
|
|
|
|
signStr = signStr + "&key=" + payKey
|
2021-11-01 03:32:23 +00:00
|
|
|
|
logger.Info("签字符串1 :", signStr)
|
2021-06-30 02:12:05 +00:00
|
|
|
|
c := md5.New()
|
|
|
|
|
_, err := c.Write([]byte(signStr))
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signByte := c.Sum(nil)
|
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%x", signByte), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func WxUnifiedOrder(r UnifiedOrderReq) (UnifiedOrderResp, error) {
|
|
|
|
|
var payResp UnifiedOrderResp
|
|
|
|
|
|
|
|
|
|
data, err := xml.Marshal(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return payResp, err
|
|
|
|
|
}
|
|
|
|
|
//logger.Error(" xml data: ", string(data))
|
|
|
|
|
|
|
|
|
|
//fmt.Println("xml:", string(data))
|
|
|
|
|
logger.Error("xml:", string(data))
|
|
|
|
|
client := http.Client{}
|
|
|
|
|
req, err := http.NewRequest("POST", UnifiedOrderUrl, bytes.NewBuffer(data))
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return payResp, err
|
|
|
|
|
}
|
|
|
|
|
req.Header.Set("Content-Type", "application/xml; charset=utf-8")
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return payResp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//fmt.Println("err:", err)
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return payResp, err
|
|
|
|
|
}
|
|
|
|
|
//fmt.Println("err:", err)
|
|
|
|
|
fmt.Println("body:", string(body))
|
|
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
err = xml.Unmarshal(body, &payResp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return payResp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if payResp.ReturnCode != "SUCCESS" {
|
|
|
|
|
return payResp, errors.New(payResp.ReturnMsg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return payResp, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-01 03:32:23 +00:00
|
|
|
|
func WxPayTransactionOrderClose(outTradeNo, mchid string) error {
|
|
|
|
|
// url := fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close", outTradeNo)
|
|
|
|
|
// para := map[string]interface{}{
|
|
|
|
|
// "mchid": mchid,
|
|
|
|
|
// }
|
|
|
|
|
// data, err := json.Marshal(para)
|
|
|
|
|
// logger.Error("json:", string(data))
|
|
|
|
|
// client := http.Client{}
|
|
|
|
|
// req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
// req.Header.Set("Accept", "application/json")
|
|
|
|
|
//// Content-Type: application/json
|
|
|
|
|
// resp, err := client.Do(req)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// //fmt.Println("err:", err)
|
|
|
|
|
// body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// logger.Error(err)
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// //fmt.Println("err:", err)
|
|
|
|
|
// fmt.Println("body:", string(body))
|
|
|
|
|
//
|
|
|
|
|
// defer resp.Body.Close()
|
|
|
|
|
var (
|
|
|
|
|
mchID string = "1609877389" // 商户号
|
|
|
|
|
mchCertificateSerialNumber string = "7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF" // 商户证书序列号
|
|
|
|
|
mchAPIv3Key string = "DeovoMingHuiRengTianTang45675123" // 商户APIv3密钥
|
|
|
|
|
)
|
|
|
|
|
// 微信商户
|
|
|
|
|
// 商户ID:1609877389
|
|
|
|
|
// 操作密码:456755
|
|
|
|
|
// 密钥API:DeovoMingHuiRengTianTang45675456
|
|
|
|
|
//密钥APIv3: DeovoMingHuiRengTianTang45675123
|
|
|
|
|
// 证书序列号:7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF
|
|
|
|
|
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
|
|
|
|
mchPrivateKey, err := wechatpayutils.LoadPrivateKeyWithPath("/Users/li/mh/mh_server/pack/configs/merchant/apiclient_key.pem")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal("load merchant private key error")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
// 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
|
|
|
|
|
opts := []core.ClientOption{
|
|
|
|
|
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
|
|
|
|
|
}
|
|
|
|
|
client, err := core.NewClient(ctx, opts...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("new wechat pay client err:%s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发送请求,以下载微信支付平台证书为例
|
|
|
|
|
// https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml
|
|
|
|
|
svc := certificates.CertificatesApiService{Client: client}
|
|
|
|
|
resp, result, err := svc.DownloadCertificates(ctx)
|
|
|
|
|
log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
|
|
|
|
|
|
|
|
|
|
svcClient := jsapi.JsapiApiService{Client: client}
|
|
|
|
|
apiResult, err := svcClient.CloseOrder(ctx, jsapi.CloseOrderRequest{
|
|
|
|
|
OutTradeNo: &outTradeNo,
|
|
|
|
|
Mchid: &mchid,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
2021-12-25 08:38:30 +00:00
|
|
|
|
fmt.Println("err:", err)
|
2021-11-01 03:32:23 +00:00
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("StatusCode:", (*apiResult).Response.StatusCode)
|
|
|
|
|
//bodyCloseOrder,_ := ioutil.ReadAll((*apiResult.Response.Body))
|
|
|
|
|
fmt.Println("apiResult:", (*apiResult).Response.StatusCode)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 02:12:05 +00:00
|
|
|
|
func PayNotifyHandle(notify WechatNotifyInfo) (string, error) {
|
|
|
|
|
m, err := struct2Map(notify)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err.Error())
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err.Error())
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sign = strings.ToUpper(sign)
|
|
|
|
|
logger.Error("微信推送支付通知 sign : payKey", sign, config.AppConfig.WxMchSecret)
|
|
|
|
|
return sign, err
|
|
|
|
|
}
|
2021-12-25 08:38:30 +00:00
|
|
|
|
|
|
|
|
|
func TransactionOrderRefund(orderRefund OrderRefund) error {
|
|
|
|
|
var (
|
|
|
|
|
mchID string = "1609877389" // 商户号
|
|
|
|
|
mchCertificateSerialNumber string = "7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF" // 商户证书序列号
|
|
|
|
|
mchAPIv3Key string = "DeovoMingHuiRengTianTang45675123" // 商户APIv3密钥
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
|
|
|
|
mchPrivateKey, err := wechatpayutils.LoadPrivateKeyWithPath("./configs/merchant/apiclient_key.pem")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Print("load merchant private key error")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
// 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
|
|
|
|
|
opts := []core.ClientOption{
|
|
|
|
|
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
|
|
|
|
|
}
|
|
|
|
|
client, err := core.NewClient(ctx, opts...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("new wechat pay client err:%s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
svc := refunddomestic.RefundsApiService{Client: client}
|
|
|
|
|
resp, result, err := svc.Create(ctx,
|
|
|
|
|
refunddomestic.CreateRequest{
|
|
|
|
|
OutTradeNo: core.String(orderRefund.OutTradeNo),
|
|
|
|
|
OutRefundNo: core.String(orderRefund.OutRefundNo),
|
|
|
|
|
Reason: core.String("取消订单"),
|
2022-04-25 05:59:56 +00:00
|
|
|
|
//NotifyUrl: core.String("https://weixin.qq.com/api/v1/wxpay/notice"),
|
|
|
|
|
NotifyUrl: core.String(orderRefund.NotifyUrl),
|
2021-12-25 08:38:30 +00:00
|
|
|
|
Amount: &refunddomestic.AmountReq{
|
|
|
|
|
Currency: core.String("CNY"),
|
|
|
|
|
Refund: core.Int64(int64(orderRefund.Amount.Refund)),
|
|
|
|
|
Total: core.Int64(int64(orderRefund.Amount.Total)),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
// 处理错误
|
|
|
|
|
log.Printf("call Create err:%s", err)
|
|
|
|
|
} else {
|
|
|
|
|
// 处理返回结果
|
|
|
|
|
log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 01:43:36 +00:00
|
|
|
|
type HmRefundBizContent struct {
|
|
|
|
|
OutOrderNo string `json:"out_order_no"`
|
|
|
|
|
RefundAmount float64 `json:"refund_amount"`
|
|
|
|
|
RefundRequestNo string `json:"refund_request_no"` //商户退款请求号
|
|
|
|
|
StoreId string `json:"store_id"`
|
|
|
|
|
//ExtendParams string `json:"extend_params"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func HmRefundTransaction(orderRefund OrderRefund) error {
|
|
|
|
|
now := time.Now().Local()
|
|
|
|
|
//strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(),
|
|
|
|
|
// now.Minute(), now.Second())
|
|
|
|
|
//expireTime := now.Add(time.Hour * 3)
|
|
|
|
|
//strExpireTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", expireTime.Year(), expireTime.Month(),
|
|
|
|
|
// expireTime.Day(), expireTime.Hour(), expireTime.Minute(), expireTime.Second())
|
|
|
|
|
nonce := utils.GenRandStr(NonceStringLength)
|
|
|
|
|
|
|
|
|
|
//if notifyUrl == "" {
|
|
|
|
|
// logger.Error("NotifyUrl is null")
|
|
|
|
|
// return nil, errors.New("NotifyUrl is null")
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
unifiedOrderReq := HmJsPayUnifiedOrderReq{}
|
|
|
|
|
publicPara := HmPayPublicPara{
|
|
|
|
|
AppId: HmPayMerchantId,
|
|
|
|
|
//SubAppId: HmWxSubMerchantId,
|
|
|
|
|
Method: "trade.refund",
|
|
|
|
|
//Charset: "UTF-8",
|
|
|
|
|
SignType: "RSA",
|
|
|
|
|
Sign: "",
|
|
|
|
|
Timestamp: now.Format(TimeFormat),
|
|
|
|
|
Nonce: nonce,
|
|
|
|
|
//Nonce: fmt.Sprintf("%d", time.Now().UnixNano()),
|
|
|
|
|
//Version: "1.0.0",
|
|
|
|
|
//Format: "JSON",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
biz := HmRefundBizContent{
|
|
|
|
|
//OutOrderNo: orderRefund.OutRefundNo,
|
|
|
|
|
OutOrderNo: orderRefund.OutTradeNo,
|
|
|
|
|
RefundAmount: float64(orderRefund.Amount.Refund) / 100,
|
|
|
|
|
//RefundRequestNo: orderRefund.OutTradeNo,
|
|
|
|
|
RefundRequestNo: orderRefund.OutRefundNo,
|
|
|
|
|
StoreId: "100001",
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.HmPayPublicPara = publicPara
|
|
|
|
|
|
|
|
|
|
bizString, err := json.Marshal(&biz)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("marshal biz err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.HmPayPublicPara.BizContent = string(bizString)
|
|
|
|
|
m, err := struct2Map(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mJson, _ := json.MarshalIndent(&m, "", " ")
|
|
|
|
|
//fmt.Println("mJson:", string(mJson))
|
|
|
|
|
|
|
|
|
|
sign, err := GenHmPaySign(m)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.Sign = sign
|
|
|
|
|
|
|
|
|
|
//unifiedOrderReqJson, _ := json.Marshal(&unifiedOrderReq)
|
|
|
|
|
//fmt.Println("unifiedOrderReqJson:", string(unifiedOrderReqJson))
|
|
|
|
|
|
|
|
|
|
unifiedOrderResp, err := HmPayRefundOrder(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("hm pay refund order error %#v", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unifiedOrderRespJson, _ := json.Marshal(&unifiedOrderResp)
|
|
|
|
|
fmt.Println("unifiedOrderRespJson:", string(unifiedOrderRespJson))
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 08:38:30 +00:00
|
|
|
|
func PayOrderRefund(orderRefund OrderRefund) error {
|
|
|
|
|
para, err := json.Marshal(&orderRefund)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
|
req, err := http.NewRequest("POST", wxPayOrderRefundsUrl, bytes.NewBuffer(para))
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//fmt.Println("err:", err)
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
//fmt.Println("err:", err)
|
|
|
|
|
fmt.Println("body:", string(body))
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
fmt.Println("")
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type OrderRefund struct {
|
|
|
|
|
OutTradeNo string `json:"out_trade_no"`
|
|
|
|
|
OutRefundNo string `json:"out_refund_no"`
|
|
|
|
|
NotifyUrl string `json:"notify_url"`
|
|
|
|
|
Amount OrderRefundAmount `json:"amount"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type OrderRefundAmount struct {
|
|
|
|
|
Refund uint32 `json:"refund"`
|
|
|
|
|
Total uint32 `json:"total"`
|
|
|
|
|
Currency string `json:"currency"`
|
|
|
|
|
}
|
2022-08-12 02:41:33 +00:00
|
|
|
|
|
|
|
|
|
func RandomNum(min int64, max int64) int64 {
|
|
|
|
|
r := mathrand.New(mathrand.NewSource(time.Now().UnixNano()))
|
|
|
|
|
num := min + r.Int63n(max-min+1)
|
|
|
|
|
return num
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func RandomNumString(min int64, max int64) string {
|
|
|
|
|
num := RandomNum(min, max)
|
|
|
|
|
return strconv.FormatInt(num, 10)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GenTradeNo() string {
|
|
|
|
|
now := time.Now().Local()
|
|
|
|
|
strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
|
|
|
|
|
tradeNO := strTime + RandomNumString(100000, 999999)
|
|
|
|
|
return tradeNO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
KC_RAND_KIND_NUM = 0 // 纯数字
|
|
|
|
|
KC_RAND_KIND_LOWER = 1 // 小写字母
|
|
|
|
|
KC_RAND_KIND_UPPER = 2 // 大写字母
|
|
|
|
|
KC_RAND_KIND_ALL = 3 // 数字、大小写字母
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 随机字符串
|
|
|
|
|
func randStr(size int, kind int) string {
|
|
|
|
|
ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
|
|
|
|
|
isAll := kind > 2 || kind < 0
|
|
|
|
|
mathrand.Seed(time.Now().UnixNano())
|
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
if isAll {
|
|
|
|
|
ikind = mathrand.Intn(3)
|
|
|
|
|
}
|
|
|
|
|
scope, base := kinds[ikind][0], kinds[ikind][1]
|
|
|
|
|
result[i] = uint8(base + mathrand.Intn(scope))
|
|
|
|
|
}
|
|
|
|
|
return string(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GenRandStr(size int) string {
|
|
|
|
|
if size <= 0 {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return randStr(size, KC_RAND_KIND_ALL)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GenWechatPaySign(m map[string]string, payKey string) (string, error) {
|
|
|
|
|
delete(m, "sign")
|
|
|
|
|
var signData []string
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
if v != "" && v != "0" {
|
|
|
|
|
signData = append(signData, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sort.Strings(signData)
|
|
|
|
|
signStr := strings.Join(signData, "&")
|
|
|
|
|
signStr = signStr + "&key=" + payKey
|
|
|
|
|
|
|
|
|
|
logger.Info("签字符串1 :", signStr)
|
|
|
|
|
c := md5.New()
|
|
|
|
|
_, err := c.Write([]byte(signStr))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signByte := c.Sum(nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%x", signByte), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
WxAppId = "wx806c079463b5b56c"
|
|
|
|
|
WxAppSecret = "3d7335cf0b9fa1d70aa7eb079526ebf0"
|
2022-08-31 07:25:45 +00:00
|
|
|
|
|
2022-08-12 02:41:33 +00:00
|
|
|
|
WxAppMchId = "1609877389"
|
|
|
|
|
WxAppMchSecret = "DeovoMingHuiRengTianTang45675456"
|
|
|
|
|
WxCheckName = "NO_CHECK"
|
|
|
|
|
SpbilCreateIp = "39.108.188.218"
|
|
|
|
|
WxTransferUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"
|
|
|
|
|
|
|
|
|
|
WxKeyFile = "./configs/merchant/apiclient_key.pem"
|
|
|
|
|
WxRootCaFile = "./configs/merchant/apiclient_cert.pem"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
|
|
|
|
|
type WxTransferReq struct {
|
|
|
|
|
XMLName xml.Name `xml:"xml"` //xml标签
|
|
|
|
|
MchAppid string `xml:"mch_appid" json:"mch_appid"` //微信分配的小程序ID,必须
|
|
|
|
|
MchId string `xml:"mchid" json:"mchid"` //微信支付分配的商户号,必须
|
|
|
|
|
DeviceInfo string `xml:"device_info" json:"device_info"`
|
|
|
|
|
NonceStr string `xml:"nonce_str" json:"nonce_str"` //随机字符串,必须
|
|
|
|
|
Sign string `xml:"sign" json:"sign"` //签名,必须 //"HMAC-SHA256"或者"MD5",非必须,默认MD5
|
|
|
|
|
PartnerTradeNo string `xml:"partner_trade_no" json:"partner_trade_no"` //CRS订单号,必须
|
|
|
|
|
OpenId string `xml:"openid" json:"openid"` //微信用户唯一标识,必须
|
|
|
|
|
CheckName string `xml:"check_name" json:"check_name"`
|
|
|
|
|
ReUserName string `xml:"re_user_name" json:"re_user_name"`
|
|
|
|
|
Amount string `xml:"amount" json:"amount"`
|
|
|
|
|
Desc string `xml:"desc" json:"desc"`
|
|
|
|
|
SpbillCreateIp string `xml:"spbill_create_ip" json:"spbill_create_ip"`
|
|
|
|
|
//SignType string `xml:"sign_type" json:"sign_type"` //"HMAC-SHA256"或者"MD5",非必须,默认MD5
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type WxTransferResp struct {
|
|
|
|
|
ReturnCode string `xml:"return_code,CDATA"`
|
|
|
|
|
ReturnMsg string `xml:"return_msg,CDATA"`
|
|
|
|
|
ResultCode string `xml:"result_code,CDATA"`
|
|
|
|
|
ErrCodeDes string `xml:"err_code_des,CDATA"`
|
|
|
|
|
PartnerTradeNo string `xml:"partner_trade_no,CDATA"`
|
|
|
|
|
PaymentNo string `xml:"payment_no,CDATA"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//给用户打款
|
|
|
|
|
func Transfer(amount uint32, openId, desc string) (*WxTransferResp, error) {
|
|
|
|
|
tradeNO := GenTradeNo()
|
|
|
|
|
nonce := GenRandStr(NonceStringLength)
|
|
|
|
|
|
|
|
|
|
req := WxTransferReq{
|
|
|
|
|
MchAppid: WxAppId,
|
|
|
|
|
MchId: WxAppMchId,
|
|
|
|
|
NonceStr: nonce,
|
|
|
|
|
Sign: "",
|
|
|
|
|
//SignType: "MD5",
|
|
|
|
|
PartnerTradeNo: tradeNO,
|
|
|
|
|
OpenId: openId,
|
|
|
|
|
CheckName: WxCheckName,
|
|
|
|
|
Amount: fmt.Sprintf("%d", amount),
|
|
|
|
|
Desc: desc,
|
|
|
|
|
SpbillCreateIp: SpbilCreateIp,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wxResp := WxTransferResp{}
|
|
|
|
|
|
|
|
|
|
//生成签名
|
|
|
|
|
m, err := struct2Map(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sign, err := GenWechatPaySign(m, WxAppMchSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
req.Sign = strings.ToUpper(sign)
|
|
|
|
|
|
|
|
|
|
payload, err := xml.Marshal(&req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request, err := newPostRequest(WxTransferUrl, string(payload))
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer request.Body.Close()
|
|
|
|
|
logger.Info("证书路径:", WxRootCaFile)
|
|
|
|
|
logger.Info("证书路径:", WxKeyFile)
|
|
|
|
|
client, err := newHttpClient(WxRootCaFile, WxKeyFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(request)
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
//logger.Info("Transfer resp = ", string(body))
|
|
|
|
|
logger.Info("Transfer resp = ", string(body))
|
|
|
|
|
err = xml.Unmarshal(body, &wxResp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if wxResp.ReturnCode != "SUCCESS" || wxResp.ResultCode != "SUCCESS" {
|
2022-10-13 09:20:52 +00:00
|
|
|
|
if wxResp.ErrCodeDes == "余额不足" {
|
|
|
|
|
return nil, errors.New("account balance insufficient")
|
|
|
|
|
}
|
2022-08-12 02:41:33 +00:00
|
|
|
|
return nil, errors.New("Transfer fail")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &wxResp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newPostRequest(url string, content string) (*http.Request, error) {
|
|
|
|
|
request, err := http.NewRequest("POST", url, strings.NewReader(content))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request.Header.Set("Content-Type", "application/xml")
|
|
|
|
|
|
|
|
|
|
return request, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newHttpClient(certFile, keyFile string) (*http.Client, error) {
|
|
|
|
|
tlsCert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conf := &tls.Config{
|
|
|
|
|
Certificates: []tls.Certificate{tlsCert},
|
|
|
|
|
}
|
|
|
|
|
trans := &http.Transport{
|
|
|
|
|
TLSClientConfig: conf,
|
|
|
|
|
}
|
|
|
|
|
client := &http.Client{
|
|
|
|
|
Transport: trans,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return client, nil
|
|
|
|
|
}
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
type HmPayPublicPara struct {
|
|
|
|
|
AppId string `json:"app_id"`
|
|
|
|
|
//SubAppId string `json:"sub_app_id"`
|
2022-11-22 07:42:48 +00:00
|
|
|
|
Method string `json:"method"`
|
|
|
|
|
//Charset string `json:"charset"`
|
|
|
|
|
SignType string `json:"sign_type"`
|
2022-11-18 07:12:09 +00:00
|
|
|
|
Sign string `json:"sign"`
|
|
|
|
|
Timestamp string `json:"timestamp"`
|
|
|
|
|
Nonce string `json:"nonce"`
|
|
|
|
|
//Version string `json:"version"`
|
|
|
|
|
//Format string `json:"format"`
|
|
|
|
|
BizContent string `json:"biz_content"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HmJsPayUnifiedOrderReq struct {
|
2022-11-22 07:42:48 +00:00
|
|
|
|
HmPayPublicPara
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HmPayBizContent struct {
|
2022-11-23 02:10:14 +00:00
|
|
|
|
Body string `json:"body"`
|
|
|
|
|
MerAppId string `json:"mer_app_id"`
|
|
|
|
|
//BuyerId string `json:"buyer_id"`
|
|
|
|
|
MerBuyerId string `json:"mer_buyer_id"`
|
|
|
|
|
CreateIp string `json:"create_ip"`
|
|
|
|
|
CreateTime string `json:"create_time"`
|
|
|
|
|
//DiscountInfo struct {
|
|
|
|
|
// DiscountableAmount float64 `json:"discountable_amount"`
|
|
|
|
|
//} `json:"discount_info"`
|
|
|
|
|
ExpireTime string `json:"expire_time"`
|
|
|
|
|
//ExtendParams struct {
|
|
|
|
|
// AccessPartyCode string `json:"access_party_code"`
|
|
|
|
|
//} `json:"extend_params"`
|
|
|
|
|
//GoodsDetails []HmPayGoodsDetails `json:"goods_details"`
|
|
|
|
|
LimitPay string `json:"limit_pay"`
|
|
|
|
|
NotifyUrl string `json:"notify_url"`
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//OperatorId string `json:"operator_id"`
|
|
|
|
|
OutOrderNo string `json:"out_order_no"`
|
2022-11-18 07:12:09 +00:00
|
|
|
|
PayType string `json:"pay_type"`
|
2022-11-22 07:42:48 +00:00
|
|
|
|
PayWay string `json:"pay_way"`
|
|
|
|
|
StoreId string `json:"store_id"`
|
|
|
|
|
//TerminalId string `json:"terminal_id"`
|
2022-11-18 07:12:09 +00:00
|
|
|
|
TotalAmount float64 `json:"total_amount"`
|
2022-11-22 07:42:48 +00:00
|
|
|
|
}
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
type HmPayGoodsDetails struct {
|
|
|
|
|
Body string `json:"body"`
|
|
|
|
|
GoodsId string `json:"goods_id"`
|
|
|
|
|
GoodsName string `json:"goods_name"`
|
|
|
|
|
Price float64 `json:"price"`
|
|
|
|
|
Quantity int `json:"quantity"`
|
|
|
|
|
ShowUrl string `json:"show_url"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HmPayUnifiedOrderDetail struct {
|
|
|
|
|
BankOrderNo string `json:"bank_order_no"`
|
|
|
|
|
BankTrxNo string `json:"bank_trx_no"`
|
|
|
|
|
BankWay string `json:"bank_way"`
|
|
|
|
|
OutOrderNo string `json:"out_order_no"`
|
|
|
|
|
PayData string `json:"pay_data"`
|
|
|
|
|
PlatTrxNo string `json:"plat_trx_no"`
|
|
|
|
|
PrepayId string `json:"prepay_id"`
|
|
|
|
|
SubCode string `json:"sub_code"`
|
|
|
|
|
SubMsg string `json:"sub_msg"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HmPayUnifiedOrderPayData struct {
|
|
|
|
|
TimeStamp string `json:"timeStamp"`
|
|
|
|
|
Package string `json:"package"`
|
|
|
|
|
PaySign string `json:"paySign"`
|
|
|
|
|
AppId string `json:"appId"`
|
|
|
|
|
SignType string `json:"signType"`
|
|
|
|
|
NonceStr string `json:"nonceStr"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HmPayUnifiedOrderRsp struct {
|
|
|
|
|
Code string `json:"code"`
|
|
|
|
|
Msg string `json:"msg"`
|
|
|
|
|
Data string `json:"data"`
|
|
|
|
|
Sign string `json:"sign"`
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//hm 微信支付
|
2022-11-26 08:52:05 +00:00
|
|
|
|
func HmJsPayUnifiedOrder(orderId string, totalFee uint32, openId, notifyUrl string) (*HmPayUnifiedOrderPayData, error) {
|
2022-11-18 07:12:09 +00:00
|
|
|
|
now := time.Now().Local()
|
|
|
|
|
strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(),
|
|
|
|
|
now.Minute(), now.Second())
|
2022-11-22 07:42:48 +00:00
|
|
|
|
expireTime := now.Add(time.Hour * 3)
|
|
|
|
|
strExpireTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", expireTime.Year(), expireTime.Month(),
|
|
|
|
|
expireTime.Day(), expireTime.Hour(), expireTime.Minute(), expireTime.Second())
|
2022-11-18 07:12:09 +00:00
|
|
|
|
nonce := utils.GenRandStr(NonceStringLength)
|
|
|
|
|
|
|
|
|
|
if notifyUrl == "" {
|
|
|
|
|
logger.Error("NotifyUrl is null")
|
|
|
|
|
return nil, errors.New("NotifyUrl is null")
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//logger.Info("MchId:", config.AppConfig.WxMchID)
|
|
|
|
|
//logger.Info("AppId:", config.AppConfig.WxAppId)
|
|
|
|
|
//logger.Info("MchSecret:", config.AppConfig.WxMchSecret)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
unifiedOrderReq := HmJsPayUnifiedOrderReq{}
|
2022-11-18 07:12:09 +00:00
|
|
|
|
publicPara := HmPayPublicPara{
|
|
|
|
|
AppId: HmPayMerchantId,
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//SubAppId: HmWxSubMerchantId,
|
|
|
|
|
Method: "trade.create",
|
|
|
|
|
//Charset: "UTF-8",
|
|
|
|
|
SignType: "RSA",
|
2022-11-18 07:12:09 +00:00
|
|
|
|
Sign: "",
|
|
|
|
|
Timestamp: now.Format(TimeFormat),
|
|
|
|
|
Nonce: nonce,
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//Nonce: fmt.Sprintf("%d", time.Now().UnixNano()),
|
|
|
|
|
//Version: "1.0.0",
|
|
|
|
|
//Format: "JSON",
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
biz := HmPayBizContent{
|
2022-11-30 01:43:36 +00:00
|
|
|
|
Body: "服务费",
|
2022-11-23 02:10:14 +00:00
|
|
|
|
MerAppId: WxAppId,
|
|
|
|
|
MerBuyerId: openId,
|
|
|
|
|
CreateIp: clientIp,
|
|
|
|
|
CreateTime: strTime,
|
|
|
|
|
ExpireTime: strExpireTime,
|
2022-11-22 07:42:48 +00:00
|
|
|
|
LimitPay: "NO_CREDIT",
|
|
|
|
|
NotifyUrl: notifyUrl,
|
|
|
|
|
OutOrderNo: orderId,
|
|
|
|
|
PayType: "JSAPI",
|
|
|
|
|
PayWay: "WECHAT",
|
|
|
|
|
StoreId: "100001",
|
|
|
|
|
TotalAmount: float64(totalFee) / 100,
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.HmPayPublicPara = publicPara
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
bizString, err := json.Marshal(&biz)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("marshal biz err:", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.HmPayPublicPara.BizContent = string(bizString)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
m, err := struct2Map(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mJson, _ := json.MarshalIndent(&m, "", " ")
|
|
|
|
|
//fmt.Println("mJson:", string(mJson))
|
|
|
|
|
|
|
|
|
|
sign, err := GenHmPaySign(m)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
unifiedOrderReq.Sign = sign
|
|
|
|
|
|
|
|
|
|
//unifiedOrderReqJson, _ := json.Marshal(&unifiedOrderReq)
|
|
|
|
|
//fmt.Println("unifiedOrderReqJson:", string(unifiedOrderReqJson))
|
|
|
|
|
|
|
|
|
|
unifiedOrderResp, err := HmPayUnifiedOrder(unifiedOrderReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("WxUnifiedOrder unified order error %#v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-11-23 02:10:14 +00:00
|
|
|
|
|
|
|
|
|
signContent, err := ToSignContent(unifiedOrderResp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("ToSignContent err:", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
err = HmVerifySha1Rsa(signContent, unifiedOrderResp.Sign)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("HmVerifySha1Rsa err:", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//fmt.Println("unifiedOrderResp:", unifiedOrderResp.Data)
|
|
|
|
|
var hmPayDetail HmPayUnifiedOrderDetail
|
|
|
|
|
err = json.Unmarshal([]byte(unifiedOrderResp.Data), &hmPayDetail)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
if err != nil {
|
2022-11-22 07:42:48 +00:00
|
|
|
|
logger.Errorf("hm pay unified order pay data unmarshal error %#v", err)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//fmt.Println("hmPayDetail:", hmPayDetail)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
var hmPayData HmPayUnifiedOrderPayData
|
|
|
|
|
err = json.Unmarshal([]byte(hmPayDetail.PayData), &hmPayData)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
if err != nil {
|
2022-11-22 07:42:48 +00:00
|
|
|
|
logger.Errorf("hm pay unified order pay data unmarshal error %#v", err)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//fmt.Println("hmPayData:", hmPayData)
|
|
|
|
|
return &hmPayData, nil
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 02:10:14 +00:00
|
|
|
|
func ToSignContent(s interface{}) (string, error) {
|
|
|
|
|
m, err := struct2Map(s)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete(m, "sign")
|
|
|
|
|
var signData []string
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
if k == "openid" {
|
|
|
|
|
fmt.Println(k, ":", v)
|
|
|
|
|
}
|
|
|
|
|
if v != "" && v != "0" {
|
|
|
|
|
signData = append(signData, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sort.Strings(signData)
|
|
|
|
|
|
|
|
|
|
//signDataJson2, _ := json.MarshalIndent(&signData, "", " ")
|
|
|
|
|
//fmt.Println("signDataJson2", string(signDataJson2))
|
|
|
|
|
|
|
|
|
|
signStr := strings.Join(signData, "&")
|
|
|
|
|
|
|
|
|
|
return signStr, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 07:12:09 +00:00
|
|
|
|
func GenHmPaySign(m map[string]string) (string, error) {
|
|
|
|
|
delete(m, "sign")
|
|
|
|
|
var signData []string
|
|
|
|
|
for k, v := range m {
|
|
|
|
|
if k == "openid" {
|
|
|
|
|
fmt.Println(k, ":", v)
|
|
|
|
|
}
|
|
|
|
|
if v != "" && v != "0" {
|
|
|
|
|
signData = append(signData, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//signDataJson, _ := json.MarshalIndent(&signData, "", " ")
|
|
|
|
|
//fmt.Println("signDataJson1", string(signDataJson))
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
sort.Strings(signData)
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
//signDataJson2, _ := json.MarshalIndent(&signData, "", " ")
|
|
|
|
|
//fmt.Println("signDataJson2", string(signDataJson2))
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
signStr := strings.Join(signData, "&")
|
|
|
|
|
//signStr = signStr + "&key=" + payKey
|
|
|
|
|
logger.Info("签字符串1 :", signStr)
|
2022-11-22 07:42:48 +00:00
|
|
|
|
|
|
|
|
|
signature, err := Sha1withRsa(signStr)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("signature err:", err)
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return signature, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
func Sha1withRsa(signContent string) (string, error) {
|
|
|
|
|
hash := crypto.SHA1
|
2022-11-18 07:12:09 +00:00
|
|
|
|
shaNew := hash.New()
|
|
|
|
|
shaNew.Write([]byte(signContent))
|
|
|
|
|
hashed := shaNew.Sum(nil)
|
|
|
|
|
priKey, err := ParsePrivateKey()
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("parse err:", err)
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, hashed)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("sign err:", err)
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return b64.StdEncoding.EncodeToString(signature), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParsePrivateKey() (*rsa.PrivateKey, error) {
|
2022-11-23 02:10:14 +00:00
|
|
|
|
//fp := "/Users/li/mh/mh_server/pack/configs/hm_pay/private_key.pem"
|
|
|
|
|
fp := "./configs/hm_pay/private_key.pem"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
privateKey, err := ioutil.ReadFile(fp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("read file err:", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block, _ := pem.Decode([]byte(privateKey))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return nil, errors.New("私钥信息错误!")
|
|
|
|
|
}
|
|
|
|
|
//priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
|
|
|
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if priKey == nil {
|
|
|
|
|
return nil, errors.New("pri key is nil")
|
|
|
|
|
}
|
|
|
|
|
return priKey.(*rsa.PrivateKey), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
2022-11-23 02:10:14 +00:00
|
|
|
|
PemBegin = "-----BEGIN RSA PRIVATE KEY-----\n"
|
|
|
|
|
PemEnd = "\n-----END RSA PRIVATE KEY-----"
|
2022-11-18 07:12:09 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func FormatPrivateKey(privateKey string) string {
|
|
|
|
|
//privateKey = strings.Trim(privateKey, "\n")
|
2022-11-23 02:10:14 +00:00
|
|
|
|
if !strings.HasPrefix(privateKey, PemBegin) {
|
|
|
|
|
privateKey = PemBegin + privateKey
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
2022-11-23 02:10:14 +00:00
|
|
|
|
if !strings.HasSuffix(privateKey, PemEnd) {
|
|
|
|
|
privateKey = privateKey + PemEnd
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
return privateKey
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 02:10:14 +00:00
|
|
|
|
const HmPubKey = `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDzGVH0Fxpb2M48U1BWr6lpNs2W3VHqtjO8X5RqWjtTwpQVKo8dqaiAGxVbsdnefPpsbI5l9rKquRAOJhWFU07hxSUgXZOk55QQmll03MBgRDXLgxyKfycLLQwhsCJAzDIWC7IWgok/RHV9m9AV2GbQxWBl+7iDE4prcbpgG8Z0HwIDAQAB`
|
|
|
|
|
|
|
|
|
|
func HmVerifySha1Rsa(signContent, signBase string) error {
|
|
|
|
|
//fp := "/Users/li/mh/mh_server/pack/configs/hm_pay/public_key.pme"
|
|
|
|
|
//publicKeyString, err := ioutil.ReadFile(fp)
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// fmt.Println("read file err:", err)
|
|
|
|
|
// return err
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
block, _ := pem.Decode([]byte(FormatPrivateKey(HmPubKey)))
|
|
|
|
|
if block == nil {
|
|
|
|
|
fmt.Println("decode block is nil")
|
|
|
|
|
return errors.New("decode block is nil")
|
|
|
|
|
}
|
|
|
|
|
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("public key err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if publicKey == nil {
|
|
|
|
|
fmt.Println("public key nil:")
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
hash := crypto.SHA1
|
|
|
|
|
shaNew := hash.New()
|
|
|
|
|
shaNew.Write([]byte(signContent))
|
|
|
|
|
hashed := shaNew.Sum(nil)
|
|
|
|
|
|
|
|
|
|
sign, err := b64.StdEncoding.DecodeString(signBase)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("sign decode err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = rsa.VerifyPKCS1v15(publicKey.(*rsa.PublicKey), hash, hashed, sign)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("verify err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
//logger.Error("验签成功")
|
|
|
|
|
fmt.Println("验签成功")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
func VerifySha1Rsa(signContent, signBase string) error {
|
2022-11-18 07:12:09 +00:00
|
|
|
|
fp := "/Users/li/mh/mh_server/pack/configs/hm_pay/public_key.pme"
|
|
|
|
|
publicKeyString, err := ioutil.ReadFile(fp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("read file err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block, _ := pem.Decode([]byte(publicKeyString))
|
2022-11-23 02:10:14 +00:00
|
|
|
|
if block == nil {
|
|
|
|
|
fmt.Println("decode block is nil")
|
|
|
|
|
return errors.New("decode block is nil")
|
|
|
|
|
}
|
2022-11-18 07:12:09 +00:00
|
|
|
|
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("public key err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if publicKey == nil {
|
|
|
|
|
fmt.Println("public key nil:")
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
hash := crypto.SHA1
|
2022-11-18 07:12:09 +00:00
|
|
|
|
shaNew := hash.New()
|
|
|
|
|
shaNew.Write([]byte(signContent))
|
|
|
|
|
hashed := shaNew.Sum(nil)
|
|
|
|
|
|
|
|
|
|
sign, err := b64.StdEncoding.DecodeString(signBase)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("sign decode err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
err = rsa.VerifyPKCS1v15(publicKey.(*rsa.PublicKey), hash, hashed, sign)
|
2022-11-18 07:12:09 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("verify err:", err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
//logger.Error("验签成功")
|
|
|
|
|
fmt.Println("验签成功")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
func HmPayUnifiedOrder(r HmJsPayUnifiedOrderReq) (HmPayUnifiedOrderRsp, error) {
|
|
|
|
|
var hmPayUnifiedOrderRsp HmPayUnifiedOrderRsp
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
2022-11-22 07:42:48 +00:00
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
|
2022-11-18 07:12:09 +00:00
|
|
|
|
fmt.Println("data json:", string(data))
|
|
|
|
|
client := http.Client{}
|
2022-11-30 01:43:36 +00:00
|
|
|
|
req, err := http.NewRequest("POST", HmPayApiUrl, bytes.NewBuffer(data))
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
|
//req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("body:", string(body))
|
|
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(body, &hmPayUnifiedOrderRsp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("hmPayUnifiedOrderRsp err:", err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
if hmPayUnifiedOrderRsp.Code != "200" {
|
|
|
|
|
return hmPayUnifiedOrderRsp, errors.New(hmPayUnifiedOrderRsp.Msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hmPayUnifiedOrderRsp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func HmPayRefundOrder(r HmJsPayUnifiedOrderReq) (HmPayUnifiedOrderRsp, error) {
|
|
|
|
|
var hmPayUnifiedOrderRsp HmPayUnifiedOrderRsp
|
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("data json:", string(data))
|
|
|
|
|
client := http.Client{}
|
|
|
|
|
req, err := http.NewRequest("POST", HmPayApiUrl, bytes.NewBuffer(data))
|
2022-11-18 07:12:09 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
2022-11-22 07:42:48 +00:00
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
|
//req.Header.Set("Content-Type", "application/json")
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
2022-11-22 07:42:48 +00:00
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error(err)
|
2022-11-22 07:42:48 +00:00
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
fmt.Println("body:", string(body))
|
|
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
err = json.Unmarshal(body, &hmPayUnifiedOrderRsp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("hmPayUnifiedOrderRsp err:", err)
|
|
|
|
|
return hmPayUnifiedOrderRsp, err
|
|
|
|
|
}
|
|
|
|
|
if hmPayUnifiedOrderRsp.Code != "200" {
|
|
|
|
|
return hmPayUnifiedOrderRsp, errors.New(hmPayUnifiedOrderRsp.Msg)
|
|
|
|
|
}
|
2022-11-18 07:12:09 +00:00
|
|
|
|
|
2022-11-22 07:42:48 +00:00
|
|
|
|
return hmPayUnifiedOrderRsp, nil
|
2022-11-18 07:12:09 +00:00
|
|
|
|
}
|
2022-11-22 07:42:48 +00:00
|
|
|
|
|
|
|
|
|
//func RsaSign(signContent string, privateKey string, hash crypto.Hash) string {
|
|
|
|
|
// shaNew := hash.New()
|
|
|
|
|
// shaNew.Write([]byte(signContent))
|
|
|
|
|
// hashed := shaNew.Sum(nil)
|
|
|
|
|
// priKey, err := ParsePrivateKey(privateKey)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// panic(err)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, hashed)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// panic(err)
|
|
|
|
|
// }
|
|
|
|
|
// return base64.StdEncoding.EncodeToString(signature)
|
|
|
|
|
//
|
|
|
|
|
// digest := sha256.Sum256(data)
|
|
|
|
|
//
|
|
|
|
|
// signature, signErr := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, digest[:])
|
|
|
|
|
//
|
|
|
|
|
// if signErr != nil {
|
|
|
|
|
// t.Errorf("Could not sign message:%s", signErr.Error())
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // just to check that we can survive to and from b64
|
|
|
|
|
// b64sig := base64.StdEncoding.EncodeToString(signature)
|
|
|
|
|
//
|
|
|
|
|
// decodedSignature, _ := base64.StdEncoding.DecodeString(b64sig)
|
|
|
|
|
//}
|