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 +5 -5
- data/README.md +4 -0
- data/lib/most_ots/models/base.rb +20 -0
- data/lib/most_ots/models/response.rb +5 -0
- data/lib/most_ots/service.rb +121 -74
- data/lib/most_ots/version.rb +1 -1
- data/most_ots.gemspec +1 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 82a7bdbc23f446162b0a1bfaff3610bf8eb84572
|
4
|
+
data.tar.gz: 26aa1c644c27c17a1967584cadc19a6b36e95d94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed089c5f4a2c654fc535c47705061d232e405d18b352b8282d4e9926b809ac5b3e8fb7a87c2d391d2c3215792d7b93ac6209e962afde244a558091dd389e06f5
|
7
|
+
data.tar.gz: ccc96f86ee0c10df7ed37a722fd9625510d88c871fbb8915444e7c3b59aa29aa30b4d2053a971e1d95815235c12e6bc6b30084d0f5e1946ee5a93d2661d15a16
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# MostMoneyOts
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/most_ots) [](https://travis-ci.org/ssxenon01/most_ots)
|
4
|
+
[](https://codeclimate.com/github/ssxenon01/most_ots/maintainability)
|
5
|
+
[](https://codebeat.co/projects/github-com-ssxenon01-most_ots-master)
|
6
|
+
[](http://inch-ci.org/github/ssxenon01/most_ots)
|
7
|
+
[](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
|
data/lib/most_ots/service.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
api_request('/api/mapi/TT3051',
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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 [
|
88
|
+
# @param [Hash] params
|
89
|
+
# @return [JSON] response
|
82
90
|
def purchase_tan(params)
|
83
91
|
logger.debug('MostOts Service Purchase Tan Called')
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
101
|
-
rsa
|
102
|
-
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(
|
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
|
121
|
+
params = encrypt_params(params)
|
116
122
|
headers = {
|
117
|
-
'Content-Type'
|
118
|
-
:Accept
|
123
|
+
'Content-Type' => 'application/json',
|
124
|
+
:Accept => 'application/json',
|
119
125
|
'Accept-Charset' => 'utf-8',
|
120
|
-
:TT
|
121
|
-
:RS
|
122
|
-
'User-Agent'
|
123
|
-
:PV
|
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 #{
|
126
|
-
|
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
|
-
|
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(
|
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
|
data/lib/most_ots/version.rb
CHANGED
data/most_ots.gemspec
CHANGED
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.
|
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-
|
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.
|
145
|
+
rubygems_version: 2.6.13
|
130
146
|
signing_key:
|
131
147
|
specification_version: 4
|
132
148
|
summary: Most Money External Protocol
|