unionpei 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|