paygate-ruby 0.1.8 → 0.2.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.
@@ -1,133 +1,136 @@
1
- require 'base64'
2
-
3
- module Paygate
4
- class AesCtr
5
-
6
- # Encrypt a text using AES encryption in Counter mode of operation
7
- #
8
- # Unicode multi-byte character safe
9
- #
10
- # @param string plaintext Source text to be encrypted
11
- # @param string password The password to use to generate a key
12
- # @param int num_bits Number of bits to be used in the key (128, 192, or 256)
13
- # @returns string Encrypted text
14
- def self.encrypt(plaintext, password, num_bits)
15
- block_size = 16 # block size fixed at 16 bytes / 128 bits (Nb=4) for AES
16
- return '' unless num_bits.in?([128, 192, 256])
17
-
18
- # use AES itself to encrypt password to get cipher key (using plain password as source for key
19
- # expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use)
20
- num_bytes = num_bits / 8 # no bytes in key (16/24/32)
21
- pw_bytes = []
22
- 0.upto(num_bytes - 1){ |i| pw_bytes[i] = password.bytes.to_a[i] & 0xff || 0} # use 1st 16/24/32 chars of password for key #warn
23
- key = Aes.cipher(pw_bytes, Aes.key_expansion(pw_bytes)) # gives us 16-byte key
24
- key = key + key[0, num_bytes - 16] # expand key to 16/24/32 bytes long
25
-
26
- # initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec,
27
- # [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106
28
- counter_block = []
29
- nonce = Time.now.to_i
30
- nonce_ms = nonce % 1000
31
- nonce_sec = (nonce / 1000.0).floor
32
- nonce_rand = (rand() * 0xffff).floor
33
- 0.upto(1){ |i| counter_block[i] = urs(nonce_ms, i * 8) & 0xff }
34
- 0.upto(1){ |i| counter_block[i + 2] = urs(nonce_rand, i * 8) & 0xff }
35
- 0.upto(3){ |i| counter_block[i + 4] = urs(nonce_sec, i * 8) & 0xff }
36
-
37
- # and convert it to a string to go on the front of the ciphertext
38
- ctr_text = ''
39
- 0.upto(7){ |i| ctr_text += counter_block[i].chr }
40
-
41
- # generate key schedule - an expansion of the key into distinct Key Rounds for each round
42
- key_schedule = Aes.key_expansion(key)
43
- block_count = (plaintext.length / block_size.to_f).ceil
44
-
45
- cipher_text = []
46
- 0.upto(block_count - 1) do |b|
47
- # set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
48
- # done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
49
- 0.upto(3){ |c| counter_block[15 - c] = urs(b, c * 8) & 0xff }
50
- 0.upto(3){ |c| counter_block[15 - c - 4] = urs(b / 0x100000000, c * 8) }
51
-
52
- cipher_cntr = Aes.cipher(counter_block, key_schedule) # -- encrypt counter block --
53
- # block size is reduced on final block
54
- block_length = b < block_count - 1 ? block_size : (plaintext.length - 1) % block_size + 1
55
- cipher_char = []
56
- 0.upto(block_length - 1) do |i|
57
- cipher_char[i] = (cipher_cntr[i] ^ plaintext.bytes.to_a[b * block_size + i]).chr
58
- end
59
- cipher_text[b] = cipher_char.join
60
- end
61
-
62
- cipher_text = ctr_text + cipher_text.join
63
- cipher_text = Base64.encode64(cipher_text).gsub(/\n/, '') + "\n"; # encode in base64
64
- end
65
-
66
- # Decrypt a text encrypted by AES in counter mode of operation
67
- #
68
- # @param string ciphertext Source text to be encrypted
69
- # @param string password The password to use to generate a key
70
- # @param int nBits Number of bits to be used in the key (128, 192, or 256)
71
- # @returns string
72
- # Decrypted text
73
- def self.decrypt(ciphertext, password, nBits)
74
- blockSize = 16 # block size fixed at 16 bytes / 128 bits (Nb=4) for AES
75
- return '' unless(nBits==128 || nBits==192 || nBits==256)
76
- ciphertext = Base64.decode64(ciphertext);
77
-
78
- nBytes = nBits/8 # no bytes in key (16/24/32)
79
- pwBytes = []
80
- 0.upto(nBytes-1){|i| pwBytes[i] = password.bytes.to_a[i] & 0xff || 0}
81
- key = Aes.cipher(pwBytes, Aes.key_expansion(pwBytes)) # gives us 16-byte key
82
- key = key.concat(key.slice(0, nBytes-16)) # expand key to 16/24/32 bytes long
83
- # recover nonce from 1st 8 bytes of ciphertext
84
- counterBlock = []
85
- ctrTxt = ciphertext[0,8]
86
- 0.upto(7){|i| counterBlock[i] = ctrTxt.bytes.to_a[i]}
87
-
88
- #generate key Schedule
89
- keySchedule = Aes.key_expansion(key);
90
-
91
- # separate ciphertext into blocks (skipping past initial 8 bytes)
92
- nBlocks = ((ciphertext.length-8)/blockSize.to_f).ceil
93
- ct=[]
94
- 0.upto(nBlocks-1){|b|ct[b] = ciphertext[8+b*blockSize, 16]}
95
-
96
- ciphertext = ct; # ciphertext is now array of block-length strings
97
-
98
- # plaintext will get generated block-by-block into array of block-length strings
99
- plaintxt = [];
100
- 0.upto(nBlocks-1) do |b|
101
- 0.upto(3){|c| counterBlock[15-c] = urs(b,c*8) & 0xff}
102
- 0.upto(3){|c| counterBlock[15-c-4] = urs((b+1)/(0x100000000-1),c*8) & 0xff}
103
- cipherCntr = Aes.cipher(counterBlock, keySchedule) # encrypt counter block
104
- plaintxtByte = []
105
- 0.upto(ciphertext[b].length - 1) do |i|
106
- # -- xor plaintxt with ciphered counter byte-by-byte --
107
- plaintxtByte[i] = (cipherCntr[i] ^ ciphertext[b].bytes.to_a[i]).chr;
108
- end
109
- plaintxt[b] = plaintxtByte.join('')
110
- end
111
- plaintext = plaintxt.join('')
112
- end
113
-
114
- private
115
-
116
- # Unsigned right shift function, since Ruby has neither >>> operator nor unsigned ints
117
- #
118
- # @param a number to be shifted (32-bit integer)
119
- # @param b number of bits to shift a to the right (0..31)
120
- # @return a right-shifted and zero-filled by b bits
121
- def self.urs(a, b)
122
- a &= 0xffffffff
123
- b &= 0x1f
124
- if a & 0x80000000 && b > 0 # if left-most bit set
125
- a = ((a >> 1) & 0x7fffffff) # right-shift one bit & clear left-most bit
126
- a = a >> (b - 1) # remaining right-shifts
127
- else # otherwise
128
- a = (a >> b); # use normal right-shift
129
- end
130
- a
131
- end
132
- end
133
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Paygate
6
+ class AesCtr
7
+ # Encrypt a text using AES encryption in Counter mode of operation
8
+ #
9
+ # Unicode multi-byte character safe
10
+ #
11
+ # @param string plaintext Source text to be encrypted
12
+ # @param string password The password to use to generate a key
13
+ # @param int num_bits Number of bits to be used in the key (128, 192, or 256)
14
+ # @returns string Encrypted text
15
+ def self.encrypt(plaintext, password, num_bits)
16
+ block_size = 16 # block size fixed at 16 bytes / 128 bits (Nb=4) for AES
17
+ return '' unless [128, 192, 256].include?(num_bits)
18
+
19
+ # use AES itself to encrypt password to get cipher key (using plain password as source for key
20
+ # expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use)
21
+ num_bytes = num_bits / 8 # no bytes in key (16/24/32)
22
+ pw_bytes = []
23
+ # use 1st 16/24/32 chars of password for key #warn
24
+ 0.upto(num_bytes - 1) do |i|
25
+ pw_bytes[i] = (password.bytes.to_a[i] & 0xff) || 0
26
+ end
27
+ key = Aes.cipher(pw_bytes, Aes.key_expansion(pw_bytes)) # gives us 16-byte key
28
+ key += key[0, num_bytes - 16] # expand key to 16/24/32 bytes long
29
+
30
+ # initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec,
31
+ # [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106
32
+ counter_block = []
33
+ nonce = Time.now.to_i
34
+ nonce_ms = nonce % 1000
35
+ nonce_sec = (nonce / 1000.0).floor
36
+ nonce_rand = (rand * 0xffff).floor
37
+ 0.upto(1) { |i| counter_block[i] = urs(nonce_ms, i * 8) & 0xff }
38
+ 0.upto(1) { |i| counter_block[i + 2] = urs(nonce_rand, i * 8) & 0xff }
39
+ 0.upto(3) { |i| counter_block[i + 4] = urs(nonce_sec, i * 8) & 0xff }
40
+
41
+ # and convert it to a string to go on the front of the ciphertext
42
+ ctr_text = ''
43
+ 0.upto(7) { |i| ctr_text += counter_block[i].chr }
44
+
45
+ # generate key schedule - an expansion of the key into distinct Key Rounds for each round
46
+ key_schedule = Aes.key_expansion(key)
47
+ block_count = (plaintext.length / block_size.to_f).ceil
48
+
49
+ cipher_text = []
50
+ 0.upto(block_count - 1) do |b|
51
+ # set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
52
+ # done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
53
+ 0.upto(3) { |c| counter_block[15 - c] = urs(b, c * 8) & 0xff }
54
+ 0.upto(3) { |c| counter_block[15 - c - 4] = urs(b / 0x100000000, c * 8) }
55
+
56
+ cipher_cntr = Aes.cipher(counter_block, key_schedule) # -- encrypt counter block --
57
+ # block size is reduced on final block
58
+ block_length = b < block_count - 1 ? block_size : ((plaintext.length - 1) % block_size) + 1
59
+ cipher_char = []
60
+ 0.upto(block_length - 1) do |i|
61
+ cipher_char[i] = (cipher_cntr[i] ^ plaintext.bytes.to_a[(b * block_size) + i]).chr
62
+ end
63
+ cipher_text[b] = cipher_char.join
64
+ end
65
+
66
+ cipher_text = ctr_text + cipher_text.join
67
+ "#{Base64.encode64(cipher_text).delete("\n")}\n" # encode in base64
68
+ end
69
+
70
+ # Decrypt a text encrypted by AES in counter mode of operation
71
+ #
72
+ # @param string ciphertext Source text to be encrypted
73
+ # @param string password The password to use to generate a key
74
+ # @param int n_bits Number of bits to be used in the key (128, 192, or 256)
75
+ # @returns string
76
+ # Decrypted text
77
+ def self.decrypt(ciphertext, password, n_bits)
78
+ block_size = 16 # block size fixed at 16 bytes / 128 bits (Nb=4) for AES
79
+ return '' unless [128, 192, 256].include?(n_bits)
80
+
81
+ ciphertext = Base64.decode64(ciphertext)
82
+
83
+ n_bytes = n_bits / 8 # no bytes in key (16/24/32)
84
+ pw_bytes = []
85
+ 0.upto(n_bytes - 1) { |i| pw_bytes[i] = (password.bytes.to_a[i] & 0xff) || 0 }
86
+ key = Aes.cipher(pw_bytes, Aes.key_expansion(pw_bytes)) # gives us 16-byte key
87
+ key.concat(key.slice(0, n_bytes - 16)) # expand key to 16/24/32 bytes long
88
+ # recover nonce from 1st 8 bytes of ciphertext
89
+ counter_block = []
90
+ ctr_txt = ciphertext[0, 8]
91
+ 0.upto(7) { |i| counter_block[i] = ctr_txt.bytes.to_a[i] }
92
+
93
+ # generate key Schedule
94
+ key_schedule = Aes.key_expansion(key)
95
+
96
+ # separate ciphertext into blocks (skipping past initial 8 bytes)
97
+ n_blocks = ((ciphertext.length - 8) / block_size.to_f).ceil
98
+ ct = []
99
+ 0.upto(n_blocks - 1) { |b| ct[b] = ciphertext[8 + (b * block_size), 16] }
100
+
101
+ ciphertext = ct; # ciphertext is now array of block-length strings
102
+
103
+ # plaintext will get generated block-by-block into array of block-length strings
104
+ plaintxt = []
105
+ 0.upto(n_blocks - 1) do |b|
106
+ 0.upto(3) { |c| counter_block[15 - c] = urs(b, c * 8) & 0xff }
107
+ 0.upto(3) { |c| counter_block[15 - c - 4] = urs((b + 1) / (0x100000000 - 1), c * 8) & 0xff }
108
+ cipher_cntr = Aes.cipher(counter_block, key_schedule) # encrypt counter block
109
+ plaintxt_byte = []
110
+ 0.upto(ciphertext[b].length - 1) do |i|
111
+ # -- xor plaintxt with ciphered counter byte-by-byte --
112
+ plaintxt_byte[i] = (cipher_cntr[i] ^ ciphertext[b].bytes.to_a[i]).chr
113
+ end
114
+ plaintxt[b] = plaintxt_byte.join
115
+ end
116
+ plaintxt.join
117
+ end
118
+
119
+ # Unsigned right shift function, since Ruby has neither >>> operator nor unsigned ints
120
+ #
121
+ # @param a number to be shifted (32-bit integer)
122
+ # @param b number of bits to shift a to the right (0..31)
123
+ # @return a right-shifted and zero-filled by b bits
124
+ def self.urs(a, b)
125
+ a &= 0xffffffff
126
+ b &= 0x1f
127
+ if (a & 0x80000000) && b.positive? # if left-most bit set
128
+ a = ((a >> 1) & 0x7fffffff) # right-shift one bit & clear left-most bit
129
+ a = a >> (b - 1) # remaining right-shifts
130
+ else # otherwise
131
+ a = (a >> b); # use normal right-shift
132
+ end
133
+ a
134
+ end
135
+ end
136
+ end
@@ -1,16 +1,20 @@
1
- module Paygate
2
- class Configuration
3
- MODES = %i(live sandbox).freeze
4
-
5
- attr_reader :mode
6
-
7
- def initialize
8
- @mode = :live
9
- end
10
-
11
- def mode=(value)
12
- fail 'Invalid mode. Value must be one of the following: :live, :sandbox' unless value && MODES.include?(value.to_sym)
13
- @mode = value.to_sym
14
- end
15
- end
16
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Paygate
4
+ class Configuration
5
+ MODES = %i[live sandbox].freeze
6
+
7
+ attr_reader :mode
8
+
9
+ def initialize
10
+ @mode = :live
11
+ end
12
+
13
+ def mode=(value)
14
+ value = value.to_sym
15
+ raise 'Invalid mode. Value must be one of the following: :live, :sandbox' unless value && MODES.include?(value)
16
+
17
+ @mode = value
18
+ end
19
+ end
20
+ end
@@ -1,21 +1,24 @@
1
- module Paygate
2
- class Member
3
- attr_reader :mid, :secret
4
-
5
- def initialize(mid, secret)
6
- @mid, @secret = mid, secret
7
- end
8
-
9
- def refund_transaction(txn_id, options = {})
10
- txn = Transaction.new(txn_id)
11
- txn.member = self
12
- txn.refund(options)
13
- end
14
-
15
- def profile_pay(profile_no, currency, amount)
16
- profile = Profile.new(profile_no)
17
- profile.member = self
18
- profile.purchase(currency, amount)
19
- end
20
- end
21
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Paygate
4
+ class Member
5
+ attr_reader :mid, :secret
6
+
7
+ def initialize(mid, secret)
8
+ @mid = mid
9
+ @secret = secret
10
+ end
11
+
12
+ def refund_transaction(txn_id, options = {})
13
+ txn = Transaction.new(txn_id)
14
+ txn.member = self
15
+ txn.refund(options)
16
+ end
17
+
18
+ def profile_pay(profile_no, currency, amount)
19
+ profile = Profile.new(profile_no)
20
+ profile.member = self
21
+ profile.purchase(currency, amount)
22
+ end
23
+ end
24
+ end
@@ -1,30 +1,33 @@
1
- require 'uri'
2
- require 'net/http'
3
-
4
- module Paygate
5
- class Profile
6
- PURCHASE_URL = 'https://service.paygate.net/INTL/pgtlProcess3.jsp'.freeze
7
-
8
- attr_reader :profile_no
9
- attr_accessor :member
10
-
11
- def initialize(profile_no)
12
- @profile_no = profile_no
13
- end
14
-
15
- def purchase(currency, amount)
16
- # Prepare params
17
- params = { profile_no: profile_no,
18
- mid: member.mid,
19
- goodcurrency: currency,
20
- unitprice: amount }.delete_if { |_, v| v.blank? }
21
-
22
- # Make request
23
- uri = URI(PURCHASE_URL)
24
- uri.query = ::URI.encode_www_form(params)
25
- response = ::Net::HTTP.get_response(uri)
26
-
27
- Response.build_from_net_http_response(:profile_pay, response)
28
- end
29
- end
30
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'net/http'
5
+
6
+ module Paygate
7
+ class Profile
8
+ PURCHASE_URL = 'https://service.paygate.net/INTL/pgtlProcess3.jsp'
9
+
10
+ attr_reader :profile_no
11
+ attr_accessor :member
12
+
13
+ def initialize(profile_no)
14
+ @profile_no = profile_no
15
+ end
16
+
17
+ def purchase(currency, amount)
18
+ # Prepare params
19
+ params = { profile_no: profile_no,
20
+ mid: member.mid,
21
+ goodcurrency: currency,
22
+ unitprice: amount }
23
+ params.compact!
24
+
25
+ # Make request
26
+ uri = URI(PURCHASE_URL)
27
+ uri.query = ::URI.encode_www_form(params)
28
+ response = ::Net::HTTP.get_response(uri)
29
+
30
+ Response.build_from_net_http_response(:profile_pay, response)
31
+ end
32
+ end
33
+ end
@@ -1,25 +1,27 @@
1
- module Paygate
2
- class Response
3
- attr_accessor :transaction_type, :http_code, :message, :body, :raw_info, :json
4
-
5
- def self.build_from_net_http_response(txn_type, response)
6
- r = new
7
- r.transaction_type = txn_type
8
- r.http_code = response.code
9
- r.message = response.message
10
- r.body = response.body
11
-
12
- case txn_type
13
- when :refund
14
- r.json = JSON.parse response.body.gsub(/^callback\((.*)\)$/, '\1') if response.code.to_i == 200
15
- when :profile_pay
16
- r.json = {}
17
- response.body.split('&').each do |key_value_pair|
18
- key_value_ary = key_value_pair.split('=')
19
- r.json[key_value_ary[0]] = key_value_ary[1]
20
- end
21
- end
22
- r
23
- end
24
- end
25
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Paygate
4
+ class Response
5
+ attr_accessor :transaction_type, :http_code, :message, :body, :raw_info, :json
6
+
7
+ def self.build_from_net_http_response(txn_type, response)
8
+ r = new
9
+ r.transaction_type = txn_type
10
+ r.http_code = response.code
11
+ r.message = response.message
12
+ r.body = response.body
13
+
14
+ case txn_type
15
+ when :refund
16
+ r.json = JSON.parse response.body.gsub(/^callback\((.*)\)$/, '\1') if response.code.to_i == 200
17
+ when :profile_pay
18
+ r.json = {}
19
+ response.body.split('&').each do |key_value_pair|
20
+ key_value_ary = key_value_pair.split('=')
21
+ r.json[key_value_ary[0]] = key_value_ary[1]
22
+ end
23
+ end
24
+ r
25
+ end
26
+ end
27
+ end
@@ -1,58 +1,60 @@
1
- require 'digest'
2
- require 'uri'
3
- require 'net/http'
4
-
5
- module Paygate
6
- class Transaction
7
- FULL_AMOUNT_IDENTIFIER = 'F'.freeze
8
-
9
- attr_reader :tid
10
- attr_accessor :member
11
-
12
- def initialize(tid)
13
- @tid = tid
14
- end
15
-
16
- def refund(options = {})
17
- # Encrypt data
18
- api_key_256 = ::Digest::SHA256.hexdigest(member.secret)
19
- aes_ctr = AesCtr.encrypt(tid, api_key_256, 256)
20
- tid_enc = "AES256#{aes_ctr}"
21
-
22
- # Prepare params
23
- params = { callback: 'callback', mid: member.mid, tid: tid_enc }
24
- params.merge!(options.slice(:amount))
25
- params[:amount] ||= FULL_AMOUNT_IDENTIFIER
26
- params[:mb_serial_no] = options[:order_id]
27
- params.delete_if { |_, v| v.blank? }
28
-
29
- # Make request
30
- uri = URI(self.class.refund_api_url)
31
- uri.query = ::URI.encode_www_form(params)
32
- response = ::Net::HTTP.get_response(uri)
33
-
34
- r = Response.build_from_net_http_response(:refund, response)
35
- r.raw_info = OpenStruct.new(tid: tid, tid_enc: tid_enc, request_url: uri.to_s)
36
- r
37
- end
38
-
39
- # Doc: https://km.paygate.net/pages/viewpage.action?pageId=9207875
40
- def verify
41
- params = { tid: tid, verifyNum: 100 }
42
-
43
- uri = URI('https://service.paygate.net/djemals/settle/verifyReceived.jsp')
44
- uri.query = ::URI.encode_www_form(params)
45
- response = ::Net::HTTP.get_response(uri)
46
-
47
- Response.build_from_net_http_response(:verify, response)
48
- end
49
-
50
- private
51
-
52
- def self.refund_api_url
53
- (Paygate.configuration.mode == :live) ?
54
- 'https://service.paygate.net/service/cancelAPI.json' :
55
- 'https://stgsvc.paygate.net/service/cancelAPI.json'
56
- end
57
- end
58
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'uri'
5
+ require 'net/http'
6
+
7
+ module Paygate
8
+ class Transaction
9
+ FULL_AMOUNT_IDENTIFIER = 'F'
10
+
11
+ attr_reader :tid
12
+ attr_accessor :member
13
+
14
+ def initialize(tid)
15
+ @tid = tid
16
+ end
17
+
18
+ def refund(options = {})
19
+ # Encrypt data
20
+ api_key256 = ::Digest::SHA256.hexdigest(member.secret)
21
+ aes_ctr = AesCtr.encrypt(tid, api_key256, 256)
22
+ tid_enc = "AES256#{aes_ctr}"
23
+
24
+ # Prepare params
25
+ params = { callback: 'callback', mid: member.mid, tid: tid_enc }
26
+ params.merge!(options.slice(:amount))
27
+ params[:amount] ||= FULL_AMOUNT_IDENTIFIER
28
+ params[:mb_serial_no] = options[:order_id]
29
+ params.compact!
30
+
31
+ # Make request
32
+ uri = URI(self.class.refund_api_url)
33
+ uri.query = ::URI.encode_www_form(params)
34
+ response = ::Net::HTTP.get_response(uri)
35
+
36
+ r = Response.build_from_net_http_response(:refund, response)
37
+ r.raw_info = OpenStruct.new(tid: tid, tid_enc: tid_enc, request_url: uri.to_s) # rubocop:disable Style/OpenStructUse
38
+ r
39
+ end
40
+
41
+ # Doc: https://km.paygate.net/pages/viewpage.action?pageId=9207875
42
+ def verify
43
+ params = { tid: tid, verifyNum: 100 }
44
+
45
+ uri = URI('https://service.paygate.net/djemals/settle/verifyReceived.jsp')
46
+ uri.query = ::URI.encode_www_form(params)
47
+ response = ::Net::HTTP.get_response(uri)
48
+
49
+ Response.build_from_net_http_response(:verify, response)
50
+ end
51
+
52
+ def self.refund_api_url
53
+ if Paygate.configuration.mode == :live
54
+ 'https://service.paygate.net/service/cancelAPI.json'
55
+ else
56
+ 'https://stgsvc.paygate.net/service/cancelAPI.json'
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,5 @@
1
- module Paygate
2
- VERSION = '0.1.8'
3
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Paygate
4
+ VERSION = '0.2.0'
5
+ end