Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat(pay): 添加支付API基础结构 feat(miniapp): 创建支付测试小程序页面与配置 feat(wechatpay): 配置微信支付参数与证书 fix(guild): 修复成员列表查询条件 docs: 更新代码规范文档与需求文档 style: 统一前后端枚举显示与注释格式 refactor(admin): 重构用户奖励发放接口参数处理 test(title): 添加称号效果参数验证测试
86 lines
2.5 KiB
Go
86 lines
2.5 KiB
Go
package pay
|
||
|
||
import (
|
||
"crypto"
|
||
crand "crypto/rand"
|
||
"crypto/rsa"
|
||
"crypto/sha256"
|
||
"crypto/x509"
|
||
"encoding/base64"
|
||
"encoding/pem"
|
||
"errors"
|
||
"fmt"
|
||
mrand "math/rand"
|
||
"os"
|
||
"time"
|
||
|
||
"bindbox-game/configs"
|
||
)
|
||
|
||
// BuildJSAPIParams 为小程序支付构造客户端参数
|
||
// 入参:appid(微信小程序AppID)、prepayID(统一下单返回的prepay_id)
|
||
// 返回:timeStamp、nonceStr、package(格式为"prepay_id=***" )、signType(固定"RSA")、paySign(RSA-SHA256签名)
|
||
// 错误:当私钥读取或签名失败时返回错误
|
||
func BuildJSAPIParams(appid string, prepayID string) (timeStamp string, nonceStr string, pkg string, signType string, paySign string, err error) {
|
||
cfg := configs.Get()
|
||
if cfg.WechatPay.PrivateKeyPath == "" {
|
||
return "", "", "", "", "", errors.New("wechat pay private key path not configured")
|
||
}
|
||
|
||
b, err := os.ReadFile(cfg.WechatPay.PrivateKeyPath)
|
||
if err != nil {
|
||
return "", "", "", "", "", err
|
||
}
|
||
block, _ := pem.Decode(b)
|
||
if block == nil {
|
||
return "", "", "", "", "", errors.New("invalid merchant private key pem")
|
||
}
|
||
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||
if err != nil {
|
||
// 兼容PKCS1
|
||
k1, e1 := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||
if e1 != nil {
|
||
return "", "", "", "", "", err
|
||
}
|
||
key = k1
|
||
}
|
||
rsaKey, ok := key.(*rsa.PrivateKey)
|
||
if !ok {
|
||
return "", "", "", "", "", errors.New("merchant private key is not RSA")
|
||
}
|
||
|
||
ts := fmt.Sprintf("%d", time.Now().Unix())
|
||
// 随机串32位
|
||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||
rb := make([]byte, 32)
|
||
for i := range rb {
|
||
rb[i] = letters[mrand.Intn(len(letters))]
|
||
}
|
||
nonce := string(rb)
|
||
pkg = "prepay_id=" + prepayID
|
||
signType = "RSA"
|
||
|
||
message := fmt.Sprintf("%s\n%s\n%s\n%s\n", appid, ts, nonce, pkg)
|
||
h := sha256.Sum256([]byte(message))
|
||
sig, err := rsa.SignPKCS1v15(crand.Reader, rsaKey, crypto.SHA256, h[:])
|
||
if err != nil {
|
||
return "", "", "", "", "", err
|
||
}
|
||
paySign = base64.StdEncoding.EncodeToString(sig)
|
||
return ts, nonce, pkg, signType, paySign, nil
|
||
}
|
||
|
||
// ValidateConfig 校验微信支付必要配置
|
||
// 入参:无
|
||
// 返回:true表示配置齐全;false表示缺失,并附带错误信息
|
||
func ValidateConfig() (bool, error) {
|
||
c := configs.Get()
|
||
if c.Wechat.AppID == "" {
|
||
return false, errors.New("wechat app_id missing")
|
||
}
|
||
if c.WechatPay.MchID == "" || c.WechatPay.SerialNo == "" || c.WechatPay.PrivateKeyPath == "" || c.WechatPay.ApiV3Key == "" {
|
||
return false, errors.New("wechat pay config incomplete")
|
||
}
|
||
return true, nil
|
||
}
|