Browse Source

unionpay v3

ls 5 years ago
parent
commit
cc4c43836a
5 changed files with 164 additions and 10 deletions
  1. 12 2
      unionpay/client.go
  2. 9 0
      unionpay/rsa.go
  3. 6 0
      unionpay/url.go
  4. 8 8
      unionpay/util.go
  5. 129 0
      unionpay/v3.go

+ 12 - 2
unionpay/client.go

@@ -84,7 +84,7 @@ type ReqParams struct {
 type ReqRespose struct {
 	Encoding       string `form:"encoding" json:"encoding" xml:"encoding"`
 	Version        string `form:"version" json:"version" xml:"version"`
-	RespCode       int    `form:"respCode" json:"respCode" xml:"respCode"` // 响应代码, 0 成功, > 0 错误
+	RespCode       string `form:"respCode" json:"respCode" xml:"respCode"` // 响应代码, 0 成功, > 0 错误
 	RespMsg        string `form:"respMsg" json:"respMsg" xml:"respMsg"`
 	TxnType        string `form:"txnType" json:"txnType" xml:"txnType"`
 	ChannelType    string `form:"channelType" json:"channelType" xml:"channelType"`
@@ -206,7 +206,17 @@ func (ci *CustomerInfo) String(encrypted []byte) string {
 
 // Ok 请求返回是否成功
 func (res *ReqRespose) Ok() (ok bool, err error) {
-	if res.RespCode == 0 {
+	if res.RespCode == "0" {
+		ok = true
+		return
+	}
+	err = errors.New(res.RespMsg)
+	return
+}
+
+// V3Ok 请求返回是否成功(Version 3.0)
+func (res *ReqRespose) V3Ok() (ok bool, err error) {
+	if res.RespCode == "00" {
 		ok = true
 		return
 	}

+ 9 - 0
unionpay/rsa.go

@@ -4,6 +4,7 @@ import (
 	"crypto"
 	"crypto/rand"
 	"crypto/rsa"
+	"crypto/sha1"
 	"crypto/sha256"
 )
 
@@ -28,6 +29,14 @@ func sign(priveKey *rsa.PrivateKey, src []byte) (data []byte, err error) {
 	return
 }
 
+// signsha1 RSA sha1签名
+func signsha1(priveKey *rsa.PrivateKey, src []byte) (data []byte, err error) {
+	hashed := sha1.Sum(src)
+	//hashed = sha256.Sum256(hashed[:])
+	data, err = rsa.SignPKCS1v15(rand.Reader, priveKey, crypto.SHA1, hashed[:])
+	return
+}
+
 // verify RSA 签名验证
 func verify(publicKey *rsa.PublicKey, src, sig []byte) (err error) {
 	hashed := sha256.Sum256(src)

+ 6 - 0
unionpay/url.go

@@ -4,6 +4,12 @@ const (
 	// BaseHost 主机地址
 	BaseHost = `https://gateway.95516.com`
 
+	// V3BaseHost 主机地址(Version 3.0)
+	V3BaseHost = `https://unionpaysecure.com`
+
 	// ReqBackTrans 建立委托:后台交易,只有同步应答
 	ReqBackTrans = `/gateway/api/backTransReq.do`
+
+	// V3ReqBackTrans 建立委托:后台交易,只有同步应答(Version 3.0)
+	V3ReqBackTrans = `/gateway/api/backTransRequest.do`
 )

+ 8 - 8
unionpay/util.go

@@ -83,14 +83,14 @@ func post(uri string, body []byte) (res ReqRespose, err error) {
 		err = fmt.Errorf("Request status code %d", msg.StatusCode)
 		return
 	}
-	/*
-		fmt.Println("*************************************")
-		fmt.Println(uri)
-		fmt.Println(msg.StatusCode)
-		fmt.Println(msg.Header)
-		fmt.Println(string(msg.Body))
-		fmt.Println("*************************************")
-		// */
+	//*
+	fmt.Println("*************************************")
+	fmt.Println(uri)
+	fmt.Println(msg.StatusCode)
+	fmt.Println(msg.Header)
+	fmt.Println(string(msg.Body))
+	fmt.Println("*************************************")
+	// */
 	var values url.Values
 	values, err = url.ParseQuery(string(msg.Body))
 	if err != nil {

+ 129 - 0
unionpay/v3.go

@@ -0,0 +1,129 @@
+package unionpay
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+
+	"git.chuangxin1.com/cx/util"
+)
+
+func getCustomerV3(ci CustomerInfo) (s string) {
+	s = "{" + ci.CertifTp + "|"
+	s += ci.CertifID + "|"
+	s += ci.CustomerName + "|"
+	s += ci.Phone + "|"
+	s += "|"           // SMS message
+	s += "|"           // password
+	s += ci.Cvn2 + "|" // cvn2
+	s += ci.Expired
+	s += "}"
+
+	return
+}
+
+// V3SendSms 发送验证码(Version 3.0)
+func V3SendSms(mi *MerchantInfo, ci CustomerInfo, oi OrderInfo) (res ReqRespose, err error) {
+	return
+}
+
+// V3Verify 验证卡片(Version 3.0)
+func V3Verify(mi *MerchantInfo, ci CustomerInfo, oi OrderInfo) (res ReqRespose, err error) {
+	args := make(map[string]string)
+
+	args["version"] = "3.0.0"
+	args["encoding"] = "utf-8"
+	args["txnType"] = "72"
+	args["txnSubType"] = "01"
+	args["bizType"] = "000000"
+	args["accessType"] = "0"
+	args["merType"] = "0"
+	args["merId"] = mi.MerID
+	args["subMerId"] = ""
+	args["subMerName"] = ""
+	args["orderId"] = oi.OrderID
+	args["txnTime"] = oi.TxnTime
+	args["accType"] = "01"
+	args["accNo"] = ci.CardNo // 账号, 不加密
+	args["customerInfo"] = base64Encode([]byte(getCustomerV3(ci)))
+	args["bindId"] = ""
+	args["riskLevel"] = ""
+	args["bindInfo"] = ""
+	args["reqReserved"] = ""
+	args["reserved"] = ""
+	args["encryptCertId"] = mi.SerialNumber()
+	args["userMac"] = ""
+	args["certId"] = mi.SerialNumber()
+
+	s := createLinkString(args, true, false)
+	sha1 := util.SHA1(s)
+
+	var data []byte
+	data, err = signsha1(mi.PrivateKey, []byte(sha1))
+	if err != nil {
+		return
+	}
+
+	args["signature"] = base64Encode(data)
+	values := url.Values{}
+	for k, v := range args {
+		values.Add(k, v)
+	}
+	res, err = post(V3BaseHost+V3ReqBackTrans, []byte(values.Encode()))
+
+	return
+}
+
+// V3Charging 代扣(Version 3.0)
+func V3Charging(mi *MerchantInfo, ci CustomerInfo, oi OrderInfo) (res ReqRespose, err error) {
+	args := make(map[string]string)
+
+	args["version"] = "3.0.0"
+	args["encoding"] = "utf-8"
+	args["txnType"] = "11"
+	args["txnSubType"] = "00"
+	args["bizType"] = "000000"
+	args["backurl"] = ""
+	args["accessType"] = "0"
+	args["merType"] = "0"
+	args["merId"] = mi.MerID
+	args["subMerId"] = ""
+	args["subMerName"] = ""
+	args["orderId"] = oi.OrderID
+	args["txnTime"] = oi.TxnTime
+	args["currencyCode"] = "156" // 交易币种
+	args["accType"] = "01"
+	args["accNo"] = ci.CardNo // 账号, 不加密
+	args["issInsCode"] = ""   // 发卡机构代码
+	args["customerInfo"] = base64Encode([]byte(getCustomerV3(ci)))
+	args["bindId"] = ""
+	args["riskLevel"] = ""
+	args["txnAmt"] = strconv.Itoa(oi.TxnAmt)
+	args["billType"] = "OT00" // 账单类型
+	args["billNo"] = ""       // 账单号码
+	args["reqReserved"] = ""
+	args["reserved"] = ""
+	args["customerIp"] = ""
+	args["encryptCertId"] = mi.SerialNumber()
+	args["billPeriod"] = "" // 账单周期
+	args["certId"] = mi.SerialNumber()
+
+	s := createLinkString(args, true, false)
+	sha1 := util.SHA1(s)
+
+	fmt.Println("createLinkString", s)
+	var data []byte
+	data, err = signsha1(mi.PrivateKey, []byte(sha1))
+	if err != nil {
+		return
+	}
+
+	args["signature"] = base64Encode(data)
+	values := url.Values{}
+	for k, v := range args {
+		values.Add(k, v)
+	}
+	res, err = post(V3BaseHost+V3ReqBackTrans, []byte(values.Encode()))
+
+	return
+}