most_ots 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: bd3e7c21684a590abd6f7805e99a3da0347b9d31b1e9e8cc6a3572cf2bb28e50
4
- data.tar.gz: 4bf3bd4c9c7bd62ef0a48f55b11aa56b6cdd7536213d6c7aaecfbe090e34d714
2
+ SHA1:
3
+ metadata.gz: 82a7bdbc23f446162b0a1bfaff3610bf8eb84572
4
+ data.tar.gz: 26aa1c644c27c17a1967584cadc19a6b36e95d94
5
5
  SHA512:
6
- metadata.gz: 3ed2e1c9aa454551e763de4346ec252efe59bc2e1bb9e5eca8b8839317e055ccc1b34bc2a2c491591f10201862553ce7227389637f416173dffa3a5646ba1fe6
7
- data.tar.gz: c2dee037cabf9068e39b78b547b77caac2214be402a2ad52c79ba60576d9f92f114e1bf79b7b2a447ef989ab914f296a220016b3d3c9051371a7d6f9514b84b8
6
+ metadata.gz: ed089c5f4a2c654fc535c47705061d232e405d18b352b8282d4e9926b809ac5b3e8fb7a87c2d391d2c3215792d7b93ac6209e962afde244a558091dd389e06f5
7
+ data.tar.gz: ccc96f86ee0c10df7ed37a722fd9625510d88c871fbb8915444e7c3b59aa29aa30b4d2053a971e1d95815235c12e6bc6b30084d0f5e1946ee5a93d2661d15a16
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # MostMoneyOts
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/most_ots.svg)](https://badge.fury.io/rb/most_ots) [![Build Status](https://travis-ci.org/ssxenon01/most_ots.svg?branch=master)](https://travis-ci.org/ssxenon01/most_ots)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/afbec1dd7a17291317f5/maintainability)](https://codeclimate.com/github/ssxenon01/most_ots/maintainability)
5
+ [![codebeat badge](https://codebeat.co/badges/d51c6f19-41bd-4778-9492-629a0601d40d)](https://codebeat.co/projects/github-com-ssxenon01-most_ots-master)
6
+ [![Inline docs](http://inch-ci.org/github/ssxenon01/most_ots.svg?branch=master)](http://inch-ci.org/github/ssxenon01/most_ots)
7
+ [![Dependency Status](https://beta.gemnasium.com/badges/github.com/ssxenon01/most_ots.svg)](https://beta.gemnasium.com/projects/github.com/ssxenon01/most_ots)
4
8
 
5
9
  [Most Money](https://customer.mostmoney.mn/index.aspx?page=content/uctrademerchant#content~share)
6
10
  External Protocol
@@ -0,0 +1,20 @@
1
+ module MostOts
2
+ class Base
3
+
4
+ def initialize(data)
5
+ @data = data
6
+ end
7
+
8
+ def method_missing(method_name, *args, &block)
9
+ if @data.key?(method_name)
10
+ @data[method_name]
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def respond_to_missing?(method_name, _include_private = false)
17
+ @data.key?(method_name)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module MostOts
2
+ class Response < Base
3
+
4
+ end
5
+ end
@@ -1,4 +1,3 @@
1
- require 'net/http'
2
1
  require 'json'
3
2
  require 'openssl'
4
3
  require 'base64'
@@ -6,86 +5,95 @@ require 'most_ots/logging'
6
5
  require 'httparty'
7
6
 
8
7
  module MostOts
9
- #
8
+ # Most Money HTTP Service Wrapper
10
9
  class Service
11
10
  include Logging
12
11
  # Fields that needs to be encrypted
13
12
  ENCRYPTED_FIELDS = %i[traceNo qrAccountNumber qrCode srcMsisdn tan].freeze
13
+ # Current Protocol Version
14
+ PROTOCOL_VERSION = '05'.freeze
14
15
 
15
- attr_accessor :cipher_key, :cipher_iv
16
+ # @return [String] 16byte key string
17
+ attr_accessor :cipher_key
18
+
19
+ # @return [Array] cipher IV binary
20
+ attr_accessor :cipher_iv
21
+
22
+ # Base Parameters
23
+ # @return [Hash]
24
+ attr_accessor :base_params
25
+
26
+ # Most Provided Public Key
27
+ # @return [File] or [String] certificate_string
28
+ attr_accessor :certificate
29
+
30
+ # Most API Endpoint
31
+ # @return [String] MOST Service HOST
32
+ attr_accessor :api_host
16
33
 
17
34
  # @param [Hash] options
18
35
  def initialize(options = {})
19
36
  logger.debug('MostOts Service API Initializing')
20
- @base_params = {
21
- lang: options.fetch(:lang) { '0' },
22
- srcInstId: options.fetch(:src_inst_id) { ENV['SRC_INST_ID'] }
23
- }
24
- @protocol_version = options.fetch(:protocol_version) { '05' }
25
- @most_cert_file = options.fetch(:most_cert_file)
26
- @api_host = options.fetch(:host) { 'http://202.131.242.165:9089' }
27
-
28
- @payee_id = options[:payee_id] if options.key?(:payee_id)
29
- @qr_bank_code = options[:qr_bank_code] if options.key?(:qr_bank_code)
30
- @qr_account_name = options[:qr_account_name] if options.key?(:qr_account_name)
31
- @qr_account_number = options[:qr_account_number] if options.key?(:qr_account_number)
32
- @tran_cur = options[:tran_cur] if options.key?(:tran_cur)
33
- @pos_no = options[:pos_no] if options.key?(:pos_no)
34
- @base_params[:channel] = options[:channel] if options.key?(:channel)
35
- @base_params[:device_mac] = options[:device_mac] if options.key?(:device_mac)
36
- @base_params[:device_ip] = options[:device_ip] if options.key?(:device_ip)
37
- @base_params[:device_name] = options[:device_name] if options.key?(:device_name)
38
- @cipher_key = options[:cipher_key]
39
- @cipher_iv = options.fetch(:cipher_iv)
40
-
41
- @user_agent = "most_ots/#{VERSION} ruby/#{RUBY_VERSION}"
42
- @user_agent << " #{options[:app_name]}/#{options[:app_version]}" if options.key?(:app_name) && options.key?(:app_version)
37
+ setup_base_params(options)
38
+ self.certificate = options.fetch(:most_cert_file)
39
+ self.api_host = options.fetch(:host) { 'http://202.131.242.165:9089' }
40
+ self.cipher_key = options[:cipher_key]
41
+ self.cipher_iv = options.fetch(:cipher_iv)
43
42
  end
44
43
 
44
+ # @param [Hash] params
45
+ # @return [JSON] response
45
46
  def purchase_qr(params)
46
47
  logger.debug('MostOts Service Purchase QR Called')
47
- base = {}
48
- base[:payeeId] = @payee_id unless @payee_id.nil?
49
- base[:posNo] = @pos_no unless @pos_no.nil?
50
- base[:tranCur] = @tran_cur unless @tran_cur.nil?
51
- api_request('/api/mapi/TT3051', base.merge(params))
48
+ # Mandatory Fields
49
+ mf = %i[srcInstId channel lang traceNo payeeId posNo tranAmount tranCur tranDesc]
50
+ # Optional Fields
51
+ of = %i[billId deviceIP deviceMac deviceName qrPaidLimit]
52
+ api_request('/api/mapi/TT3051', configure_params(params, mf, of))
52
53
  end
53
54
 
55
+ # @param [Hash] params
56
+ # @return [JSON] response
54
57
  def transfer_qr(params)
55
58
  logger.debug('MostOts Service Transfer QR Called')
56
- base = {}
57
- base[:qrBankCode] = @qr_bank_code unless @qr_bank_code.nil?
58
- base[:qrAccountName] = @qr_account_name unless @qr_account_name.nil?
59
- base[:qrAccountNumber] = @qr_account_number unless @qr_account_number.nil?
60
- base[:tranCur] = @tran_cur unless @tran_cur.nil?
61
- api_request('/api/mapi/TT3061', params)
59
+ # Mandatory Fields
60
+ mf = %i[srcInstId channel lang traceNo qrBankCode qrAccountName qrAccountNumber tranAmount tranCur]
61
+ # Optional Fields
62
+ of = %i[tranDesc]
63
+ api_request('/api/mapi/TT3061', configure_params(params, mf, of))
62
64
  end
63
65
 
66
+ # @param [Hash] params
67
+ # @return [JSON] response
64
68
  def wait_payment_response(params)
65
69
  logger.debug('MostOts Service Waiting Payment Response')
66
- base = {}
67
- base[:payeeId] = @payee_id unless @payee_id.nil?
68
- base[:posNo] = @pos_no unless @pos_no.nil?
69
- api_request('/api/mapi/TT3064', params)
70
+ # Mandatory Fields
71
+ mf = %i[srcInstId channel lang qrBankCode qrAccountName qrAccountNumber tranAmount tranCur]
72
+ # Optional Fields
73
+ of = %i[tranDesc]
74
+ api_request('/api/mapi/TT3064', configure_params(params, mf, of))
70
75
  end
71
76
 
77
+ # @param [Hash] params
78
+ # @return [JSON] response
72
79
  def check_qr_payment(params)
73
80
  logger.debug('MostOts Service Check QR Payment Called')
74
- base = {}
75
- base[:payeeId] = @payee_id unless @payee_id.nil?
76
- base[:posNo] = @pos_no unless @pos_no.nil?
77
- base[:tranCur] = @tran_cur unless @tran_cur.nil?
78
- api_request('/api/mapi/TT3065', params)
81
+ # Mandatory Fields
82
+ mf = %i[srcInstId channel lang traceNo qrCode payeeId posNo billId isCheckQr]
83
+ # Optional Fields
84
+ of = %i[deviceIP deviceMac deviceName]
85
+ api_request('/api/mapi/TT3065', configure_params(params, mf, of))
79
86
  end
80
87
 
81
- # @param [Object] params
88
+ # @param [Hash] params
89
+ # @return [JSON] response
82
90
  def purchase_tan(params)
83
91
  logger.debug('MostOts Service Purchase Tan Called')
84
- base = {}
85
- base[:payeeId] = @payee_id unless @payee_id.nil?
86
- base[:posNo] = @pos_no unless @pos_no.nil?
87
- base[:tranCur] = @tran_cur unless @tran_cur.nil?
88
- api_request('/api/mapi/TT1608', params)
92
+ # Mandatory Fields
93
+ mf = %i[srcInstId channel lang traceNo payeeId posNo srcMsisdn tan tranAmount tranCur]
94
+ # Optional Fields
95
+ of = %i[billId tranDesc deviceIP deviceMac deviceName]
96
+ api_request('/api/mapi/TT1608', configure_params(params, mf, of))
89
97
  end
90
98
 
91
99
  private
@@ -94,16 +102,14 @@ module MostOts
94
102
  # @param [Hash or String] data
95
103
  # @return [Hash] encrypted hash with signature
96
104
  def encrypt(data)
97
- data = JSON.generate(data) unless data.is_a?(String)
98
105
  cipher = OpenSSL::Cipher.new('AES-128-CBC')
99
106
  cipher.encrypt
100
- cipher.iv = @cipher_iv.pack('c*')
101
- rsa = OpenSSL::PKey::RSA.new @most_cert_file
102
- key = @cipher_key.nil? ? cipher.random_key : @cipher_key
103
- cipher.key = key
107
+ cipher.iv = cipher_iv.pack('c*')
108
+ rsa = OpenSSL::PKey::RSA.new certificate
109
+ cipher.key = cipher_key_string
104
110
  {
105
111
  SD: Base64.encode64("#{cipher.update(data)}#{cipher.final}"),
106
- EK: Base64.encode64(rsa.public_encrypt(key)),
112
+ EK: Base64.encode64(rsa.public_encrypt(cipher_key_string)),
107
113
  SG: Digest::SHA1.base64digest(data)
108
114
  }
109
115
  end
@@ -112,34 +118,75 @@ module MostOts
112
118
  # @param [Hash] params
113
119
  # @return [Object] response
114
120
  def api_request(path, params = nil)
115
- params = generate_params(params)
121
+ params = encrypt_params(params)
116
122
  headers = {
117
- 'Content-Type' => 'application/json',
118
- :Accept => 'application/json',
123
+ 'Content-Type' => 'application/json',
124
+ :Accept => 'application/json',
119
125
  'Accept-Charset' => 'utf-8',
120
- :TT => path.split('TT').last,
121
- :RS => '00',
122
- 'User-Agent' => @user_agent,
123
- :PV => @protocol_version
126
+ :TT => path.split('TT').last,
127
+ :RS => '00',
128
+ 'User-Agent' => user_agent,
129
+ :PV => PROTOCOL_VERSION
124
130
  }
125
- logger.debug("Service Called With endpoint #{@api_host}#{path} params: #{params}")
126
- logger.debug("headers: #{headers}")
127
- req = HTTParty.post(
128
- "#{@api_host}#{path}",
129
- body: params,
130
- headers: headers
131
- )
131
+ logger.debug("Service Called With endpoint #{api_host}#{path} params: #{params}")
132
+ req = HTTParty.post("#{api_host}#{path}", body: params, headers: headers)
132
133
  JSON.parse(req.body)
133
134
  end
134
135
 
136
+ def configure_params(params, mandatory_fields, optional_fields = [])
137
+ params = base_params.merge(params)
138
+ processed_params = {}
139
+ required = mandatory_fields.select { |mk| params[mk].nil? }
140
+ if required.any?
141
+ raise "Following mandatory Fields cannot be nil: #{required.join('.')}"
142
+ end
143
+ params.each do |k, v|
144
+ processed_params[k] = v if (mandatory_fields + optional_fields).include?(k) && !v.nil?
145
+ end
146
+ processed_params
147
+ end
148
+
135
149
  # @param [Hash] params
136
- def generate_params(params)
150
+ # @return [String] json_string
151
+ def encrypt_params(params)
137
152
  to_encrypt = {}
138
153
  ENCRYPTED_FIELDS.each do |encrypted_key|
139
154
  to_encrypt[encrypted_key] = params.delete(encrypted_key) if params.key?(encrypted_key)
140
155
  end
141
- JSON.generate(@base_params.merge(params).merge(encrypt(to_encrypt)))
156
+ JSON.generate(params.merge(encrypt(JSON.generate(to_encrypt))))
142
157
  end
143
158
 
159
+ # @param [Hash] options
160
+ # @return [Hash] base_params
161
+ def setup_base_params(options)
162
+ self.base_params = {
163
+ lang: options.fetch(:lang) { '0' },
164
+ srcInstId: options.fetch(:src_inst_id) { ENV['SRC_INST_ID'] },
165
+ channel: options[:channel],
166
+ deviceMac: options[:device_mac],
167
+ deviceIp: options[:device_ip],
168
+ deviceName: options[:device_name],
169
+ payeeId: options[:payee_id],
170
+ qrBankCode: options[:qr_bank_code],
171
+ qrAccountName: options[:qr_account_name],
172
+ qrAccountNumber: options[:qr_account_number],
173
+ tranCur: options[:tran_cur],
174
+ posNo: options[:pos_no]
175
+ }
176
+ end
177
+
178
+ # @return [String] 16 byte key string
179
+ def cipher_key_string
180
+ if cipher_key.nil?
181
+ cipher = OpenSSL::Cipher.new('AES-128-CBC')
182
+ cipher.encrypt
183
+ self.cipher_key = cipher.random_key
184
+ end
185
+ cipher_key
186
+ end
187
+
188
+ def user_agent
189
+ "most_ots/#{VERSION} ruby/#{RUBY_VERSION}"
190
+ end
144
191
  end
145
192
  end
@@ -1,3 +1,3 @@
1
1
  module MostOts
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
data/most_ots.gemspec CHANGED
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'bundler', '~> 1.16'
35
35
  spec.add_development_dependency 'rake', '~> 10.0'
36
36
  spec.add_development_dependency 'rspec', '~> 3.0'
37
+ spec.add_development_dependency 'ruby-jmeter', '~> 3.1'
37
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: most_ots
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gundsambuu Natsagdorj
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-26 00:00:00.000000000 Z
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby-jmeter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.1'
83
97
  description:
84
98
  email:
85
99
  - ssxenon01@gmail.com
@@ -103,6 +117,8 @@ files:
103
117
  - lib/most_ots/errors/error.rb
104
118
  - lib/most_ots/errors/server_error.rb
105
119
  - lib/most_ots/logging.rb
120
+ - lib/most_ots/models/base.rb
121
+ - lib/most_ots/models/response.rb
106
122
  - lib/most_ots/service.rb
107
123
  - lib/most_ots/version.rb
108
124
  - most_ots.gemspec
@@ -126,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
142
  version: '0'
127
143
  requirements: []
128
144
  rubyforge_project:
129
- rubygems_version: 2.7.4
145
+ rubygems_version: 2.6.13
130
146
  signing_key:
131
147
  specification_version: 4
132
148
  summary: Most Money External Protocol