Skip to content

Commit

Permalink
Feature/alipay v3 (#422)
Browse files Browse the repository at this point in the history
* alipay v3
  • Loading branch information
iGoogle-ink authored Oct 2, 2024
1 parent 6de2a76 commit 4e7edf1
Show file tree
Hide file tree
Showing 20 changed files with 1,534 additions and 66 deletions.
32 changes: 17 additions & 15 deletions alipay/cert/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package cert
var (
Appid = "2021000122672388"

// 私钥
PrivateKey = "MIIEpQIBAAKCAQEAw0x6QX0eeW+XRNh4u/BG1RsyuYYsHmqenk4GrPV8ElrUEN6nLRwSXGSIIuIuyCo0t4swCNp9Q54g+AUmpAddeBCYhHKrAYG4n11MnXUYosEe43wzUhd7PaXpxctFlSKhFgYBiX7cQg/O8ThHJJ0H0Qy+k9NNJ2gMnfPypk9/43DstHmKEVQvgQpcgnhlbK8X4thIK4zW0xwHgDhSAeZu9QLvf/cc2PdKmd5xiUUM7J7PtwT7VvbKI27fYOBe1hxxrvpY6vcGGGal8xhNOKD+eiqXAgPgIRYuXqLpPgaYOImjnnH9lIpzjrCO0nsba1T4tonDjp5jv0FaSKwOTAjO6QIDAQABAoIBAQCjxUUcF7zvXml+XPzZtQLg/97IfsAOfaAn5gxpC66QgcQlpWCRTmIDQnZ6sitCxUnRxJFySy4R/s9szHz7vgVegqQzJSlLqSlV0lpGDAStrr6lSuiKZZB+QNxJdk0SY6irnDu7vjsb1r/VvjjCdkAwyLwjoGSpr/Isnn4TgsUexoBJOVBRvfsVmzNq0oaD12jEHPLnOgyBOUxN54A64mz7H7VBnYhG2TOL2ECqiQ/bAD3hy4KGoU1y3uT5gcC1pOXTE1XP4d1LDt434G4nPUIMxkMLhotecviWsbJ4FocRcPXs8qVptgarj5h9IMrjyLXDm17hfUqTtImhMEDqE/JFAoGBAP5RWI9qhIzEAWxualhAc2IssQ8MPFGkXFWB4NWYmXVMxodVonyQp9P4AFdL3wsiVhvSmccxqCy5R6Mbv81rFnb29meL08eqAy3HAW/br3jcnbN/W799OGaMXBi+DDES1xBmQndFVGFfm09xcndyTrmGiMgHW1kGgz6WFEHuRXI/AoGBAMSXMMqHEZxD9T4tahFV4xlUP67mLDrETQNOT0vX4NrLS4CXZMkt+IVqy3Z0TRapyIrkBpEUoH3ScGzzbIOdLz57SS7D+ZbsU5kCTDXKfPVxww4RjZ92xNJiEHBMzta9Ku5+D3mBznBFm9dMO8+E+0PSKMxm8n4AovQ9SU/hGyTXAoGBALrU4+yoYixPqoQQMcwXvSx4jLLzWDTaPIMM4THJ46MK/iZaQP6l/sV4Qjffo0I4vW2/L/3oexYwH3KyZhvw+hX3pFm5naHnQmKU+ndEuwpdePVvMOXihla/8sCyjZ5Xqut/VIDuy+ilJiIcw+0Aatlc/ouE7BTg9fY6pzMwapBdAoGBAIkMvb7zGpvN5JJMJr2fGor16M+NNxhg8S900GMXRHJDd4dWA7UcjzyzjtQtj/BUvLHW9Zz+vEP7CNVrfiLi2aS9Xe90P/OvHTh2GZsGZsbVYB3WrtyUd/IS21LuuOOLTPqmdzNGAxzR6irVwnyRQHmvcTHOMw8UcoXCk/FUBRBRAoGAYx52azbgbw1dDoxgGWHWS31zpYdGdg2pxPkr1TInrKFbrQEwnNTqcnPIHqytkvrc9gpqW4XU0Ux7pU/twPO9JXHfXDNWXmJUHyYIeLwbeHrhJ+avtPDs8VwsI8zbBu84D13NJq7dWxPLEUYQNrCrAw4+ywvXmBzXkvEdLaQq1S4="
// 应用私钥
PrivateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3DCgphWsp4OyB5pxF7ImUHHC7luATNfACFiK9qCvMRX1Ot0j4Ll64HUwVWaTfYbS00QyWPZLxwmGIAvh0y+9odu699oAb047p1XG1Q5eQa4qYrlxKGDeGUdWjK0C8qqeVHMAa8FK3xGukPYNersUbQ5E/eQqD7o6m51xR8AzhZ1lwWdW6PPAN51sH9o/MSvGZTmYAOWsErhSKZ0Eb613oG/rfxrvuBH3tFAqHva/cjNPznukieWCHrD5OUXlM48MEK2Ht8rFXs2HG6ZDdMNUMJuz15H5HQ3Plt1KYLy6b6Y6a7NtE1VWGvlmhT1Quzeudkb4lyYMC7DBCE4cZtMBlAgMBAAECggEAAfjNjfTz/JWBtryHPnGX4dKUnFC5xTs1hLA8W5KuNhshiHGNBa9qMc2O/kPi9M0Wp0QBQLUVGimf51kw2AFCaPuvArjfFG2pAnfcK7m4rkOaUJ7AO8QbBQVoqcNThTTJbV/L6f5gxb4F8tT+z0xOr0aBEA/7vwQY4U9ovTE60krIDbd3hE2Eh8RdrKebLrUvvGZ2LPFF3suuGbHHhQwRIzF8Enfa5TjyEJxGz3C3cdCEDjhA/tbMh05egeDhu1qu+Nx1FXzcyc/bFTKF2qPXeE27rclw8U07wggiegHPntJJ9Fgso918f0n8URlzhwpRQ5EjbBNOiVjkKGxQD0rLGQKBgQDl81Jk1iw2WWMuBxZKtxy43sXKjWY8umhrhK0gDjfRXokppCf91+tC3t/7BEc+X8HuAEYCuPs+tnv0XYdhfOeBpy/GHB7NQqYqCiu3Ptm3KnIm/q+CnnPA1HY7222Sa/9NptbfOfrPIlINnglAwjpZ2tn5h0uNvZfMP4Yh+x6aTwKBgQDLyKADd6Iw5jshwVF2SIlv/qHH5w8UKFmkLDT5l6RAqIg0mqY5tPpOEm5JohfYRmp9+ny4U8+V0CNNehN7FLreLJm5ksDvcOuIlEXPCzuEzyO8tkHFuW1pXLcdNnzZmdQ3S8o0mDllegEbwV0OK10RcJ96NRJnngNYp7rohrUxCwKBgHAvHmJtjpJRV66r7Hc1EIEsxehExb0Y4DqcNu4toZO2gEpdeNlBztgH7dQDyVIn22/mmEFZx9FXq++S9apdCoDZdNg8/dX8Dx7xaVR0CDlxLtHRbQTXkvdfb/NR4QoPQDW9EJVFLxSA1PEpya/bUiZmO/OdywFynq0ZzLGlVs/HAoGBALyLV2Fd4vaTTcqhbpmd62tvkIfARLdFzgqTzD/SCeq5A6yIGZvy0lRBwUDndGBqZkVA6PwyrzHRbZhVhoiuWWcOpPyJx3DCbWnkpeI2Zk8ux8Xma1xhf9WoLtQcgc9jAHJY8TFQVmqJQ1VGxq5BeM6WATe0ut6b2ETCi7BwUlyZAoGAV4kL7eiV2rcHa8IROWh8oo+8fgPMb5MSmbU78n/o4tXRTdUmg/6ghE1t9dWK867/PEubVFEvO8F15oQvwLHYdD+SPeLmp/CLf20jzNSjkImFxMG7xmnpre5+sfgIGjioI1rFkwrVk7II7GfvmGpDTbOSLWeiymdFsmmPnjs8I5Q="

PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtwwoKYVrKeDsgeacReyJlBxwu5bgEzXwAhYivagrzEV9TrdI+C5euB1MFVmk32G0tNEMlj2S8cJhiAL4dMvvaHbuvfaAG9OO6dVxtUOXkGuKmK5cShg3hlHVoytAvKqnlRzAGvBSt8RrpD2DXq7FG0ORP3kKg+6OpudcUfAM4WdZcFnVujzwDedbB/aPzErxmU5mADlrBK4UimdBG+td6Bv638a77gR97RQKh72v3IzT857pInlgh6w+TlF5TOPDBCth7fKxV7NhxumQ3TDVDCbs9eR+R0Nz5bdSmC8um+mOmuzbRNVVhr5ZoU9ULs3rnZG+JcmDAuwwQhOHGbTAZQIDAQAB"

// 支付宝公钥证书
AlipayPublicContentRSA2 = []byte(`-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -139,22 +141,22 @@ Yf4Zr0fJsGuv

// 应用公钥证书
AppPublicContent = []byte(`-----BEGIN CERTIFICATE-----
MIIDmTCCAoGgAwIBAgIQICMGCXK2Am4QGbc/5Yi2QjANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
MIIDmTCCAoGgAwIBAgIQICQJJiIfTmxJDlWhVlLYPjANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjMwNjA5MTI1MjAyWhcNMjQwNjEzMTI1MjAyWjBr
dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjQwOTI2MTU0ODExWhcNMjUxMDAxMTU0ODExWjBr
MQswCQYDVQQGEwJDTjEfMB0GA1UECgwWbGFnbWlzNjI1NEBzYW5kYm94LmNvbTEPMA0GA1UECwwG
QWxpcGF5MSowKAYDVQQDDCEyMDg4NzIxMDAzMjM2NDQyLTIwMjEwMDAxMjI2NzIzODgwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDTHpBfR55b5dE2Hi78EbVGzK5hiweap6eTgas9XwS
WtQQ3qctHBJcZIgi4i7IKjS3izAI2n1DniD4BSakB114EJiEcqsBgbifXUyddRiiwR7jfDNSF3s9
penFy0WVIqEWBgGJftxCD87xOEcknQfRDL6T000naAyd8/KmT3/jcOy0eYoRVC+BClyCeGVsrxfi
2EgrjNbTHAeAOFIB5m71Au9/9xzY90qZ3nGJRQzsns+3BPtW9sojbt9g4F7WHHGu+ljq9wYYZqXz
GE04oP56KpcCA+AhFi5eouk+Bpg4iaOecf2UinOOsI7SextrVPi2icOOnmO/QVpIrA5MCM7pAgMB
AAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEAZc2RyiGKftnKi/0zIUUl
xKDPyUdVBBYDagcraHROKXafsZEnhO/cdBPC3VAJEiygNvddB51l088cGb8pGS2VqTQqR/Ehmd1x
kLMleWlUocX0Mwctz/J6jNp9/JKcVe1jk492HR7Csqjf+hvsajIVliIWzuhzB7C0eNEb46Js/G8T
QmsX92eHI0r2pcmsVr+PmDioLu4H4miKrDRhXNXLQ2AQfxPOCOtxt0tSNrB97bDNSwB1O4OItmr/
Cimb7l1nqxY3BOY5o8iAWLv4wG4giYu9LSrEJW0nWa2JG059kMlWLSVe7Afx0GzMVQUP6NJNdulP
ddebveu2CNZcJ7ipbA==
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3DCgphWsp4OyB5pxF7ImUHHC7luATNfACFiK9qCvM
RX1Ot0j4Ll64HUwVWaTfYbS00QyWPZLxwmGIAvh0y+9odu699oAb047p1XG1Q5eQa4qYrlxKGDeG
UdWjK0C8qqeVHMAa8FK3xGukPYNersUbQ5E/eQqD7o6m51xR8AzhZ1lwWdW6PPAN51sH9o/MSvGZ
TmYAOWsErhSKZ0Eb613oG/rfxrvuBH3tFAqHva/cjNPznukieWCHrD5OUXlM48MEK2Ht8rFXs2HG
6ZDdMNUMJuz15H5HQ3Plt1KYLy6b6Y6a7NtE1VWGvlmhT1Quzeudkb4lyYMC7DBCE4cZtMBlAgMB
AAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEAeMqluNI07JunRvkeOdN3
u4l1EicBtaMA63h6Ico92YanIgAzvZY9etwBiCP9ULmqckw+jo6+taXERe3fXSoUqyCH+3Hnb30f
MHp+oHlmpxCG93GLYBe9QcugrbEKg7RJ1l8ikyXMt3nkxBcQochCuNxdhGGYM4rxlGtwU1j0v+CV
Ne4IsK8fbpMF8wfYGOwDb+P1Mqx2Hv1D0qLu4S2ztz+br8Opg5leGY8wMt9+mW5aKwEKX3FVDi5J
ijiKYWzTm718zrmMJ+sN2VrapDvtj92bibOt0PKXUtQ5I++RtjG//dRpjAg9aS5pjvui80tNtwAc
xaEqw58KZ41dIaw3Zw==
-----END CERTIFICATE-----`)
)
4 changes: 0 additions & 4 deletions alipay/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ var (
ctx = context.Background()
client *Client
err error
// 普通公钥模式时
//aliPayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk3/P3KX7rqwVEMkbZlY80PqBKxNHsMB4q5wKbpKU2KZffDiilV3bPpHPm1wHaJHKHudmirVWjn65lIspqIMgA4RoU3Cf0sEs8Mf9aAzv0F47KAWb2oBhDyQcYGtHftLG7q2mGBalXK7TJWWA2+DB2UAtfZELBRaVhsaF7bCkGd3GjTSXBZcyXAShgnH94C7yTr2IRbv+SnwedTdCKHxXvoPRvABylO9Krx8MiyJECBBfQScA67SsL+E1MKiMVdMomzlTEQ7W0UEAtzmG4aRMzSp30Lggit1xH7HKyOWgSE3Xy0LT78VKbqGRuCAT6IT5AA9jqSAbOBft7igJFkz9swIDAQAB"
//appPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0x6QX0eeW+XRNh4u/BG1RsyuYYsHmqenk4GrPV8ElrUEN6nLRwSXGSIIuIuyCo0t4swCNp9Q54g+AUmpAddeBCYhHKrAYG4n11MnXUYosEe43wzUhd7PaXpxctFlSKhFgYBiX7cQg/O8ThHJJ0H0Qy+k9NNJ2gMnfPypk9/43DstHmKEVQvgQpcgnhlbK8X4thIK4zW0xwHgDhSAeZu9QLvf/cc2PdKmd5xiUUM7J7PtwT7VvbKI27fYOBe1hxxrvpY6vcGGGal8xhNOKD+eiqXAgPgIRYuXqLpPgaYOImjnnH9lIpzjrCO0nsba1T4tonDjp5jv0FaSKwOTAjO6QIDAQAB"
//appPrivateKey = "MIIEpQIBAAKCAQEAw0x6QX0eeW+XRNh4u/BG1RsyuYYsHmqenk4GrPV8ElrUEN6nLRwSXGSIIuIuyCo0t4swCNp9Q54g+AUmpAddeBCYhHKrAYG4n11MnXUYosEe43wzUhd7PaXpxctFlSKhFgYBiX7cQg/O8ThHJJ0H0Qy+k9NNJ2gMnfPypk9/43DstHmKEVQvgQpcgnhlbK8X4thIK4zW0xwHgDhSAeZu9QLvf/cc2PdKmd5xiUUM7J7PtwT7VvbKI27fYOBe1hxxrvpY6vcGGGal8xhNOKD+eiqXAgPgIRYuXqLpPgaYOImjnnH9lIpzjrCO0nsba1T4tonDjp5jv0FaSKwOTAjO6QIDAQABAoIBAQCjxUUcF7zvXml+XPzZtQLg/97IfsAOfaAn5gxpC66QgcQlpWCRTmIDQnZ6sitCxUnRxJFySy4R/s9szHz7vgVegqQzJSlLqSlV0lpGDAStrr6lSuiKZZB+QNxJdk0SY6irnDu7vjsb1r/VvjjCdkAwyLwjoGSpr/Isnn4TgsUexoBJOVBRvfsVmzNq0oaD12jEHPLnOgyBOUxN54A64mz7H7VBnYhG2TOL2ECqiQ/bAD3hy4KGoU1y3uT5gcC1pOXTE1XP4d1LDt434G4nPUIMxkMLhotecviWsbJ4FocRcPXs8qVptgarj5h9IMrjyLXDm17hfUqTtImhMEDqE/JFAoGBAP5RWI9qhIzEAWxualhAc2IssQ8MPFGkXFWB4NWYmXVMxodVonyQp9P4AFdL3wsiVhvSmccxqCy5R6Mbv81rFnb29meL08eqAy3HAW/br3jcnbN/W799OGaMXBi+DDES1xBmQndFVGFfm09xcndyTrmGiMgHW1kGgz6WFEHuRXI/AoGBAMSXMMqHEZxD9T4tahFV4xlUP67mLDrETQNOT0vX4NrLS4CXZMkt+IVqy3Z0TRapyIrkBpEUoH3ScGzzbIOdLz57SS7D+ZbsU5kCTDXKfPVxww4RjZ92xNJiEHBMzta9Ku5+D3mBznBFm9dMO8+E+0PSKMxm8n4AovQ9SU/hGyTXAoGBALrU4+yoYixPqoQQMcwXvSx4jLLzWDTaPIMM4THJ46MK/iZaQP6l/sV4Qjffo0I4vW2/L/3oexYwH3KyZhvw+hX3pFm5naHnQmKU+ndEuwpdePVvMOXihla/8sCyjZ5Xqut/VIDuy+ilJiIcw+0Aatlc/ouE7BTg9fY6pzMwapBdAoGBAIkMvb7zGpvN5JJMJr2fGor16M+NNxhg8S900GMXRHJDd4dWA7UcjzyzjtQtj/BUvLHW9Zz+vEP7CNVrfiLi2aS9Xe90P/OvHTh2GZsGZsbVYB3WrtyUd/IS21LuuOOLTPqmdzNGAxzR6irVwnyRQHmvcTHOMw8UcoXCk/FUBRBRAoGAYx52azbgbw1dDoxgGWHWS31zpYdGdg2pxPkr1TInrKFbrQEwnNTqcnPIHqytkvrc9gpqW4XU0Ux7pU/twPO9JXHfXDNWXmJUHyYIeLwbeHrhJ+avtPDs8VwsI8zbBu84D13NJq7dWxPLEUYQNrCrAw4+ywvXmBzXkvEdLaQq1S4="
)

func TestMain(m *testing.M) {
Expand Down
6 changes: 2 additions & 4 deletions alipay/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,8 @@ func (a *Client) autoVerifySignByCert(sign, signData string, signDataErr error)
}

signBytes, _ := base64.StdEncoding.DecodeString(sign)
hashs := crypto.SHA256
h := hashs.New()
h.Write([]byte(signData))
if err = rsa.VerifyPKCS1v15(a.aliPayPublicKey, hashs, h.Sum(nil), signBytes); err != nil {
sum256 := sha256.Sum256([]byte(signData))
if err = rsa.VerifyPKCS1v15(a.aliPayPublicKey, crypto.SHA256, sum256[:], signBytes); err != nil {
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
}
}
Expand Down
111 changes: 111 additions & 0 deletions alipay/v3/cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package alipay

import (
"crypto/md5"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"os"
"strings"

"github.com/go-pay/gopay"
)

// 允许进行 sn 提取的证书签名算法
var allowSignatureAlgorithm = map[string]bool{
"MD2-RSA": true,
"MD5-RSA": true,
"SHA1-RSA": true,
"SHA256-RSA": true,
"SHA384-RSA": true,
"SHA512-RSA": true,
"SHA256-RSAPSS": true,
"SHA384-RSAPSS": true,
"SHA512-RSAPSS": true,
}

// GetCertSN 获取证书序列号SN
// certPathOrData x509证书文件路径(appPublicCert.crt、alipayPublicCert.crt) 或证书 buffer
// 返回 sn:证书序列号(app_cert_sn、alipay_cert_sn)
// 返回 err:error 信息
func GetCertSN(certPathOrData any) (sn string, err error) {
var certData []byte
switch pathOrData := certPathOrData.(type) {
case string:
certData, err = os.ReadFile(pathOrData)
if err != nil {
return gopay.NULL, err
}
case []byte:
certData = pathOrData
default:
return gopay.NULL, errors.New("certPathOrData 证书类型断言错误")
}

if block, _ := pem.Decode(certData); block != nil {
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return gopay.NULL, err
}
name := cert.Issuer.String()
serialNumber := cert.SerialNumber.String()
h := md5.New()
h.Write([]byte(name))
h.Write([]byte(serialNumber))
sn = hex.EncodeToString(h.Sum(nil))
}
if sn == gopay.NULL {
return gopay.NULL, errors.New("failed to get sn,please check your cert")
}
return sn, nil
}

// GetRootCertSN 获取root证书序列号SN
// rootCertPathOrData x509证书文件路径(alipayRootCert.crt) 或文件 buffer
// 返回 sn:证书序列号(alipay_root_cert_sn)
// 返回 err:error 信息
func GetRootCertSN(rootCertPathOrData any) (sn string, err error) {
var (
certData []byte
certEnd = `-----END CERTIFICATE-----`
)
switch pathOrData := rootCertPathOrData.(type) {
case string:
certData, err = os.ReadFile(pathOrData)
if err != nil {
return gopay.NULL, err
}
case []byte:
certData = pathOrData
default:
return gopay.NULL, errors.New("rootCertPathOrData 断言异常")
}

pems := strings.Split(string(certData), certEnd)
for _, c := range pems {
if block, _ := pem.Decode([]byte(c + certEnd)); block != nil {
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
continue
}
if !allowSignatureAlgorithm[cert.SignatureAlgorithm.String()] {
continue
}
name := cert.Issuer.String()
serialNumber := cert.SerialNumber.String()
h := md5.New()
h.Write([]byte(name))
h.Write([]byte(serialNumber))
if sn == gopay.NULL {
sn += hex.EncodeToString(h.Sum(nil))
} else {
sn += "_" + hex.EncodeToString(h.Sum(nil))
}
}
}
if sn == gopay.NULL {
return gopay.NULL, errors.New("failed to get sn,please check your cert")
}
return sn, nil
}
104 changes: 104 additions & 0 deletions alipay/v3/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package alipay

import (
"crypto/rsa"
"fmt"
"time"

"github.com/go-pay/crypto/xpem"
"github.com/go-pay/crypto/xrsa"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/xhttp"
"github.com/go-pay/xlog"
)

// ClientV3 支付宝 V3
type ClientV3 struct {
AppId string
AppCertSN string
AliPayPublicCertSN string
AliPayRootCertSN string
AppAuthToken string
IsProd bool
aesKey string // biz_content 加密的 AES KEY
ivKey []byte
privateKey *rsa.PrivateKey
aliPayPublicKey *rsa.PublicKey // 支付宝证书公钥内容 alipayPublicCert.crt
DebugSwitch gopay.DebugSwitch
logger xlog.XLogger
requestIdFunc xhttp.RequestIdHandler
location *time.Location
hc *xhttp.Client
}

// NewClientV3 初始化支付宝客户端 V3
// appid:应用ID
// privateKey:应用私钥,支持PKCS1和PKCS8
// isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。
func NewClientV3(appid, privateKey string, isProd bool) (client *ClientV3, err error) {
if appid == gopay.NULL || privateKey == gopay.NULL {
return nil, gopay.MissAlipayInitParamErr
}
key := xrsa.FormatAlipayPrivateKey(privateKey)
priKey, err := xpem.DecodePrivateKey([]byte(key))
if err != nil {
return nil, err
}
logger := xlog.NewLogger()
logger.SetLevel(xlog.DebugLevel)
client = &ClientV3{
AppId: appid,
IsProd: isProd,
privateKey: priKey,
DebugSwitch: gopay.DebugOff,
logger: logger,
requestIdFunc: defaultRequestIdFunc,
hc: xhttp.NewClient(),
}
return client, nil
}

// 设置自定义RequestId生成函数
func (a *ClientV3) SetRequestIdFunc(requestIdFunc xhttp.RequestIdHandler) {
if requestIdFunc != nil {
a.requestIdFunc = requestIdFunc
}
}

// 应用公钥证书内容设置 app_cert_sn、alipay_root_cert_sn、alipay_cert_sn
// appCertContent:应用公钥证书文件内容
// alipayRootCertContent:支付宝根证书文件内容
// alipayPublicCertContent:支付宝公钥证书文件内容
func (a *ClientV3) SetCert(appCertContent, alipayRootCertContent, alipayPublicCertContent []byte) (err error) {
appCertSn, err := GetCertSN(appCertContent)
if err != nil {
return fmt.Errorf("get app_cert_sn return err, but alse return alipay client. err: %w", err)
}
rootCertSn, err := GetRootCertSN(alipayRootCertContent)
if err != nil {
return fmt.Errorf("get alipay_root_cert_sn return err, but alse return alipay client. err: %w", err)
}
publicCertSn, err := GetCertSN(alipayPublicCertContent)
if err != nil {
return fmt.Errorf("get alipay_cert_sn return err, but alse return alipay client. err: %w", err)
}

// alipay public key
pubKey, err := xpem.DecodePublicKey(alipayPublicCertContent)
if err != nil {
return fmt.Errorf("decode alipayPublicCertContent err: %w", err)
}

a.AppCertSN = appCertSn
a.AliPayRootCertSN = rootCertSn
a.AliPayPublicCertSN = publicCertSn
a.aliPayPublicKey = pubKey
return nil
}

// SetAESKey 设置 biz_content 的AES加密key,设置此参数默认开启 biz_content 参数加密
// 注意:目前不可用,设置后会报错
func (a *ClientV3) SetAESKey(aesKey string) {
a.aesKey = aesKey
a.ivKey = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}
45 changes: 45 additions & 0 deletions alipay/v3/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package alipay

import (
"context"
"os"
"testing"

"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay/cert"
"github.com/go-pay/xlog"
)

var (
ctx = context.Background()
client *ClientV3
err error
)

func TestMain(m *testing.M) {
xlog.SetLevel(xlog.DebugLevel)
// 初始化支付宝客户端
// appid:应用ID
// privateKey:应用私钥,支持PKCS1和PKCS8
// isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。
client, err = NewClientV3(cert.Appid, cert.PrivateKey, false)
if err != nil {
xlog.Error(err)
return
}
// Debug开关,输出/关闭日志
client.DebugSwitch = gopay.DebugOn

// 设置biz_content加密KEY,设置此参数默认开启加密(目前不可用,设置后会报错)
//client.SetAESKey("KvKUTqSVZX2fUgmxnFyMaQ==")

// 传入证书内容
err := client.SetCert(cert.AppPublicContent, cert.AlipayRootContent, cert.AlipayPublicContentRSA2)
// 传入证书文件路径
//err := client.SetCertSnByPath("cert/appPublicCert.crt", "cert/alipayRootCert.crt", "cert/alipayPublicCert.crt")
if err != nil {
xlog.Debug("SetCert:", err)
return
}
os.Exit(m.Run())
}
Loading

0 comments on commit 4e7edf1

Please sign in to comment.