transbank-webpay 0.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe020196d892c3624a23ca1b34120e389f013066
4
- data.tar.gz: a5236458db9a18c0e89c0a9c93217504c6c605a7
3
+ metadata.gz: 7a89c6199367fd33bb85f9870e52153547414ad7
4
+ data.tar.gz: 63ec216618b2de32cd2af59ff1af1af205c64a96
5
5
  SHA512:
6
- metadata.gz: 172bf5d4851e558dab4e08705573539b34c8bb2a2ad75fd65930d133ebfedaf3d9fa0d80184e49a8ac4cb6c7410714b01a21ffd336114c090bdb82c511249f7d
7
- data.tar.gz: f3fbc82cd2a93e6197a3ccd9bc0a9e92f91eece03801236b1418f927e24751ab87d55710dc08079a39b5bd29837929435464060a4aa0932087c1530a3ee4da8f
6
+ metadata.gz: 15aa8ffba7bf1e939921501bf77576b6afc889e36d07c58007748607848fdb2ea76a6628c20061ca7cce0a74674fe499d4c77aa20c15d7f0414d1c0d6eae7683
7
+ data.tar.gz: 317322dd5edcf986a54a0bdfe8814ca22482c077efd414a2bd38aa469574da93e22f5454a46a7c1b1055a438ea733ec947585dc591130efd28489d1ed0b0b512
data/README.md CHANGED
@@ -1 +1,157 @@
1
- # Not ready for production
1
+ # Transbank::Webpay
2
+
3
+ Ruby Implementation of Transbank Webpay API SOAP
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'transbank-webpay'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install transbank-webpay
20
+
21
+ Run the generator:
22
+
23
+ $ rails generate transbank_webpay:install
24
+
25
+ ## Usage
26
+
27
+ **Init Transaction**
28
+
29
+ ```ruby
30
+ response = Transbank::Webpay.init_transaction({
31
+ buy_order: 'A1234567',
32
+ session_id: '123456',
33
+ return_url: 'http://web.com/return',
34
+ final_url: 'http://web.com/finalize',
35
+ amount: 12_000
36
+ })
37
+ => #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct token="12333b5bcd772565db2cbf36e88eafcca93a95dad29dd8bd6f44d6d37345", url="https://tbk-web.com/initTransactioninitTransaction">>
38
+ response.token
39
+ => "12333b5bcd772565db2cbf36e88eafcca93a95dad29dd8bd6f44d6d37345"
40
+ response.url
41
+ => "https://tbk-web.com/initTransaction"
42
+ response.valid?
43
+ => true
44
+ ```
45
+
46
+ **Get Transaction Result**
47
+
48
+ ```ruby
49
+ response = Transbank::Webpay.get_transaction_result(token)
50
+ => #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct accounting_date="0234", buy_order="A1234567", card_detail=#<Transbank::Webpay::Struct card_number=3456>, detail_output=#<Transbank::Webpay::Struct shares_number=0, amount=12000, commerce_code=237020000556, buy_order="A1234567", authorization_code=1234, payment_type_code="VN", response_code=0>, session_id=123456, transaction_date=Mon, 10 Jul 2016 10:00:00 -0400, url_redirection="https://tbk-web.com/filtroUnificado/voucher.cgi", vci="TSY">>
51
+ response.accounting_date
52
+ => "0234"
53
+ response.buy_order
54
+ => "A1234567"
55
+ response.card_detail.card_number
56
+ => 3456
57
+ response.detail_output.shares_number
58
+ => 0
59
+ response.detail_output.amount
60
+ => 12000
61
+ response.detail_output.commerce_code
62
+ => 237020000556
63
+ response.detail_output.buy_order
64
+ => "A1234567"
65
+ response.detail_output.authorization_code
66
+ => 1234
67
+ response.detail_output.payment_type_code
68
+ => "VN"
69
+ response.response_code
70
+ => 0
71
+ response.session_id
72
+ => 123456
73
+ response.transaction_date
74
+ => Mon, 10 Jul 2016 10:00:00 -0400
75
+ response.url_redirection
76
+ => "https://tbk-web.com/filtroUnificado/voucher.cgi"
77
+ response.vci
78
+ => "TSY"
79
+ response.valid?
80
+ => true
81
+ ```
82
+
83
+ **Acknowledge Transaction**
84
+
85
+ ```ruby
86
+ response = Transbank::Webpay.acknowledge_transaction(token)
87
+ => #< Transbank::Webpay::Response valid: true>
88
+ response.valid?
89
+ => true
90
+ ```
91
+
92
+ **Nullify**
93
+
94
+ ```ruby
95
+ Transbank::Webpay.nullify({
96
+ authorization_code: 1234,
97
+ authorized_amount: 12_000,
98
+ buy_order: 'A1234567',
99
+ nullify_amount: 12_000
100
+ })
101
+ => #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct authorization_code=1415234, authorization_date=Mon, 10 Jul 2016 10:00:00 -0400, balance=0, nullified_amount=12000, token="8743gr557f7037005a48487197b0539a021436dabaf485c4947c95347ba1dgdw78">>
102
+
103
+ response.authorization_code
104
+ => 1415234
105
+ response.authorization_date
106
+ => Mon, 10 Jul 2016 10:00:00 -0400
107
+ response.balance
108
+ => 0
109
+ response.nullified_amount
110
+ => 12000
111
+ response.token
112
+ => "8743gr557f7037005a48487197b0539a021436dabaf485c4947c95347ba1dgdw78"
113
+ response.valid?
114
+ => true
115
+ ```
116
+ **Available response methods:**
117
+
118
+
119
+ ```ruby
120
+ response.valid? # true or false if any errors occurred (exceptions included)
121
+ response.errors # errors array
122
+ response.errors_display? # errors for human
123
+ response.exception? # true or false if an exception occurred
124
+ response.exception # exception object
125
+ response.attributes # hash attributes response (token, reverse_code . . .)
126
+ ```
127
+
128
+ ## Configuration
129
+
130
+ First, you need to set up your configuration:
131
+
132
+ `rails generate transbank_webpay:install`
133
+
134
+ Then edit (config/initializers/transbank_webpay.rb):
135
+
136
+ ```ruby
137
+ Transbank::Webpay.configure do |config|
138
+ config.wsdl_transaction_url = 'WEBPAY_SOAP_URL'
139
+ config.wsdl_nullify_url = 'NULLIFY_WEBPAY_SOAP_URL'
140
+ config.cert_path = 'ABSOLUTE_PATH_TO_CRT_FILE'
141
+ config.key_path = 'ABSOLUTE_PATH_TO_KEY_FILE'
142
+ config.server_cert_path = 'ABSOLUTE_PATH_TO_SERVER_CRT_OR_PEM_FILE'
143
+ config.commerce_code = 'COMMERCE_CODE'
144
+ end
145
+ ```
146
+
147
+ ## Contributing
148
+
149
+ 1. Fork it ( https://github.com/[my-github-username]/transbank-webpay/fork )
150
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
151
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
152
+ 4. Push to the branch (`git push origin my-new-feature`)
153
+ 5. Create a new Pull Request
154
+
155
+ ## License
156
+
157
+ transbank-webpay is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,11 @@
1
+ module TransbankWebpay
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def generate_config_file
7
+ copy_file 'transbank_webpay.rb', 'config/initializers/transbank_webpay.rb'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ Transbank::Webpay.configure do |config|
2
+ config.wsdl_transaction_url = 'WEBPAY_SOAP_URL'
3
+ config.wsdl_nullify_url = 'NULLIFY_WEBPAY_SOAP_URL'
4
+ config.cert_path = 'ABSOLUTE_PATH_TO_CRT_FILE'
5
+ config.key_path = 'ABSOLUTE_PATH_TO_KEY_FILE'
6
+ config.server_cert_path = 'ABSOLUTE_PATH_TO_SERVER_CRT_OR_PEM_FILE'
7
+ config.commerce_code = 'COMMERCE_CODE'
8
+
9
+ # These are the default options for Net::HTTP
10
+ # config.http_options = { read_timeout: 80 }
11
+
12
+ # ignores any exception passed as argument
13
+ # not capture any exception: config.rescue_exceptions []
14
+ # Default is:
15
+ # [
16
+ # Net::ReadTimeout, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
17
+ # EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
18
+ # ]
19
+ # config.rescue_exceptions = [
20
+ # Net::ReadTimeout, Timeout::Error,
21
+ # Transbank::Webpay::Exceptions::InvalidSignature
22
+ # ]
23
+ end
@@ -1,12 +1,17 @@
1
1
  require 'net/https'
2
2
  require 'uri'
3
- require 'savon'
3
+ require 'nokogiri'
4
4
  require 'signer'
5
- require 'nori'
6
5
  require 'ostruct'
6
+ require 'builder'
7
7
 
8
8
  require 'transbank/webpay/version'
9
9
  require 'transbank/webpay/configuration'
10
+ require 'transbank/webpay/validations'
11
+ require 'transbank/webpay/struct'
12
+ require 'transbank/webpay/reader'
13
+ require 'transbank/webpay/exceptions'
14
+ require 'transbank/webpay/helper'
10
15
  require 'transbank/webpay/exception_response'
11
16
  require 'transbank/webpay/client'
12
17
  require 'transbank/webpay/response'
@@ -21,6 +21,12 @@ module Transbank
21
21
  Request.new(url, :acknowledge_transaction, params).response
22
22
  end
23
23
 
24
+ def nullify(underscore_params = {})
25
+ params = build_nullify_params(underscore_params)
26
+ url = config.wsdl_nullify_url
27
+ Request.new(url, :nullify, params).response
28
+ end
29
+
24
30
  private
25
31
 
26
32
  def config
@@ -2,7 +2,7 @@ module Transbank
2
2
  module Webpay
3
3
  class Configuration
4
4
  attr_accessor :wsdl_transaction_url
5
- attr_accessor :wsdl_cancel_url
5
+ attr_accessor :wsdl_nullify_url
6
6
 
7
7
  attr_accessor :commerce_code
8
8
 
@@ -1,15 +1,25 @@
1
1
  module Transbank
2
2
  module Webpay
3
3
  class Document
4
- attr_reader :unsigned_document, :unsigned_xml
4
+ include Helper
5
+ attr_reader :unsigned_xml
5
6
  XML_HEADER = "<env:Header><wsse:Security xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' wsse:mustUnderstand='1'/></env:Header>".freeze # rubocop:disable LineLength
6
7
  SOAPENV = 'http://schemas.xmlsoap.org/soap/envelope/'.freeze
7
8
 
8
- def initialize(wsdl_url, action, params = {})
9
- client = Savon.client(wsdl: wsdl_url)
10
- xml = client.build_request(action, message: params).body
9
+ NAMESPACES = {
10
+ 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
11
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
12
+ 'xmlns:tns' => 'http://service.wswebpay.webpay.transbank.com/',
13
+ 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/'
14
+ }.freeze
11
15
 
12
- @unsigned_document = Nokogiri::XML(xml)
16
+ def initialize(action, params = {})
17
+ camelcase_action = camelcase(action).to_sym
18
+ @unsigned_xml = build_xml camelcase_action, params
19
+ end
20
+
21
+ def unsigned_document
22
+ @unsigned_document ||= Nokogiri::XML(unsigned_xml)
13
23
  end
14
24
 
15
25
  def envelope
@@ -47,6 +57,30 @@ module Transbank
47
57
  signer.to_xml
48
58
  end
49
59
 
60
+ private
61
+
62
+ def build_xml(action, params = {})
63
+ xml = Builder::XmlMarkup.new indent: 0
64
+ xml.instruct! :xml, encoding: 'UTF-8'
65
+ xml.env(:Envelope, NAMESPACES) do
66
+ xml.env(:Body) do
67
+ xml.tns(action) do
68
+ params.each do |name, value|
69
+ build_tag(xml, name, value)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def build_tag(xml, name, value)
77
+ return xml.tag!(name, value) unless value.is_a?(Hash)
78
+
79
+ xml.tag!(name) do
80
+ value.each { |k, v| build_tag(xml, k, v) }
81
+ end
82
+ end
83
+
50
84
  def cert
51
85
  @cert ||= OpenSSL::X509::Certificate.new open(Transbank::Webpay.configuration.cert_path)
52
86
  end
@@ -1,11 +1,12 @@
1
1
  module Transbank
2
2
  module Webpay
3
3
  class ExceptionResponse
4
- attr_accessor :exception, :action
4
+ attr_reader :exception, :action, :params
5
5
 
6
- def initialize(exception, action)
7
- self.exception = exception
8
- self.action = action
6
+ def initialize(exception, action, params)
7
+ @exception = exception
8
+ @action = action
9
+ @params = params
9
10
  end
10
11
 
11
12
  def valid?
@@ -0,0 +1,7 @@
1
+ module Transbank
2
+ module Webpay
3
+ module Exceptions
4
+ class InvalidSignature < SecurityError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,80 @@
1
+ module Transbank
2
+ module Webpay
3
+ module Helper
4
+ XS_INTEGER = /^[-+]?[1-9]([0-9]*)?$|^0$/
5
+ XS_DATE_TIME = /^-?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/
6
+
7
+ def camelcase(underscore)
8
+ underscore
9
+ .to_s
10
+ .gsub(/(?<=_)(\w)/) { Regexp.last_match[1].upcase }
11
+ .gsub(/(?:_)(\w)/, '\1')
12
+ end
13
+
14
+ def underscore(camelcase)
15
+ camelcase
16
+ .to_s
17
+ .gsub(/::/, '/')
18
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
19
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
20
+ .tr("-", "_")
21
+ .downcase
22
+ end
23
+
24
+ def typecasting(value)
25
+ case value
26
+ when 'true'
27
+ true
28
+ when 'false'
29
+ false
30
+ when XS_DATE_TIME
31
+ try_to_convert(value) { |v| DateTime.parse(v) }
32
+ when XS_INTEGER
33
+ try_to_convert(value) { |v| Integer v }
34
+ else
35
+ value
36
+ end
37
+ end
38
+
39
+ def xml_to_hash(xml_io)
40
+ result = Nokogiri::XML(xml_io)
41
+ xml_node_to_hash(result.root)
42
+ end
43
+
44
+ private
45
+
46
+ def xml_node_to_hash(node)
47
+ return Transbank::Webpay::Struct.new if node.nil?
48
+ return node.content unless node.element?
49
+ return if node.children.empty?
50
+
51
+ hash = node.children.each_with_object({}) do |child, h|
52
+ result = xml_node_to_hash(child)
53
+ return result if return_result?(child)
54
+
55
+ assin_values h, result, child
56
+ end
57
+
58
+ Transbank::Webpay::Struct.new hash
59
+ end
60
+
61
+ def return_result?(child)
62
+ child.next_sibling.nil? && child.previous_sibling.nil?
63
+ end
64
+
65
+ def try_to_convert(value)
66
+ yield value
67
+ rescue ArgumentError
68
+ value
69
+ end
70
+
71
+ def assin_values(hash, result, child)
72
+ return if child.name == 'text'
73
+
74
+ key = underscore child.name
75
+ value = typecasting result
76
+ hash.store key, value
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,6 +1,8 @@
1
1
  module Transbank
2
2
  module Webpay
3
3
  module Params
4
+ include Helper
5
+
4
6
  def build_init_transaction_params(underscore_params = {})
5
7
  camelcase_params = {
6
8
  wSTransactionType: 'TR_NORMAL_WS',
@@ -17,6 +19,17 @@ module Transbank
17
19
 
18
20
  { wsInitTransactionInput: camelcase_params }
19
21
  end
22
+
23
+ def build_nullify_params(underscore_params = {})
24
+ camelcase_params = underscore_params.each_with_object({}) do |(key, value), hash|
25
+ new_key = camelcase(key).to_sym
26
+ hash[new_key] = value
27
+ end
28
+
29
+ camelcase_params[:commerceId] = Transbank::Webpay.configuration.commerce_code
30
+
31
+ { nullificationInput: camelcase_params }
32
+ end
20
33
  end
21
34
  end
22
35
  end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ module Transbank
3
+ module Webpay
4
+ module Reader
5
+ attr_reader :content, :action
6
+
7
+ RESPONSE_CODE = {
8
+ get_transaction_result: {
9
+ '0' => 'transacción aprobada',
10
+ '-1' => 'rechazo de transacción',
11
+ '-2' => 'transacción debe reintentarse',
12
+ '-3' => 'error en transacción',
13
+ '-4' => 'rechazo de transacción',
14
+ '-5' => 'rechazo por error de tasa',
15
+ '-6' => 'excede cupo máximo mensual',
16
+ '-7' => 'excede límite diario por transacción',
17
+ '-8' => 'rubro no autorizado'
18
+ },
19
+ default: {
20
+ '0' => 'aprobada',
21
+ '-98' => 'Error'
22
+ }
23
+ }.freeze
24
+
25
+ def doc
26
+ @doc ||= Nokogiri::XML body
27
+ end
28
+
29
+ def response_code_display
30
+ RESPONSE_CODE.fetch(action, RESPONSE_CODE[:default]).fetch(response_code, response_code)
31
+ end
32
+
33
+ def body
34
+ content.body
35
+ end
36
+
37
+ def xml_error_display
38
+ xml_error.map { |e| e.text.gsub(/<!--|-->/, '').strip }
39
+ end
40
+
41
+ def attributes?
42
+ xml_return != ""
43
+ end
44
+
45
+ private
46
+
47
+ def xml_return
48
+ @xml_return ||= doc.at_xpath("//return").to_s
49
+ end
50
+
51
+ def signature_decode
52
+ Base64.decode64(signature_node.content)
53
+ end
54
+
55
+ def xml_error
56
+ doc.xpath("//faultstring")
57
+ end
58
+
59
+ def response_code
60
+ doc.xpath("//responseCode").text
61
+ end
62
+
63
+ def signature_node
64
+ doc.at_xpath('//ds:SignatureValue', ds: 'http://www.w3.org/2000/09/xmldsig#')
65
+ end
66
+
67
+ def digest
68
+ doc.at_xpath("//ds:DigestValue", ds: 'http://www.w3.org/2000/09/xmldsig#').text
69
+ end
70
+
71
+ def signed_node
72
+ doc.at_xpath '//ds:SignedInfo', ds: 'http://www.w3.org/2000/09/xmldsig#'
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,11 +1,12 @@
1
1
  module Transbank
2
2
  module Webpay
3
3
  class Request
4
- attr_accessor :client, :document, :action
4
+ attr_accessor :client, :document, :action, :params
5
5
 
6
6
  def initialize(wsdl_url, action, params = {})
7
+ @params = params
7
8
  @action = action
8
- @document = Document.new(wsdl_url, action, params)
9
+ @document = Document.new(action, params)
9
10
  @client = Client.new wsdl_url
10
11
  end
11
12
 
@@ -13,9 +14,9 @@ module Transbank
13
14
  rescue_exceptions = Transbank::Webpay.configuration.rescue_exceptions
14
15
 
15
16
  @response ||= begin
16
- Response.new client.post(document.to_xml), action
17
+ Response.new client.post(document.to_xml), action, params
17
18
  rescue match_class(rescue_exceptions) => error
18
- ExceptionResponse.new error, action
19
+ ExceptionResponse.new error, action, params
19
20
  end
20
21
  end
21
22
 
@@ -1,94 +1,31 @@
1
- # rubocop:disable all
2
1
  module Transbank
3
2
  module Webpay
4
3
  class Response
5
- attr_accessor :content, :action, :attributes, :errors, :exception
4
+ include Validations
5
+ include Reader
6
+ include Helper
6
7
 
7
- RESPONSE_CODE = {
8
- get_transaction_result: {
9
- '0' => 'transacción aprobada',
10
- '-1' => 'rechazo de transacción',
11
- '-2' => 'transacción debe reintentarse',
12
- '-3' => 'error en transacción',
13
- '-4' => 'rechazo de transacción',
14
- '-5' => 'rechazo por error de tasa',
15
- '-6' => 'excede cupo máximo mensual',
16
- '-7' => 'excede límite diario por transacción',
17
- '-8' => 'rubro no autorizado'
18
- },
19
- default: {
20
- '0' => 'aprobado',
21
- '-98' => 'Error'
22
- }
23
- }
8
+ attr_reader :attributes, :exception, :params
24
9
 
25
- def initialize(content, action)
26
- self.content = content
27
- self.action = action
28
- self.attributes = xml_result
29
- self.errors = []
30
- validate!
31
- end
10
+ def initialize(content, action, params)
11
+ @content = content
12
+ @action = action
13
+ @params = params
14
+ @attributes = xml_to_hash(xml_return)
15
+ @errors = []
32
16
 
33
- def body
34
- content.body
17
+ validate_response!
35
18
  end
36
19
 
37
20
  def http_code
38
21
  content.code
39
22
  end
40
23
 
41
- def doc
42
- @doc ||= Nokogiri::XML body
43
- end
44
-
45
- def xml_result
46
- parser.parse(doc.at_xpath("//return").to_s).fetch( :return, {}).tap do |hash|
47
- hash[:detail_output].tap {|r| r[:amount] = r[:amount].to_i }
48
-
49
- hash.each { |k, v| hash.store(k, OpenStruct.new(v)) if v.is_a?(Hash) }
50
- end
51
- end
52
-
53
- def xml_error
54
- doc.xpath("//faultstring")
55
- end
56
-
57
- def errors_display
58
- errors.join ', '
59
- end
60
-
61
- def valid?
62
- errors.empty?
63
- end
64
-
65
- def signed_node
66
- doc.at_xpath '//ds:SignedInfo', {'ds' => 'http://www.w3.org/2000/09/xmldsig#'}
67
- end
68
-
69
- def signature_node
70
- doc.at_xpath('//ds:SignatureValue', {'ds' => 'http://www.w3.org/2000/09/xmldsig#'})
71
- end
72
-
73
- def signature_decode
74
- Base64.decode64(signature_node.content)
75
- end
76
-
77
- def response_code
78
- @response_code ||= doc.xpath("//responseCode").text
79
- end
80
-
81
- def response_code_display
82
- if response_code.present?
83
- RESPONSE_CODE.fetch(action, RESPONSE_CODE[:default]).fetch(response_code, response_code)
84
- end
85
- end
86
-
87
24
  def inspect
88
25
  result = ["valid: #{valid?}"]
89
- result << attributes_display if attributes.any?
26
+ result << attributes.inspect if attributes?
90
27
  result << "error: \"#{errors_display}\"" if errors.any?
91
- "#<#{self.class} #{result.join(', ')} >"
28
+ "#<#{self.class} #{result.join(', ')}>"
92
29
  end
93
30
 
94
31
  def exception?
@@ -100,62 +37,12 @@ module Transbank
100
37
  end
101
38
 
102
39
  def method_missing(method_name, *args, &block)
103
- attributes[method_name.to_sym] || super
40
+ attributes.respond_to?(method_name) && attributes.send(method_name) || super
104
41
  end
105
42
 
106
43
  def respond_to_missing?(method_name, include_private = false)
107
- attributes.keys.include?(method_name.to_sym) || super
108
- end
109
-
110
- def xml_error_display
111
- xml_error.map { |e| e.text.gsub(/<!--|-->/, '').strip }
112
- end
113
-
114
- private
115
-
116
- def verify
117
- return if signature_node.nil?
118
-
119
- signed_node.add_namespace 'soap', 'http://schemas.xmlsoap.org/soap/envelope/'
120
- signed_node_canonicalize = signed_node.canonicalize Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, ["soap"], nil
121
-
122
- pub_key.verify OpenSSL::Digest::SHA1.new, signature_decode, signed_node_canonicalize
123
- end
124
-
125
- def server_cert
126
- @server_cert ||= begin
127
- path = Transbank::Webpay.configuration.server_cert_path
128
- OpenSSL::X509::Certificate.new File.read(path)
129
- end
130
- end
131
-
132
- def pub_key
133
- server_cert.public_key
134
- end
135
-
136
- def parser
137
- @parser ||= Nori.new convert_tags_to: lambda { |tag| tag.snakecase.to_sym }
138
- end
139
-
140
- def attributes_display
141
- attributes.map{|name, value| "#{name}: \"#{value}\""}.join ', '
142
- end
143
-
144
- def validate!
145
- if response_code.present? and response_code != '0'
146
- self.errors << response_code_display
147
- end
148
-
149
- if content.class != Net::HTTPOK
150
- self.errors += xml_error_display
151
- self.errors << content.message if content.respond_to?(:message) and self.errors.blank?
152
- end
153
-
154
- if (self.errors.blank? || signature_node.present?) && !verify
155
- raise Exceptions::InvalidSignature.new("Invalid signature")
156
- end
44
+ attributes.respond_to?(method_name, include_private) || super
157
45
  end
158
46
  end
159
47
  end
160
48
  end
161
- # rubocop:enable all
@@ -0,0 +1,6 @@
1
+ module Transbank
2
+ module Webpay
3
+ class Struct < OpenStruct
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,74 @@
1
+ module Transbank
2
+ module Webpay
3
+ module Validations
4
+ attr_reader :errors
5
+
6
+ def errors_display
7
+ errors.join ', '
8
+ end
9
+
10
+ def valid?
11
+ errors.empty?
12
+ end
13
+
14
+ def validate_response!
15
+ validate_response_code!
16
+ validate_http_response!
17
+
18
+ return if errors.any? || validate_document
19
+
20
+ raise Transbank::Webpay::Exceptions::InvalidSignature, 'Invalid signature'
21
+ end
22
+
23
+ private
24
+
25
+ def calculated_digest
26
+ node = doc.at_xpath('//soap:Body')
27
+ node_canonicalize = node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, nil, nil)
28
+ digest = OpenSSL::Digest::SHA1.new.reset.digest(node_canonicalize)
29
+ Base64.encode64(digest).strip
30
+ end
31
+
32
+ def server_cert
33
+ @server_cert ||= begin
34
+ path = Transbank::Webpay.configuration.server_cert_path
35
+ OpenSSL::X509::Certificate.new File.read(path)
36
+ end
37
+ end
38
+
39
+ def pub_key
40
+ server_cert.public_key
41
+ end
42
+
43
+ # Validations
44
+ def validate_response_code!
45
+ return if response_code.empty?
46
+ @errors << response_code_display if response_code != '0'
47
+ end
48
+
49
+ def validate_http_response!
50
+ return if content.class == Net::HTTPOK
51
+
52
+ @errors += xml_error_display
53
+ @errors << content.message if content.respond_to?(:message) && @errors.empty?
54
+ end
55
+
56
+ def validate_document
57
+ return false if signature_node.nil?
58
+ validate_digest && validate_signature
59
+ end
60
+
61
+ def validate_signature
62
+ signed_node_canonicalize = signed_node.canonicalize(
63
+ Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, ["soap"], nil
64
+ )
65
+
66
+ pub_key.verify OpenSSL::Digest::SHA1.new, signature_decode, signed_node_canonicalize
67
+ end
68
+
69
+ def validate_digest
70
+ calculated_digest == digest
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,5 +1,5 @@
1
1
  module Transbank
2
2
  module Webpay
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -20,9 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ["lib"]
21
21
 
22
22
  spec.add_dependency 'signer'
23
- spec.add_dependency 'savon', '~> 2.0'
24
23
  spec.add_dependency 'nokogiri'
25
- spec.add_dependency 'nori'
24
+ spec.add_dependency 'builder', '>= 2.0'
26
25
 
27
26
  spec.add_development_dependency 'bundler', '~> 1.11'
28
27
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transbank-webpay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ramón Soto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-24 00:00:00.000000000 Z
11
+ date: 2016-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: signer
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: savon
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: nokogiri
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,19 +39,19 @@ dependencies:
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: nori
42
+ name: builder
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
60
46
  - !ruby/object:Gem::Version
61
- version: '0'
47
+ version: '2.0'
62
48
  type: :runtime
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
- version: '0'
54
+ version: '2.0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: bundler
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +125,8 @@ files:
139
125
  - Rakefile
140
126
  - bin/console
141
127
  - bin/setup
128
+ - lib/generators/transbank_webpay/install/install_generator.rb
129
+ - lib/generators/transbank_webpay/install/templates/transbank_webpay.rb
142
130
  - lib/transbank-webpay.rb
143
131
  - lib/transbank/webpay.rb
144
132
  - lib/transbank/webpay/api.rb
@@ -146,9 +134,14 @@ files:
146
134
  - lib/transbank/webpay/configuration.rb
147
135
  - lib/transbank/webpay/document.rb
148
136
  - lib/transbank/webpay/exception_response.rb
137
+ - lib/transbank/webpay/exceptions.rb
138
+ - lib/transbank/webpay/helper.rb
149
139
  - lib/transbank/webpay/params.rb
140
+ - lib/transbank/webpay/reader.rb
150
141
  - lib/transbank/webpay/request.rb
151
142
  - lib/transbank/webpay/response.rb
143
+ - lib/transbank/webpay/struct.rb
144
+ - lib/transbank/webpay/validations.rb
152
145
  - lib/transbank/webpay/version.rb
153
146
  - transbank-webpay.gemspec
154
147
  homepage: ''