tonglian-ruby-sdk 0.1.1 → 0.3.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tonglian-ruby-sdk.rb +95 -8
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49ce7186f7a279006ad84373d7953bd427a5a6ee02d75a89f3badba8d270adc8
4
- data.tar.gz: cac13ca36e52d2c23f4d6dd3fa335a4fa4b42291e5144884041b9ca2ee66b6a4
3
+ metadata.gz: 7f4d54ded35c1a345b7c1523f59e561e70d08d6bad618e2c83a14d33ab532065
4
+ data.tar.gz: d37d2482450c7a156674fe5ec2b71e5b69eb415ee949aaea55392068113357c1
5
5
  SHA512:
6
- metadata.gz: 57319941384bfb56c30c4a439b00970dc17120dc6c4c7f4538006d5051bf42901ccab770284179afeffd9ca403917a9102e87a490599e7e691d0a7be663e1a09
7
- data.tar.gz: d68bc1ace21cae2b279eee74776be06ab01214862872c81379c06a2ba2762b953625ac24805d5202205d1857be63b14fe9ab15cfa9524714afa2a4f23e62787b
6
+ metadata.gz: 8d3afc6f5ad630dae3dfca5346a196493c7ef3ed217a862dc2946e766515434e8bef43bc22d4b21339d57f9df122f2e939f50af5ca4167e2ee0fbabe5f584557
7
+ data.tar.gz: f82d4d303edf28781dfa7f86bc0df7ead862f6dcb14dda96bfa00e775128f8088346ff8be1aa14a364e0c84dbded75be3eaf6ac60ea4acd91c9bd9673db803c7
@@ -5,8 +5,57 @@ require 'openssl'
5
5
  require 'cgi'
6
6
  require 'digest'
7
7
  require 'base64'
8
+ require 'net/http'
9
+ require 'active_support/all'
8
10
 
9
11
  module TonglianRubySdk
12
+ # Client class to handle request and responses to and from Tonglian gateway
13
+ class Client
14
+ REQUEST_STUB = {
15
+ 'charset' => 'utf-8',
16
+ 'format' => 'JSON',
17
+ 'signType' => 'SHA256WithRSA',
18
+ 'version' => '1.0'
19
+ }.freeze
20
+
21
+ def initialize(api_end_point, app_id, private_path, private_passwd, public_path)
22
+ @api_end_point = api_end_point
23
+ @app_id = app_id
24
+ @signer = Signer.new(private_path, private_passwd, public_path)
25
+ end
26
+
27
+ def request(method, params)
28
+ data = REQUEST_STUB.dup
29
+ data['appId'] = @app_id
30
+ data['method'] = method
31
+ data['timestamp'] = timestamp
32
+ data['bizContent'] = params.to_json
33
+ data['sign'] = @signer.sign(data)
34
+
35
+ url = URI(@api_end_point)
36
+ http = Net::HTTP.new(url.host, url.port)
37
+ http.use_ssl = true if @api_end_point.downcase.starts_with?('https') # Enable SSL for HTTPS
38
+
39
+ request = Net::HTTP::Post.new(url.request_uri)
40
+ request['Content-Type'] = 'application/x-www-form-urlencoded'
41
+ request.body = URI.encode_www_form(data)
42
+ response = http.request(request)
43
+
44
+ object = JSON.parse(response.body)
45
+ @signer.verify?(object) || raise('Invalid response signature!')
46
+ { 'code' => response.code, 'data' => object }
47
+ end
48
+
49
+ private
50
+
51
+ def timestamp
52
+ timezone = ActiveSupport::TimeZone.new('Asia/Shanghai')
53
+ current_time = Time.now.in_time_zone(timezone)
54
+ current_time.strftime('%Y-%m-%d %H:%M:%S')
55
+ end
56
+ end
57
+
58
+ # To sign client request message and verify tonglian's response message
10
59
  class Signer
11
60
  def initialize(private_path, private_passwd, public_path)
12
61
  @private_path = private_path
@@ -15,34 +64,72 @@ module TonglianRubySdk
15
64
  end
16
65
 
17
66
  def sign(params)
18
- str = make_sign_message(params)
19
- private_file = File.open(@private_path)
20
- private_key = OpenSSL::PKCS12.new(private_file, @private_passwd).key.export
67
+ message = make_sign_message(params)
21
68
  rsa = OpenSSL::PKey::RSA.new private_key
22
- Base64.encode64(rsa.sign('sha1', str.force_encoding('UTF-8')))
69
+ Base64.strict_encode64(rsa.sign(OpenSSL::Digest.new('SHA256'), message))
23
70
  end
24
71
 
25
72
  def verify?(params, signature = nil)
26
73
  signature = params['sign'] if signature.nil? || signature.to_s.empty?
27
- str = make_sign_message(params)
74
+ params.delete('sign')
75
+ message = make_verify_message(params)
76
+
28
77
  public_file = File.open(@public_path)
29
78
  public_key = OpenSSL::X509::Certificate.new(public_file).public_key.export
30
79
  rsa = OpenSSL::PKey::RSA.new(public_key)
31
- rsa.verify('sha1', Base64.decode64(signature), str)
80
+ rsa.verify(OpenSSL::Digest.new('SHA256'), Base64.decode64(signature), message)
32
81
  end
33
82
 
34
83
  private
35
84
 
85
+ def private_key
86
+ return @private_key if @private_key
87
+
88
+ private_file = File.open(@private_path)
89
+ @private_key = OpenSSL::PKCS12.new(private_file, @private_passwd).key.export
90
+ end
91
+
92
+ def public_key
93
+ return @public_key if @public_key
94
+
95
+ public_file = File.open(@public_path)
96
+ @public_key = OpenSSL::X509::Certificate.new(public_file).public_key.export
97
+ end
98
+
36
99
  def make_sign_message(params)
37
100
  sorted_params = []
38
101
  params.keys.sort.map do |k|
39
102
  next if %w[sign signType].include? k
40
103
  next if params[k].nil? || params[k].to_s.empty?
41
104
 
42
- sorted_params.push("#{k}=#{CGI.escape(params[k])}")
105
+ sorted_params.push("#{k}=#{params[k]}")
43
106
  end
44
107
 
45
- Base64.encode64(Digest::MD5.hexdigest(sorted_params.join('&')))
108
+ flattened_params = sorted_params.join('&')
109
+ md5_digest = Digest::MD5.digest(flattened_params)
110
+ Base64.strict_encode64(md5_digest)
111
+ end
112
+
113
+ def make_verify_message(params)
114
+ params = sort_object(params)
115
+ flattened_params = params.to_json
116
+ Base64.strict_encode64(Digest::MD5.digest(flattened_params))
117
+ end
118
+
119
+ # In Ruby 3, a hash preserves the order the keys are inserted
120
+ # So we can make a 'sorted' hash and generate a sorted json later
121
+ def sort_object(obj)
122
+ result = nil
123
+ if obj.is_a? Hash
124
+ result = {}
125
+ obj.keys.sort.each { |k| result[k] = sort_object(obj[k]) }
126
+ elsif obj.is_a? Array
127
+ result = []
128
+ obj.sort.each { |k| result.push(k) }
129
+ else
130
+ result = obj
131
+ end
132
+ result
46
133
  end
47
134
  end
48
135
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tonglian-ruby-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yi Zhang