unionpei 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/unionpei.rb +9 -0
- data/lib/unionpei/acp_sdk.ini +73 -0
- data/lib/unionpei/acp_service.rb +104 -0
- data/lib/unionpei/cert_util.rb +193 -0
- data/lib/unionpei/log_util.rb +82 -0
- data/lib/unionpei/payment.rb +42 -0
- data/lib/unionpei/sdk_config.rb +76 -0
- data/lib/unionpei/sdk_util.rb +350 -0
- data/lib/unionpei/version.rb +9 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3c36dce06744feba796985728071df04f0ddd51e44f7ad666a9c7e4bb7ff7004
|
4
|
+
data.tar.gz: 99bcbe8926142f141ca88553d6b23c5635c380e275336f1ff452edc62e34f5c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b28982c26e99784beebb5331fe113fba53264666f76661ab67fd20647679c67892266c3e21f5e43fdc73ca50314833f8717b68650bb1dd0e261c405059fcf691
|
7
|
+
data.tar.gz: d77a75a98af0f0d5dbbce5bac5f2e2780fcf022019306a4ed649c7710f8ef4cdd595264e63ed9b985eeb4e348f02ceb17a7779b68e766d5f749f0871631dbed3
|
data/lib/unionpei.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
;;;;;;;;;;;;;;SDK配置文件(证书方式签名);;;;;;;;;;;;;;;;
|
2
|
+
; 说明:
|
3
|
+
; 1. 使用时请删除后缀的“.证书”,并将此文件复制到根文件夹下替换原来的acp_sdk.ini。
|
4
|
+
; 2. 具体配置项请根据注释修改。
|
5
|
+
;
|
6
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
7
|
+
|
8
|
+
[acpsdk]
|
9
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址);;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
10
|
+
|
11
|
+
;;交易请求地址
|
12
|
+
acpsdk.frontTransUrl=https://gateway.test.95516.com/gateway/api/frontTransReq.do
|
13
|
+
acpsdk.backTransUrl=https://gateway.test.95516.com/gateway/api/backTransReq.do
|
14
|
+
acpsdk.singleQueryUrl=https://gateway.test.95516.com/gateway/api/queryTrans.do
|
15
|
+
acpsdk.batchTransUrl=https://gateway.test.95516.com/gateway/api/batchTrans.do
|
16
|
+
acpsdk.fileTransUrl=https://filedownload.test.95516.com/
|
17
|
+
acpsdk.appTransUrl=https://gateway.test.95516.com/gateway/api/appTransReq.do
|
18
|
+
acpsdk.cardTransUrl=https://gateway.test.95516.com/gateway/api/cardTransReq.do
|
19
|
+
|
20
|
+
;以下缴费产品使用,其余产品用不到
|
21
|
+
acpsdk.jfFrontTransUrl=https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
|
22
|
+
acpsdk.jfBackTransUrl=https://gateway.test.95516.com/jiaofei/api/backTransReq.do
|
23
|
+
acpsdk.jfSingleQueryUrl=https://gateway.test.95516.com/jiaofei/api/queryTrans.do
|
24
|
+
acpsdk.jfCardTransUrl=https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
|
25
|
+
acpsdk.jfAppTransUrl=https://gateway.test.95516.com/jiaofei/api/appTransReq.do
|
26
|
+
|
27
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
28
|
+
|
29
|
+
; 报文版本号,固定5.1.0,请勿改动
|
30
|
+
acpsdk.version=5.1.0
|
31
|
+
|
32
|
+
; 签名方式,证书方式固定01,请勿改动
|
33
|
+
acpsdk.signMethod=01
|
34
|
+
|
35
|
+
; 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
|
36
|
+
acpsdk.ifValidateCNName=false
|
37
|
+
|
38
|
+
; 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
|
39
|
+
acpsdk.ifValidateRemoteCert=false
|
40
|
+
|
41
|
+
;后台通知地址,填写后台接收银联前台通知的地址
|
42
|
+
acpsdk.backUrl=http://222.222.222.222:8080/backRcvResponse
|
43
|
+
|
44
|
+
;前台通知地址,填写后台接收银联后台通知的地址,必须外网能访问
|
45
|
+
acpsdk.frontUrl=http://localhost:8080/frontRcvResponse
|
46
|
+
|
47
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;入网测试环境签名证书配置 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
48
|
+
; 多证书的情况证书路径为代码指定,可不对此块做配置。
|
49
|
+
; 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
|
50
|
+
; 测试环境证书位于assets/测试环境证书/文件夹下,请复制到d:/certs文件夹。生产环境证书由业务部门邮件发送。
|
51
|
+
; windows样例:
|
52
|
+
acpsdk.signCert.path=certs/acp_test_sign.pfx
|
53
|
+
; linux样例(注意:在linux下读取证书需要保证证书有被应用读的权限)(后续其他路径配置也同此条说明)
|
54
|
+
;acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/ac00000000000001.pfx
|
55
|
+
|
56
|
+
; 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
|
57
|
+
acpsdk.signCert.pwd=000000
|
58
|
+
|
59
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;加密证书配置;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
60
|
+
; 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
|
61
|
+
acpsdk.encryptCert.path=certs/acp_test_enc.cer
|
62
|
+
|
63
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;验签证书配置;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
64
|
+
; 验签中级证书(证书位于assets/测试环境证书/文件夹下,请复制到d:/certs文件夹)
|
65
|
+
acpsdk.middleCert.path=certs/acp_test_middle.cer
|
66
|
+
; 验签根证书(证书位于assets/测试环境证书/文件夹下,请复制到d:/certs文件夹)
|
67
|
+
acpsdk.rootCert.path=certs/acp_test_root.cer
|
68
|
+
|
69
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;日志配置;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
70
|
+
; 日志打印路径,linux注意要有写权限
|
71
|
+
acpsdk.log.file.path=upacp_sdk_ruby.log
|
72
|
+
; 日志级别,debug级别会打印密钥,生产请用info或以上级别
|
73
|
+
acpsdk.log.level=DEBUG
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
require_relative 'log_util'
|
4
|
+
require_relative 'sdk_config'
|
5
|
+
require_relative 'sdk_util'
|
6
|
+
|
7
|
+
module UnionPei
|
8
|
+
class AcpService
|
9
|
+
def AcpService.sign(req, certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
10
|
+
SDKUtil.buildSignature(req, certPath, certPwd)
|
11
|
+
end
|
12
|
+
|
13
|
+
def AcpService.signByCertInfo(req, certPath, certPwd)
|
14
|
+
SDKUtil.buildSignature(req, certPath, certPwd)
|
15
|
+
end
|
16
|
+
|
17
|
+
def AcpService.signBySecureKey(req, secureKey)
|
18
|
+
SDKUtil.buildSignature(req, nil, nil, secureKey)
|
19
|
+
end
|
20
|
+
|
21
|
+
def AcpService.validate(resp)
|
22
|
+
SDKUtil.verify(resp)
|
23
|
+
end
|
24
|
+
|
25
|
+
def AcpService.validateBySecureKey(resp, secureKey)
|
26
|
+
SDKUtil.verifyBySecureKey(resp, secureKey)
|
27
|
+
end
|
28
|
+
|
29
|
+
def AcpService.post(params, url)
|
30
|
+
content = SDKUtil.createLinkString(params, false, true)
|
31
|
+
respString = SDKUtil.post(url, content)
|
32
|
+
resp = SDKUtil.parseQString(respString)
|
33
|
+
return resp
|
34
|
+
end
|
35
|
+
|
36
|
+
def AcpService.createAutoFormHtml(params, reqUrl)
|
37
|
+
return SDKUtil.createAutoFormHtml(params, reqUrl)
|
38
|
+
end
|
39
|
+
|
40
|
+
def AcpService.getCustomerInfo(customerInfo)
|
41
|
+
if(customerInfo == nil or customerInfo.length == 0)
|
42
|
+
return ""
|
43
|
+
end
|
44
|
+
return Base.encode64("{" + SDKUtil.createLinkString(customerInfo,false,false)+"}").gsub(/\n|\r/, '')
|
45
|
+
end
|
46
|
+
|
47
|
+
def AcpService.getCustomerInfoWithEncrypt(customerInfo)
|
48
|
+
if(customerInfo == nil or customerInfo.length == 0)
|
49
|
+
return ""
|
50
|
+
end
|
51
|
+
encryptedInfo = {}
|
52
|
+
for key in customerInfo.keys
|
53
|
+
if (key == 'phoneNo' or key == 'cvn2' or key == 'expired')
|
54
|
+
encryptedInfo[key] = customerInfo.delete(key)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if (encryptedInfo.length > 0)
|
58
|
+
encryptedInfo = SDKUtil.createLinkString(encryptedInfo, false, false)
|
59
|
+
encryptedInfo = AcpService.encryptData(encryptedInfo, SDKConfig.instance.encryptCertPath)
|
60
|
+
customerInfo['encryptedInfo'] = encryptedInfo
|
61
|
+
end
|
62
|
+
return Base64.encode64("{" + SDKUtil.createLinkString(customerInfo,false,false)+"}").gsub(/\n|\r/, '')
|
63
|
+
end
|
64
|
+
|
65
|
+
def AcpService.parseCustomerInfo(customerInfostr, certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
66
|
+
customerInfostr = Base64.decode64(customerInfostr)
|
67
|
+
customerInfostr = customerInfostr[1, customerInfostr.length-1]
|
68
|
+
customerInfo = SDKUtil.parseQString(customerInfostr)
|
69
|
+
if customerInfo['encryptedInfo']
|
70
|
+
encryptedInfoStr = customerInfo.delete('encryptedInfo')
|
71
|
+
encryptedInfoStr = AcpService.decryptData(encryptedInfoStr, certPath, certPwd)
|
72
|
+
encryptedInfo = SDKUtil.parseQString(encryptedInfoStr)
|
73
|
+
for key in encryptedInfo.keys
|
74
|
+
customerInfo[key] = encryptedInfo[key]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
return customerInfo
|
78
|
+
end
|
79
|
+
|
80
|
+
def AcpService.getEncryptCertId
|
81
|
+
return CertUtil.getEncryptCertId
|
82
|
+
end
|
83
|
+
|
84
|
+
def AcpService.encryptData(data, certPath=SDKConfig.instance.encryptCertPath)
|
85
|
+
return SDKUtil.encryptPub(data, certPath)
|
86
|
+
end
|
87
|
+
|
88
|
+
def AcpService.decryptData(data, certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
89
|
+
return SDKUtil.decryptPri(data, certPath, certPwd)
|
90
|
+
end
|
91
|
+
|
92
|
+
def AcpService.deCodeFileContent(params, fileDirectory)
|
93
|
+
return SDKUtil.deCodeFileContent(params, fileDirectory)
|
94
|
+
end
|
95
|
+
|
96
|
+
def AcpService.enCodeFileContent(path)
|
97
|
+
return SDKUtil.enCodeFileContent(path)
|
98
|
+
end
|
99
|
+
|
100
|
+
def AcpService.updateEncryptCert(params)
|
101
|
+
return SDKUtil.getEncryptCert(params)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
require_relative 'log_util'
|
4
|
+
require_relative 'sdk_config'
|
5
|
+
|
6
|
+
|
7
|
+
module UnionPei
|
8
|
+
UNIONPAY_CNNAME = "中国银联股份有限公司"
|
9
|
+
|
10
|
+
class Cert
|
11
|
+
attr_accessor :cert, :certId, :key
|
12
|
+
@certId
|
13
|
+
@key
|
14
|
+
@cert
|
15
|
+
end
|
16
|
+
|
17
|
+
class CertUtil
|
18
|
+
|
19
|
+
@@signCerts = {}
|
20
|
+
@@encryptCert = {}
|
21
|
+
@@verifyCerts = {} #5.0.0验签证书,key是certId
|
22
|
+
@@verifyCerts5_1_0 = {} #5.1.0验签证书,key是base64的证书内容
|
23
|
+
@@middleCert = nil
|
24
|
+
@@rootCert = nil
|
25
|
+
|
26
|
+
private
|
27
|
+
def CertUtil.initSignCert(certPath, certPwd)
|
28
|
+
if !certPath || !certPwd
|
29
|
+
LogUtil.info("signCertPath or signCertPwd is none, exit initSignCert")
|
30
|
+
return
|
31
|
+
end
|
32
|
+
LogUtil.info("读取签名证书……")
|
33
|
+
cert = Cert.new
|
34
|
+
file = IO.binread(certPath)
|
35
|
+
p12 = OpenSSL::PKCS12.new(file, certPwd)
|
36
|
+
cert.certId = p12.certificate.serial.to_s
|
37
|
+
cert.cert = p12.certificate
|
38
|
+
cert.key = p12.key
|
39
|
+
@@signCerts[certPath] = cert
|
40
|
+
LogUtil.info("签名证书读取成功,序列号:" + cert.certId)
|
41
|
+
end
|
42
|
+
|
43
|
+
def CertUtil.initEncryptCert(certPath=SDKConfig.instance.encryptCertPath)
|
44
|
+
if !certPath
|
45
|
+
LogUtil.info("encryptCertPath is none, exit initEncryptCert")
|
46
|
+
return
|
47
|
+
end
|
48
|
+
LogUtil.info("读取加密证书……")
|
49
|
+
cert = Cert.new
|
50
|
+
file = IO.binread(certPath)
|
51
|
+
x509Cert = OpenSSL::X509::Certificate.new(file)
|
52
|
+
cert.cert = x509Cert
|
53
|
+
cert.certId = x509Cert.serial.to_s
|
54
|
+
cert.key = x509Cert.public_key
|
55
|
+
@@encryptCert[certPath] = cert
|
56
|
+
LogUtil.info("加密证书读取成功,序列号:" + cert.certId)
|
57
|
+
end
|
58
|
+
|
59
|
+
def CertUtil.initRootCert()
|
60
|
+
if @@rootCert
|
61
|
+
return
|
62
|
+
end
|
63
|
+
if !SDKConfig.instance.rootCertPath
|
64
|
+
LogUtil.info("rootCertPath is none, exit initRootCert")
|
65
|
+
return
|
66
|
+
end
|
67
|
+
LogUtil.info("start initRootCert")
|
68
|
+
file = IO.binread(SDKConfig.instance.rootCertPath)
|
69
|
+
x509Cert = OpenSSL::X509::Certificate.new(file)
|
70
|
+
@@rootCert = x509Cert
|
71
|
+
LogUtil.info("initRootCert succeed")
|
72
|
+
end
|
73
|
+
|
74
|
+
def CertUtil.initMiddleCert()
|
75
|
+
if @@middleCert
|
76
|
+
return
|
77
|
+
end
|
78
|
+
if !SDKConfig.instance.middleCertPath
|
79
|
+
LogUtil.info("middleCertPath is none, exit initMiddleCert")
|
80
|
+
return
|
81
|
+
end
|
82
|
+
LogUtil.info("start initMiddleCert")
|
83
|
+
file = IO.binread(SDKConfig.instance.middleCertPath)
|
84
|
+
x509Cert = OpenSSL::X509::Certificate.new(file)
|
85
|
+
@@middleCert = x509Cert
|
86
|
+
LogUtil.info("initMiddleCert succeed")
|
87
|
+
end
|
88
|
+
|
89
|
+
public
|
90
|
+
def CertUtil.getSignPriKey(certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
91
|
+
if !@@signCerts[certPath]
|
92
|
+
CertUtil.initSignCert(certPath, certPwd)
|
93
|
+
end
|
94
|
+
@@signCerts[certPath].key
|
95
|
+
end
|
96
|
+
|
97
|
+
def CertUtil.getSignCertId(certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
98
|
+
if !@@signCerts[certPath]
|
99
|
+
CertUtil.initSignCert(certPath, certPwd)
|
100
|
+
end
|
101
|
+
@@signCerts[certPath].certId
|
102
|
+
end
|
103
|
+
|
104
|
+
def CertUtil.getEncryptKey(certPath=SDKConfig.instance.encryptCertPath)
|
105
|
+
if !@@encryptCert[certPath]
|
106
|
+
CertUtil.initEncryptCert(certPath)
|
107
|
+
end
|
108
|
+
@@encryptCert[certPath].key
|
109
|
+
end
|
110
|
+
|
111
|
+
def CertUtil.getEncryptCertId(certPath=SDKConfig.instance.encryptCertPath)
|
112
|
+
if !@@encryptCert[certPath]
|
113
|
+
CertUtil.initEncryptCert(certPath)
|
114
|
+
end
|
115
|
+
@@encryptCert[certPath].certId
|
116
|
+
end
|
117
|
+
|
118
|
+
def CertUtil.verifyAndGetVerifyKey(certBase64String)
|
119
|
+
|
120
|
+
if @@verifyCerts5_1_0[certBase64String]
|
121
|
+
return @@verifyCerts5_1_0[certBase64String].key
|
122
|
+
end
|
123
|
+
initMiddleCert
|
124
|
+
initRootCert
|
125
|
+
|
126
|
+
x509Cert = OpenSSL::X509::Certificate.new(certBase64String)
|
127
|
+
|
128
|
+
cert = Cert.new
|
129
|
+
cert.cert = x509Cert
|
130
|
+
cert.certId = x509Cert.serial.to_s
|
131
|
+
cert.key = x509Cert.public_key
|
132
|
+
|
133
|
+
store = OpenSSL::X509::Store.new
|
134
|
+
store.purpose = OpenSSL::X509::PURPOSE_ANY
|
135
|
+
store.add_cert(x509Cert)
|
136
|
+
store.add_cert(@@middleCert)
|
137
|
+
store.add_cert(@@rootCert)
|
138
|
+
if !store.verify(x509Cert)
|
139
|
+
LogUtil.error("validate signPubKeyCert by cert chain failed, error=" + store.error + ", error string=" + store.error_string)
|
140
|
+
return nil
|
141
|
+
end
|
142
|
+
|
143
|
+
sSubject = x509Cert.subject.to_s
|
144
|
+
ss = sSubject.split("@")
|
145
|
+
if ss.length <= 2
|
146
|
+
LogUtil.error("error sSubject: " + sSubject)
|
147
|
+
return nil
|
148
|
+
end
|
149
|
+
cn = ss[2];
|
150
|
+
if SDKConfig.instance.ifValidateCNName
|
151
|
+
if UNIONPAY_CNNAME != cn
|
152
|
+
LogUtil.error("cer owner is not CUP:" + cn)
|
153
|
+
return nil
|
154
|
+
elsif UNIONPAY_CNNAME != cn and cn != "00040000:SIGN" #测试环境目前是00040000:SIGN
|
155
|
+
LogUtil.error("cer owner is not CUP:" + cn)
|
156
|
+
return nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
LogUtil.info("validate signPubKeyCert by cert succeed: " + certBase64String)
|
161
|
+
@@verifyCerts5_1_0[certBase64String] = cert;
|
162
|
+
return @@verifyCerts5_1_0[certBase64String].key
|
163
|
+
|
164
|
+
# 用bc的jar用中级证书验证可以单独验时间,然后再用中级证书验一下,但为了和谐统一,目前改store验证书链验证了。
|
165
|
+
# if Time.new<x509Cert.not_before or Time.new>x509Cert.not_after
|
166
|
+
# LogUtil..info("verifyPubKeyCert has expired")
|
167
|
+
# return nil
|
168
|
+
# end
|
169
|
+
# if x509Cert.verify(@@middleKey)
|
170
|
+
# return x509Cert.public_key
|
171
|
+
# else
|
172
|
+
# LogUtil.info("validate signPubKeyCert by rootCert failed")
|
173
|
+
# return nil
|
174
|
+
# end
|
175
|
+
end
|
176
|
+
|
177
|
+
def CertUtil.getDecryptPriKey(certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
178
|
+
if !@@signCerts[certPath]
|
179
|
+
CertUtil.initSignCert(certPath, certPwd)
|
180
|
+
end
|
181
|
+
@@signCerts[certPath].key
|
182
|
+
end
|
183
|
+
|
184
|
+
def CertUtil.resetEncryptCertPublicKey()
|
185
|
+
@@encryptCert = {}
|
186
|
+
CertUtil.initEncryptCert
|
187
|
+
end
|
188
|
+
|
189
|
+
def CertUtil.getX509Cert(strCert)
|
190
|
+
OpenSSL::X509::Certificate.new(strCert)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'logger'
|
5
|
+
require 'net/https'
|
6
|
+
require 'uri'
|
7
|
+
require_relative 'sdk_config'
|
8
|
+
|
9
|
+
module UnionPei
|
10
|
+
class LogUtil
|
11
|
+
|
12
|
+
@@logger = nil
|
13
|
+
|
14
|
+
private_class_method :new
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def LogUtil.getLogger
|
19
|
+
if !@@logger
|
20
|
+
puts "init LogUtil"
|
21
|
+
if SDKConfig.instance.logFilePath.nil?
|
22
|
+
@@logger = Logger.new(STDOUT)
|
23
|
+
else
|
24
|
+
@@logger = Logger.new(SDKConfig.instance.logFilePath)
|
25
|
+
end
|
26
|
+
@@logger.datetime_format = '%Y-%m-%d %H:%M:%S'
|
27
|
+
@@logger.formatter = proc do |severity, datetime, progname, msg|
|
28
|
+
"#{datetime} [#{severity}] #{progname}: #{msg}\n"
|
29
|
+
end
|
30
|
+
@@logger.level = case SDKConfig.instance.logLevel.upcase
|
31
|
+
when 'INFO' then
|
32
|
+
Logger::INFO
|
33
|
+
when 'DEBUG' then
|
34
|
+
Logger::DEBUG
|
35
|
+
when 'WARN' then
|
36
|
+
Logger::WARN
|
37
|
+
when 'ERROR' then
|
38
|
+
Logger::ERROR
|
39
|
+
when 'FATAL' then
|
40
|
+
Logger::FATAL
|
41
|
+
else
|
42
|
+
Logger::UNKNOWN
|
43
|
+
end
|
44
|
+
end
|
45
|
+
p = LogUtil.parse_caller(caller(0)[2]) #可能有多线程问题?我才不管哼
|
46
|
+
@@logger.progname = p[0].to_s + ":" + p[1].to_s
|
47
|
+
@@logger
|
48
|
+
end
|
49
|
+
|
50
|
+
def LogUtil.parse_caller(at)
|
51
|
+
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
|
52
|
+
file = $1
|
53
|
+
line = $2.to_i
|
54
|
+
method = $3
|
55
|
+
[file, line, method]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
public
|
60
|
+
|
61
|
+
def LogUtil.info(msg)
|
62
|
+
LogUtil.getLogger.info(msg)
|
63
|
+
end
|
64
|
+
|
65
|
+
def LogUtil.debug(msg)
|
66
|
+
LogUtil.getLogger.debug(msg)
|
67
|
+
end
|
68
|
+
|
69
|
+
def LogUtil.warn(msg)
|
70
|
+
LogUtil.getLogger.warn(msg)
|
71
|
+
end
|
72
|
+
|
73
|
+
def LogUtil.error(msg)
|
74
|
+
LogUtil.getLogger.error(msg)
|
75
|
+
end
|
76
|
+
|
77
|
+
def LogUtil.fatal(msg)
|
78
|
+
LogUtil.getLogger.fatal(msg)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require "date"
|
3
|
+
require_relative 'sdk_config'
|
4
|
+
require_relative 'acp_service'
|
5
|
+
|
6
|
+
module UnionPei
|
7
|
+
class Payment
|
8
|
+
class << self
|
9
|
+
def B2C
|
10
|
+
req = {}
|
11
|
+
|
12
|
+
req["version"] = UnionPei::SDKConfig.instance.version
|
13
|
+
req["encoding"] = UnionPei::SDKConfig.instance.encoding
|
14
|
+
req["signMethod"] = UnionPei::SDKConfig.instance.signMethod
|
15
|
+
|
16
|
+
req["frontUrl"] = UnionPei::SDKConfig.instance.frontUrl
|
17
|
+
req["backUrl"] = UnionPei::SDKConfig.instance.backUrl
|
18
|
+
|
19
|
+
req["txnType"] = "01"
|
20
|
+
req["txnSubType"] = "01"
|
21
|
+
req["bizType"] = "000201" # 000201 是b2c / 000202 是 b2b
|
22
|
+
req["channelType"] = "07"
|
23
|
+
req["currencyCode"] = "156"
|
24
|
+
req["txnAmt"] = "881000"
|
25
|
+
|
26
|
+
req["merId"] = "777290058189920"
|
27
|
+
req["orderId"] = DateTime.parse(Time.now.to_s).strftime("%Y%m%d%H%M%S").to_s
|
28
|
+
req["txnTime"] = DateTime.parse(Time.now.to_s).strftime("%Y%m%d%H%M%S").to_s
|
29
|
+
req["accessType"] = "0"
|
30
|
+
|
31
|
+
#签名示例
|
32
|
+
UnionPei::AcpService.sign(req)
|
33
|
+
url = UnionPei::SDKConfig.instance.frontTransUrl
|
34
|
+
|
35
|
+
#前台自提交表单示例
|
36
|
+
resp = UnionPei::AcpService.createAutoFormHtml(req, url)
|
37
|
+
resp
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'iniparse'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
module UnionPei
|
7
|
+
class SDKConfig
|
8
|
+
include Singleton
|
9
|
+
attr_reader :frontTransUrl, :singleQueryUrl, :backTransUrl, :batchTransUrl, :fileTransUrl, :appTransUrl,
|
10
|
+
:cardTransUrl, :jfFrontTransUrl, :jfSingleQueryUrl, :jfBackTransUrl, :jfCardTransUrl,
|
11
|
+
:jfAppTransUrl, :qrcBackTransUrl, :qrcB2cIssBackTransUrl, :qrcB2cMerBackTransUrl,
|
12
|
+
:signMethod, :version, :ifValidateCNName, :ifValidateRemoteCert, :signCertPath, :signCertPwd,
|
13
|
+
:validateCertDir, :encryptCertPath, :rootCertPath, :middleCertPath, :frontUrl, :backUrl,
|
14
|
+
:encoding, :secureKey, :logFilePath, :logLevel
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
|
18
|
+
path = File.dirname(__FILE__)
|
19
|
+
ini = IniParse.parse(File.read("#{path}/acp_sdk.ini").force_encoding("UTF-8"))
|
20
|
+
puts 'load config: ' + "#{path}/acp_sdk.ini"
|
21
|
+
|
22
|
+
@frontTransUrl = ini["acpsdk"]["acpsdk.frontTransUrl"]
|
23
|
+
@singleQueryUrl = ini["acpsdk"]["acpsdk.singleQueryUrl"]
|
24
|
+
@backTransUrl = ini["acpsdk"]["acpsdk.backTransUrl"]
|
25
|
+
@batchTransUrl = ini["acpsdk"]["acpsdk.batchTransUrl"]
|
26
|
+
@fileTransUrl = ini["acpsdk"]["acpsdk.fileTransUrl"]
|
27
|
+
@appTransUrl = ini["acpsdk"]["acpsdk.appTransUrl"]
|
28
|
+
@cardTransUrl = ini["acpsdk"]["acpsdk.cardTransUrl"]
|
29
|
+
|
30
|
+
@jfFrontTransUrl = ini["acpsdk"]["acpsdk.jfFrontTransUrl"]
|
31
|
+
@jfSingleQueryUrl = ini["acpsdk"]["acpsdk.jfSingleQueryUrl"]
|
32
|
+
@jfBackTransUrl = ini["acpsdk"]["acpsdk.jfBackTransUrl"]
|
33
|
+
@jfCardTransUrl = ini["acpsdk"]["acpsdk.jfCardTransUrl"]
|
34
|
+
@jfAppTransUrl = ini["acpsdk"]["acpsdk.jfAppTransUrl"]
|
35
|
+
|
36
|
+
@qrcBackTransUrl = ini["acpsdk"]["acpsdk.qrcBackTransUrl"]
|
37
|
+
@qrcB2cIssBackTransUrl = ini["acpsdk"]["acpsdk.qrcB2cIssBackTransUrl"]
|
38
|
+
@qrcB2cMerBackTransUrl = ini["acpsdk"]["acpsdk.qrcB2cMerBackTransUrl"]
|
39
|
+
|
40
|
+
@signMethod = ini["acpsdk"]["acpsdk.signMethod"]
|
41
|
+
@signMethod = @signMethod.to_s if !@signMethod.nil?
|
42
|
+
@version = ini["acpsdk"]["acpsdk.version"]
|
43
|
+
@version = "5.0.0" if @version.nil?
|
44
|
+
|
45
|
+
@ifValidateCNName = ini["acpsdk"]["acpsdk.ifValidateCNName"]
|
46
|
+
@ifValidateCNName = true if @ifValidateCNName.nil?
|
47
|
+
@ifValidateRemoteCert = ini["acpsdk"]["acpsdk.ifValidateRemoteCert"]
|
48
|
+
@ifValidateRemoteCert = false if @ifValidateRemoteCert.nil?
|
49
|
+
|
50
|
+
@signCertPath = ini["acpsdk"]["acpsdk.signCert.path"]
|
51
|
+
@signCertPwd = ini["acpsdk"]["acpsdk.signCert.pwd"]
|
52
|
+
@signCertPwd = @signCertPwd.to_s if !@signCertPwd.nil?
|
53
|
+
|
54
|
+
@validateCertDir = ini["acpsdk"]["acpsdk.validateCert.dir"]
|
55
|
+
@encryptCertPath = ini["acpsdk"]["acpsdk.encryptCert.path"]
|
56
|
+
@rootCertPath = ini["acpsdk"]["acpsdk.rootCert.path"]
|
57
|
+
@middleCertPath = ini["acpsdk"]["acpsdk.middleCert.path"]
|
58
|
+
|
59
|
+
@frontUrl = ini["acpsdk"]["acpsdk.frontUrl"]
|
60
|
+
@backUrl = ini["acpsdk"]["acpsdk.backUrl"]
|
61
|
+
|
62
|
+
@encoding = ini["acpsdk"]["acpsdk.encoding"]
|
63
|
+
@secureKey = ini["acpsdk"]["acpsdk.secureKey"]
|
64
|
+
@secureKey = @secureKey.to_s if !@secureKey.nil?
|
65
|
+
|
66
|
+
@logFilePath = ini["acpsdk"]["acpsdk.log.file.path"]
|
67
|
+
@logLevel = ini["acpsdk"]["acpsdk.log.level"]
|
68
|
+
|
69
|
+
@encoding = 'UTF-8'
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
|
@@ -0,0 +1,350 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'logger'
|
3
|
+
require 'net/https'
|
4
|
+
require 'uri'
|
5
|
+
require 'base64'
|
6
|
+
require "zlib"
|
7
|
+
require_relative 'sdk_config'
|
8
|
+
require_relative 'cert_util'
|
9
|
+
|
10
|
+
|
11
|
+
module UnionPei
|
12
|
+
class SDKUtil
|
13
|
+
|
14
|
+
def SDKUtil.post(url, content)
|
15
|
+
LogUtil.info("post url:["+url+"]")
|
16
|
+
LogUtil.info("post content:["+content+"]")
|
17
|
+
uri = URI.parse(url)
|
18
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
19
|
+
http.use_ssl = true if uri.scheme == "https"
|
20
|
+
if !SDKConfig.instance.ifValidateRemoteCert
|
21
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
22
|
+
end
|
23
|
+
res = http.post(uri.path, content).body.force_encoding(SDKConfig.instance.encoding)
|
24
|
+
LogUtil.info('resp:['+res+']')
|
25
|
+
return res
|
26
|
+
end
|
27
|
+
|
28
|
+
def SDKUtil.createLinkString(para, sort, encode)
|
29
|
+
linkString = ""
|
30
|
+
keys = para.keys
|
31
|
+
if sort
|
32
|
+
keys = keys.sort
|
33
|
+
end
|
34
|
+
for key in keys
|
35
|
+
value = para[key]
|
36
|
+
# print(key + ":" + value)
|
37
|
+
if encode
|
38
|
+
value = URI.encode_www_form_component(value)
|
39
|
+
end
|
40
|
+
# print(str(type(key))+":"+str(type(value))+":"+str(key)+":"+str(value))
|
41
|
+
linkString = linkString + key + "=" + value + "&"
|
42
|
+
end
|
43
|
+
linkString = linkString[0, linkString.length - 1]
|
44
|
+
# print (linkString)
|
45
|
+
return linkString
|
46
|
+
end
|
47
|
+
|
48
|
+
def SDKUtil.filterNoneValue(para)
|
49
|
+
keys = para.keys
|
50
|
+
for key in keys
|
51
|
+
value = para[key]
|
52
|
+
if !value or value == ""
|
53
|
+
para.delete(key)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def SDKUtil.buildSignature(req, signCertPath=SDKConfig.instance.signCertPath, signCertPwd=SDKConfig.instance.signCertPwd, secureKey=SDKConfig.instance.secureKey)
|
59
|
+
|
60
|
+
SDKUtil.filterNoneValue(req)
|
61
|
+
if !req["signMethod"]
|
62
|
+
LogUtil.error("signMethod must not null")
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
if !req["version"]
|
66
|
+
LogUtil.error("version must not null")
|
67
|
+
return nil
|
68
|
+
end
|
69
|
+
if "01" == req["signMethod"]
|
70
|
+
req["certId"] = CertUtil.getSignCertId(signCertPath, signCertPwd)
|
71
|
+
LogUtil.info("=== start to sign ===")
|
72
|
+
prestr = SDKUtil.createLinkString(req, true, false)
|
73
|
+
LogUtil.info("sorted: [" + prestr + "]")
|
74
|
+
prestr = SDKUtil.sha256(prestr)
|
75
|
+
LogUtil.info("sha256: [" + prestr + "]")
|
76
|
+
LogUtil.info("sign cert: [" + signCertPath + "], pwd: [" + signCertPwd + "]")
|
77
|
+
key = CertUtil.getSignPriKey(signCertPath, signCertPwd)
|
78
|
+
signature = Base64.encode64(key.sign('sha256', prestr)).gsub(/\n|\r/, '')
|
79
|
+
LogUtil.info("signature: [" + signature + "]")
|
80
|
+
elsif "11" == req["signMethod"]
|
81
|
+
LogUtil.info("=== start to sign ===")
|
82
|
+
prestr = createLinkString(req, true, false)
|
83
|
+
LogUtil.info("sorted: [" + prestr + "]")
|
84
|
+
if secureKey.nil?
|
85
|
+
LogUtil.error("secureKey must not null")
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
prestr = prestr + "&" + sha256(secureKey)
|
89
|
+
LogUtil.debug("before final sha256: [" + prestr + "]")
|
90
|
+
signature = SDKUtil.sha256(prestr)
|
91
|
+
LogUtil.info("signature: [" + signature + "]")
|
92
|
+
elsif "12" == ["signMethod"]
|
93
|
+
LogUtil.error("sm3算法暂未实现,请勿使用。")
|
94
|
+
return nil
|
95
|
+
else
|
96
|
+
LogUtil.info("invalid signMethod: [" + req["signMethod"].to_s + "]")
|
97
|
+
end
|
98
|
+
LogUtil.info("=== end of sign ===")
|
99
|
+
req["signature"] = signature
|
100
|
+
return signature
|
101
|
+
end
|
102
|
+
|
103
|
+
def SDKUtil.paraFilter(para)
|
104
|
+
result = {}
|
105
|
+
for key in para.keys
|
106
|
+
if (key == "signature" or para[key] == "")
|
107
|
+
next
|
108
|
+
else
|
109
|
+
result[key] = para[key]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return result
|
113
|
+
end
|
114
|
+
|
115
|
+
def SDKUtil.sha256(data)
|
116
|
+
OpenSSL::Digest::SHA256.digest(data).unpack("H*")[0].downcase
|
117
|
+
end
|
118
|
+
|
119
|
+
def SDKUtil.putKeyValueToMap(temp, isKey, key, m, decode)
|
120
|
+
if isKey
|
121
|
+
m[key.to_s] = ""
|
122
|
+
else
|
123
|
+
if decode
|
124
|
+
temp = URI.decode_www_form_component(temp)
|
125
|
+
end
|
126
|
+
m[key.to_s] = temp
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def SDKUtil.parseQString(respString, decode=false)
|
131
|
+
resp = {}
|
132
|
+
temp = ""
|
133
|
+
key = ""
|
134
|
+
isKey = true
|
135
|
+
isOpen = false;
|
136
|
+
openName = "\0";
|
137
|
+
|
138
|
+
for curChar in respString.split("") #遍历整个带解析的字符串
|
139
|
+
if (isOpen)
|
140
|
+
if (curChar == openName)
|
141
|
+
isOpen = false
|
142
|
+
end
|
143
|
+
temp = temp + curChar
|
144
|
+
elsif (curChar == "{")
|
145
|
+
isOpen = true
|
146
|
+
openName = "}"
|
147
|
+
temp = temp + curChar
|
148
|
+
elsif (curChar == "[")
|
149
|
+
isOpen = true
|
150
|
+
openName = "]"
|
151
|
+
temp = temp + curChar
|
152
|
+
elsif (isKey and curChar == "=")
|
153
|
+
key = temp
|
154
|
+
temp = ""
|
155
|
+
isKey = false
|
156
|
+
elsif (curChar == "&" and not isOpen) # 如果读取到&分割符
|
157
|
+
SDKUtil.putKeyValueToMap(temp, isKey, key, resp, decode)
|
158
|
+
temp = ""
|
159
|
+
isKey = true
|
160
|
+
else
|
161
|
+
temp = temp + curChar
|
162
|
+
end
|
163
|
+
end
|
164
|
+
SDKUtil.putKeyValueToMap(temp, isKey, key, resp, decode)
|
165
|
+
return resp
|
166
|
+
end
|
167
|
+
|
168
|
+
def SDKUtil.verify(resp)
|
169
|
+
if !resp["signMethod"]
|
170
|
+
LogUtil.error("signMethod must not null")
|
171
|
+
return nil
|
172
|
+
end
|
173
|
+
if !resp["version"]
|
174
|
+
LogUtil.error("version must not null")
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
if !resp["signature"]
|
178
|
+
LogUtil.error("signature must not null")
|
179
|
+
return nil
|
180
|
+
end
|
181
|
+
signMethod = resp["signMethod"]
|
182
|
+
version = resp["version"]
|
183
|
+
result = false
|
184
|
+
if "01" == signMethod
|
185
|
+
LogUtil.info("=== start to verify signature ===")
|
186
|
+
signature = resp.delete("signature")
|
187
|
+
LogUtil.info("signature: [" + signature + "]")
|
188
|
+
prestr = SDKUtil.createLinkString(resp, true, false)
|
189
|
+
LogUtil.info("sorted: [" + prestr + "]")
|
190
|
+
prestr = SDKUtil.sha256(prestr)
|
191
|
+
LogUtil.info("sha256: [" + prestr + "]")
|
192
|
+
key = CertUtil.verifyAndGetVerifyKey(resp["signPubKeyCert"])
|
193
|
+
if !key
|
194
|
+
LogUtil.info("no cert was found by signPubKeyCert: " + resp["signPubKeyCert"])
|
195
|
+
result = false
|
196
|
+
else
|
197
|
+
signature = Base64.decode64(signature)
|
198
|
+
result = key.verify("sha256", signature, prestr)
|
199
|
+
end
|
200
|
+
LogUtil.info("verify signature " + (result ? "succeed" : "fail"))
|
201
|
+
LogUtil.info("=== end of verify signature ===")
|
202
|
+
return result
|
203
|
+
elsif "11" == signMethod or "12" == signMethod
|
204
|
+
return SDKUtil.verifyBySecureKey(resp, SDKConfig.instance.secureKey)
|
205
|
+
else
|
206
|
+
LogUtil.info("Error signMethod [" + signMethod + "] in validate. ")
|
207
|
+
return false
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def SDKUtil.verifyBySecureKey(resp, secureKey)
|
212
|
+
if resp["signMethod"].nil?
|
213
|
+
LogUtil.error("signMethod must not null")
|
214
|
+
return nil
|
215
|
+
end
|
216
|
+
if resp["signature"].nil?
|
217
|
+
LogUtil.error("signature must not null")
|
218
|
+
return nil
|
219
|
+
end
|
220
|
+
signMethod = resp["signMethod"]
|
221
|
+
result = false
|
222
|
+
LogUtil.info("=== start to verify signature ===")
|
223
|
+
if "11" == signMethod
|
224
|
+
signature = resp.delete("signature")
|
225
|
+
LogUtil.info("signature: [" + signature+ "]")
|
226
|
+
prestr = createLinkString(resp, true, false)
|
227
|
+
LogUtil.info("sorted: [" + prestr + "]")
|
228
|
+
beforeSha256 = prestr + "&" + sha256(secureKey)
|
229
|
+
LogUtil.debug("before final sha256: [" + beforeSha256 + "]")
|
230
|
+
afterSha256 = sha256(beforeSha256)
|
231
|
+
result = (afterSha256 == signature)
|
232
|
+
if !result
|
233
|
+
LogUtil.debug("after final sha256: [" + afterSha256 + "]")
|
234
|
+
end
|
235
|
+
elsif "12" == signMethod
|
236
|
+
LogUtil.error("sm3算法暂未实现,请勿使用。")
|
237
|
+
else
|
238
|
+
LogUtil.info("Error signMethod [" + signMethod.to_s + "] in validate. ")
|
239
|
+
end
|
240
|
+
LogUtil.info("verify signature " + (result ? "succeed" : "fail"))
|
241
|
+
LogUtil.info("=== end of verify signature ===")
|
242
|
+
return result
|
243
|
+
end
|
244
|
+
|
245
|
+
def SDKUtil.createAutoFormHtml(params, reqUrl)
|
246
|
+
result = "<html><head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + SDKConfig.instance.encoding + "\" /></head><body onload=\"javascript:document.pay_form.submit();\"> <form id=\"pay_form\" name=\"pay_form\" action=\"" + reqUrl + "\" method=\"post\">"
|
247
|
+
for key in params.keys
|
248
|
+
value = params[key]
|
249
|
+
result += " <input type=\"hidden\" name=\"" + key + "\" id=\"" + key +"\" value=\""+ value +"\" />\n"
|
250
|
+
end
|
251
|
+
result += "<!-- <input type=\"submit\" type=\"hidden\">--> </form></body></html>"
|
252
|
+
LogUtil.info("auto post html:" + result)
|
253
|
+
return result
|
254
|
+
end
|
255
|
+
|
256
|
+
def SDKUtil.encryptPub(data, certPath=SDKConfig.instance.encryptCertPath)
|
257
|
+
rsaKey = CertUtil.getEncryptKey(certPath)
|
258
|
+
result = rsaKey.public_encrypt(data)
|
259
|
+
result = Base64.encode64(result).gsub(/\n|\r/, '')
|
260
|
+
return result
|
261
|
+
end
|
262
|
+
|
263
|
+
def SDKUtil.decryptPri(data, certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
|
264
|
+
pkey = CertUtil.getDecryptPriKey(certPath, certPwd)
|
265
|
+
data = Base64.decode64(data)
|
266
|
+
result = pkey.private_decrypt(data)
|
267
|
+
return result
|
268
|
+
end
|
269
|
+
|
270
|
+
def SDKUtil.deCodeFileContent(params, fileDirectory)
|
271
|
+
if !params["fileContent"]
|
272
|
+
return false
|
273
|
+
end
|
274
|
+
LogUtil.info("---------处理后台报文返回的文件---------")
|
275
|
+
fileContent = params["fileContent"]
|
276
|
+
if !fileContent
|
277
|
+
LogUtil.info("文件内容为空")
|
278
|
+
return false
|
279
|
+
end
|
280
|
+
fileContent = Zlib::Inflate.inflate(Base64.decode64(fileContent))
|
281
|
+
filePath = ''
|
282
|
+
if !params["fileName"]
|
283
|
+
LogUtil.info("文件名为空")
|
284
|
+
filePath = fileDirectory + "/" + params["merId"] + "_" + params["batchNo"] + "_" + params["txnTime"] + ".txt"
|
285
|
+
else
|
286
|
+
filePath = fileDirectory + "/" + params['fileName']
|
287
|
+
end
|
288
|
+
output = File.new(filePath, 'w')
|
289
|
+
if !output
|
290
|
+
LogUtil.error "Unable to open file!"
|
291
|
+
return false
|
292
|
+
end
|
293
|
+
output.syswrite(fileContent)
|
294
|
+
LogUtil.info "文件位置 >:" + filePath
|
295
|
+
output.close
|
296
|
+
return true
|
297
|
+
end
|
298
|
+
|
299
|
+
def SDKUtil.enCodeFileContent(path)
|
300
|
+
fileContent = IO.binread(path)
|
301
|
+
fileContent = Base64.encode64(Zlib::Deflate.deflate(fileContent)).gsub(/\n|\r/, '')
|
302
|
+
end
|
303
|
+
|
304
|
+
def SDKUtil.getEncryptCert(params)
|
305
|
+
if params['encryptPubKeyCert'].nil? or params['certType'].nil?
|
306
|
+
LogUtil.error("encryptPubKeyCert or certType is null")
|
307
|
+
return -1
|
308
|
+
end
|
309
|
+
strCert = params['encryptPubKeyCert']
|
310
|
+
certType = params['certType']
|
311
|
+
|
312
|
+
x509Cert = CertUtil.getX509Cert(strCert)
|
313
|
+
if "01" == certType
|
314
|
+
# 更新敏感信息加密公钥
|
315
|
+
if x509Cert.serial.to_s == CertUtil.getEncryptCertId
|
316
|
+
return 0
|
317
|
+
end
|
318
|
+
localCertPath = SDKConfig.instance.encryptCertPath
|
319
|
+
newLocalCertPath = SDKUtil.genBackupName(localCertPath)
|
320
|
+
# 将本地证书进行备份存储
|
321
|
+
File.rename(localCertPath, newLocalCertPath)
|
322
|
+
f = File.new(localCertPath, "w")
|
323
|
+
if !f
|
324
|
+
LogUtil.error 'Unable to open file!'
|
325
|
+
return -1
|
326
|
+
end
|
327
|
+
f.syswrite(strCert)
|
328
|
+
f.close
|
329
|
+
LogUtil.info('save new encryptPubKeyCert success')
|
330
|
+
CertUtil.resetEncryptCertPublicKey
|
331
|
+
return 1
|
332
|
+
elsif "02" == certType
|
333
|
+
return 0
|
334
|
+
else
|
335
|
+
LogUtil.error("unknown cerType:"+certType)
|
336
|
+
return -1
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def SDKUtil.genBackupName(fileName)
|
341
|
+
i = fileName.rindex('.')
|
342
|
+
leftFileName = fileName[0, i]
|
343
|
+
rightFileName = fileName[i + 1, fileName.length - i]
|
344
|
+
newFileName = leftFileName + '_backup' + '.' + rightFileName
|
345
|
+
return newFileName
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: unionpei
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shuang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: iniparse
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jruby-openssl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: An unofficial unionpay gem
|
42
|
+
email: memorycancel@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/unionpei.rb
|
48
|
+
- lib/unionpei/acp_sdk.ini
|
49
|
+
- lib/unionpei/acp_service.rb
|
50
|
+
- lib/unionpei/cert_util.rb
|
51
|
+
- lib/unionpei/log_util.rb
|
52
|
+
- lib/unionpei/payment.rb
|
53
|
+
- lib/unionpei/sdk_config.rb
|
54
|
+
- lib/unionpei/sdk_util.rb
|
55
|
+
- lib/unionpei/version.rb
|
56
|
+
homepage: https://rubygems.org/gems/unionpei
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.1.4
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: An unofficial unionpay gem
|
79
|
+
test_files: []
|