sepafm 0.1.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3a2be4081eef183a47eae2d15775937b0afdeb7
4
- data.tar.gz: 84c058d1e86826ddc435abb1aaa66ff4c73d4a7a
3
+ metadata.gz: 3071e7c2f8f6ab6f0fcff615a38f2d11517952da
4
+ data.tar.gz: fc8beef75e2f56ece35cccbd5101d1d2cc9af062
5
5
  SHA512:
6
- metadata.gz: c4c73d8aa2da66edc8d915bd0690230e40c944e91acc5fc4de51134830ba5dc3e797d42d6b73a155632d1330c92b1d08cf7594589aa7aebad1b0c332cbdc6ff5
7
- data.tar.gz: 4388e0c0357a779f637b731ff726f6cc81585c71bf88bddadeb160d37f7ea535d7e3f742c7f080cad204aa33b135ec7547ce75d31bcb26766e04723a68ea7dbc
6
+ metadata.gz: 734914613e29893e3c2188a0a3e390bbaf0ae0c170ef58a045f40261e3691c49fa9fc560753c2f5db83a0bd0ff013aab936d889746bc462d0b99571538ea318d
7
+ data.tar.gz: f0d4fac6bbb809d2750f2f6f501e5467398dd85ecef9ab8abbd6a2f6788734284ca12b0ebf066b0e87fc36637c1911c6ad2d1ec53a992abefcd4c110241c83a0
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ lib/**/*.rb
2
+ --private
3
+ --readme readme.md
4
+ --markup markdown
5
+ --title "Documentation for Sepa"
6
+ - LICENSE
@@ -1,7 +1,21 @@
1
1
  module Sepa
2
+
3
+ # Contains functionality to build the application request
4
+ #
5
+ # @todo Add return values for content modifying methods to signal whether they succeeded or not
2
6
  class ApplicationRequest
3
7
  include Utilities
4
8
 
9
+ # Initializes the {ApplicationRequest} with a params hash. The application request is usually
10
+ # initialized by the {SoapBuilder}. The xml template of the application request is also loaded
11
+ # here.
12
+ #
13
+ # @param params [Hash] the hash containing attributes needed by the {ApplicationRequest}. All
14
+ # the key => value pairs in the hash are initialized as instance variables. The hash in the
15
+ # initialization is usually the same as with {SoapBuilder} so the values have already been
16
+ # validated by the client.
17
+ # @todo Consider not using instance_variable_set so that all the available instance variables
18
+ # can easily be seen.
5
19
  def initialize(params = {})
6
20
  # Set all params as instance variables
7
21
  params.each do |key, value|
@@ -11,6 +25,11 @@ module Sepa
11
25
  @application_request = load_body_template AR_TEMPLATE_PATH
12
26
  end
13
27
 
28
+ # Sets the nodes in the application request, processes signature and then returns the
29
+ # application request as an xml document.
30
+ #
31
+ # @return [String] the application request as an xml document
32
+ # @todo This method is obviously doing too much
14
33
  def to_xml
15
34
  set_common_nodes
16
35
  set_nodes_contents
@@ -18,28 +37,48 @@ module Sepa
18
37
  @application_request.to_xml
19
38
  end
20
39
 
40
+ # Base64 encodes the whole application request
41
+ #
42
+ # @return [String] the base64 encoded application request
21
43
  def to_base64
22
44
  encode to_xml
23
45
  end
24
46
 
47
+ # Returns the application request as a Nokogiri document
48
+ #
49
+ # @return [Nokogiri::XML::Document] the application request as a nokogiri document
25
50
  def to_nokogiri
26
51
  Nokogiri::XML to_xml
27
52
  end
28
53
 
29
54
  private
30
55
 
56
+ # Sets node to value
57
+ #
58
+ # @param node [String] the name of the node which value is to be set
59
+ # @param value [#to_s] the value which is going to be set to the node
31
60
  def set_node(node, value)
32
61
  @application_request.at_css(node).content = value
33
62
  end
34
63
 
64
+ # Sets node to base64 encoded value
65
+ #
66
+ # @param node [String] name of the node
67
+ # @param value [#to_s] the value which is going to be set to the nodea base64 encoded
68
+ # @todo rename
35
69
  def set_node_b(node, value)
36
70
  set_node node, encode(value)
37
71
  end
38
72
 
73
+ # Converts {#command} to string, removes underscores and capitalizes it.
74
+ #
75
+ # @example Example input and output
76
+ # :get_user_info --> GetUserInfo
39
77
  def pretty_command
40
78
  @command.to_s.split(/[\W_]/).map {|c| c.capitalize}.join
41
79
  end
42
80
 
81
+ # Determines which content setting method to call depending on {#command}
43
82
  def set_nodes_contents
44
83
  case @command
45
84
  when :create_certificate
@@ -57,6 +96,7 @@ module Sepa
57
96
  end
58
97
  end
59
98
 
99
+ # Sets nodes' values for download file request
60
100
  def set_download_file_nodes
61
101
  add_target_id_after 'FileReferences'
62
102
  set_node("Status", @status)
@@ -64,6 +104,11 @@ module Sepa
64
104
  set_node("FileReference", @file_reference)
65
105
  end
66
106
 
107
+ # Sets Danske Bank's get bank certificate request's contents
108
+ #
109
+ # @raise [OnlyWorksWithDanske] if {#bank} is not danske
110
+ # @todo Investigate a better way to set the bank's root certificate's serial instead of
111
+ # hardcoding it
67
112
  def set_get_bank_certificate_nodes
68
113
  raise 'OnlyWorksWithDanske' if @bank != :danske
69
114
 
@@ -73,24 +118,34 @@ module Sepa
73
118
  set_node("elem|RequestId", @request_id)
74
119
  end
75
120
 
121
+ # Sets nodes' contents for upload file request
76
122
  def set_upload_file_nodes
77
123
  set_node_b("Content", @content)
78
124
  set_node("FileType", @file_type)
79
125
  add_target_id_after 'Environment'
80
126
  end
81
127
 
128
+ # Sets nodes' contents for download file list request
82
129
  def set_download_file_list_nodes
83
130
  add_target_id_after 'Environment'
84
131
  set_node("Status", @status)
85
132
  set_node("FileType", @file_type)
86
133
  end
87
134
 
135
+ # Sets nodes' contents for Nordea's get certificate request
136
+ #
137
+ # @todo Raise error if {#bank} is other than Nordea like in {#set_get_bank_certificate_nodes}
138
+ # @todo Check further into what service actually is
88
139
  def set_get_certificate_nodes
89
140
  set_node("Service", '')
90
141
  set_node("Content", format_cert_request(@signing_csr))
91
142
  set_node("HMAC", hmac(@pin, csr_to_binary(@signing_csr)))
92
143
  end
93
144
 
145
+ # Sets nodes' contents for Danske Bank's create certificate request. Environment is set to
146
+ # customertest if {#environment} is `:test`
147
+ #
148
+ # @todo Raise error if {#bank} is other than Nordea like in {#set_get_bank_certificate_nodes}
94
149
  def set_create_certificate_nodes
95
150
  set_node("tns|CustomerId", @customer_id)
96
151
  set_node("tns|KeyGeneratorType", 'software')
@@ -105,6 +160,8 @@ module Sepa
105
160
  set_node("tns|PIN", @pin)
106
161
  end
107
162
 
163
+ # Sets contents for nodes that are common to all requests except when {#command} is
164
+ # `:get_bank_certificate` or `:create_certificate`. {#environment} is upcased here.
108
165
  def set_common_nodes
109
166
  return if @command == :get_bank_certificate
110
167
  return if @command == :create_certificate
@@ -116,25 +173,48 @@ module Sepa
116
173
  set_node("Command", pretty_command)
117
174
  end
118
175
 
176
+ # Removes a node from {#application_request}
177
+ #
178
+ # @param node [String] name of the node to remove
179
+ # @param xmlns [String] the namespace of the node
180
+ # @todo Move to {Utilities} and move document to parameters
119
181
  def remove_node(node, xmlns)
120
182
  @application_request.at_css("xmlns|#{node}", 'xmlns' => xmlns).remove
121
183
  end
122
184
 
185
+ # Adds node to the root of the application request
186
+ #
187
+ # @todo Move to {Utilities} and move document to parameters
123
188
  def add_node_to_root(node)
124
189
  @application_request.root.add_child(node)
125
190
  end
126
191
 
192
+ # Calculates the digest of {#application_request}
193
+ #
194
+ # @todo Use the digest calculation method in {Utilities} instead of implementing the
195
+ # functionality again here.
196
+ # @return [String] the base64 encoded digest of the {#application_request}
127
197
  def calculate_digest
128
198
  sha1 = OpenSSL::Digest::SHA1.new
129
199
  encode(sha1.digest(@application_request.canonicalize))
130
200
  end
131
201
 
202
+ # Adds value to signature node
203
+ #
204
+ # @param node [String] name of the signature node
205
+ # @param value [#to_s] the value to be set to the node
206
+ # @todo Remove this method and use {#set_node} method
132
207
  def add_value_to_signature(node, value)
133
208
  dsig = 'http://www.w3.org/2000/09/xmldsig#'
134
209
  sig = @application_request.at_css("dsig|#{node}", 'dsig' => dsig)
135
210
  sig.content = value
136
211
  end
137
212
 
213
+ # Calculates the application request's signature value. Uses {#signing_private_key} for the
214
+ # calculation.
215
+ #
216
+ # @return [String] the base64 encoded signature
217
+ # @todo Move to {Utilities}
138
218
  def calculate_signature
139
219
  sha1 = OpenSSL::Digest::SHA1.new
140
220
  dsig = 'http://www.w3.org/2000/09/xmldsig#'
@@ -143,6 +223,9 @@ module Sepa
143
223
  encode signature
144
224
  end
145
225
 
226
+ # Removes signature from the application request, calculates the application request's digest,
227
+ # calculates the signature and adds needed values to signature node. Also adds
228
+ # {#own_signing_certificate} to the signature node.
146
229
  def process_signature
147
230
  # No signature for Certificate Requests
148
231
  return if @command == :get_certificate
@@ -157,6 +240,10 @@ module Sepa
157
240
  add_value_to_signature('X509Certificate', format_cert(@own_signing_certificate))
158
241
  end
159
242
 
243
+ # Adds target id to the application request after a specific node because the schema defines a
244
+ # sequence. Target id is only added if {#bank} is `:nordea`
245
+ #
246
+ # @param node [String] the name of the node after which the target id node will be added
160
247
  def add_target_id_after(node)
161
248
  return unless @bank == :nordea
162
249
 
@@ -1,22 +1,39 @@
1
1
  module Sepa
2
+
3
+ # Contains functionality for the application response embedded in {Response}
4
+ # @todo Use functionality from this class more when validating response
2
5
  class ApplicationResponse
3
6
  include ActiveModel::Validations
4
7
  include Utilities
5
8
 
9
+ # The raw xml of the application response
10
+ #
11
+ # @return [String] the raw xml of the application response
6
12
  attr_reader :xml
7
13
 
8
14
  validate :response_must_validate_against_schema
9
15
 
16
+ # Initializes the {ApplicationResponse} with an application response xml and bank
17
+ #
18
+ # @param app_resp [#to_s] the application response xml
19
+ # @param bank [Symbol] the bank from which the application response came from
10
20
  def initialize(app_resp, bank)
11
21
  @xml = app_resp
12
22
  @bank = bank
13
23
  end
14
24
 
25
+ # The application response as a nokogiri xml document
26
+ #
27
+ # @return [Nokogiri::XML::Document] the application response as a nokogiri document
15
28
  def doc
16
29
  @doc ||= xml_doc @xml
17
30
  end
18
31
 
19
- # Checks that the hash value reported in the signature matches the actual one.
32
+ # Checks that the hash value reported in the signature matches the one that is calculated
33
+ # locally
34
+ #
35
+ # @return [true] if hashes match
36
+ # @return [false] if hashes don't match
20
37
  def hashes_match?
21
38
  are = doc.clone
22
39
 
@@ -31,19 +48,36 @@ module Sepa
31
48
  false
32
49
  end
33
50
 
34
- # Checks that the signature is signed with the private key of the certificate's public key.
51
+ # Checks that the signature has been calculated with the private key of the certificate's public
52
+ # key.
53
+ #
54
+ # @return [true] if signature can be verified
55
+ # @return [false] if signature fails to verify
35
56
  def signature_is_valid?
36
57
  validate_signature(doc, certificate, :normal)
37
58
  end
38
59
 
60
+ # Returns the raw xml of the application response
61
+ #
62
+ # @return [String] the raw xml of the application response
39
63
  def to_s
40
64
  @xml
41
65
  end
42
66
 
67
+ # The certificate which private key has been used to sign the application response
68
+ #
69
+ # @return [OpenSSL::X509::Certificate] if the certificate can be found
70
+ # @return [nil] if the certificate cannot be found
71
+ # @raise [OpenSSL::X509::CertificateError] if the certificate is not valid
43
72
  def certificate
44
73
  extract_cert(doc, 'X509Certificate', DSIG)
45
74
  end
46
75
 
76
+ # Checks whether the embedded certificate has been signed by the private key of the bank's root
77
+ # certificate. The root certificate used varies by bank.
78
+ #
79
+ # @return [true] if the certificate is trusted
80
+ # @return [false] if the certificate is not trusted
47
81
  def certificate_is_trusted?
48
82
  root_certificate =
49
83
  case @bank
@@ -58,6 +92,7 @@ module Sepa
58
92
 
59
93
  private
60
94
 
95
+ # Validates that the response is valid against the application response schema
61
96
  def response_must_validate_against_schema
62
97
  check_validity_against_schema(doc, 'application_response.xsd')
63
98
  end
@@ -1,7 +1,13 @@
1
1
  module Sepa
2
+
3
+ # Contains functionality to check the attributes passed to {Client}. Uses
4
+ # ActiveModel::Validations for the actual validation.
2
5
  module AttributeChecks
3
6
  include ErrorMessages
4
7
 
8
+ # Commands which are allowed for a specific bank
9
+ #
10
+ # @return [Array<Symbol>] the commands which are allowed for {Client#bank}.
5
11
  def allowed_commands
6
12
  case bank
7
13
  when :nordea
@@ -14,10 +20,12 @@ module Sepa
14
20
  end
15
21
  end
16
22
 
23
+ # Checks that {Client#command} is included in {#allowed_commands}
17
24
  def check_command
18
25
  errors.add(:command, "Invalid command") unless allowed_commands.include? command
19
26
  end
20
27
 
28
+ # Checks that signing keys and certificates can be initialized properly.
21
29
  def check_keys
22
30
  return if [:get_certificate, :get_bank_certificate, :create_certificate].include? command
23
31
 
@@ -34,6 +42,7 @@ module Sepa
34
42
  end
35
43
  end
36
44
 
45
+ # Checks that signing certificate signing request can be initialized properly.
37
46
  def check_signing_csr
38
47
  return unless [:get_certificate, :create_certificate].include? command
39
48
 
@@ -42,6 +51,7 @@ module Sepa
42
51
  end
43
52
  end
44
53
 
54
+ # Checks that encryption certificate signing request can be initialized properly.
45
55
  def check_encryption_cert_request
46
56
  return unless command == :create_certificate
47
57
 
@@ -50,6 +60,7 @@ module Sepa
50
60
  end
51
61
  end
52
62
 
63
+ # Checks that {Client#file_type} is proper
53
64
  def check_file_type
54
65
  return unless [:upload_file, :download_file_list, :download_file].include? command
55
66
 
@@ -58,6 +69,7 @@ module Sepa
58
69
  end
59
70
  end
60
71
 
72
+ # Checks that {Client#target_id} is valid.
61
73
  def check_target_id
62
74
  return if [:get_user_info,
63
75
  :get_certificate,
@@ -70,6 +82,11 @@ module Sepa
70
82
  check_presence_and_length(:target_id, 80, TARGET_ID_ERROR_MESSAGE)
71
83
  end
72
84
 
85
+ # Checks presence and length of an attribute
86
+ #
87
+ # @param attribute [Symbol] the attribute to validate
88
+ # @param length [Integer] the maximum length of the attribute
89
+ # @param error_message [#to_s] the error message to display if the validation fails
73
90
  def check_presence_and_length(attribute, length, error_message)
74
91
  check = true
75
92
  check &&= send(attribute)
@@ -80,6 +97,8 @@ module Sepa
80
97
  errors.add(attribute, error_message) unless check
81
98
  end
82
99
 
100
+ # Checks that the content (payload) of the request is somewhat correct. This validation is only
101
+ # run when {Client#command} is `:upload_file`.
83
102
  def check_content
84
103
  return unless command == :upload_file
85
104
 
@@ -91,12 +110,15 @@ module Sepa
91
110
  errors.add(:content, CONTENT_ERROR_MESSAGE) unless check
92
111
  end
93
112
 
113
+ # Checks that the {Client#pin} used in certificate requests in valid
94
114
  def check_pin
95
115
  return unless [:create_certificate, :get_certificate].include? command
96
116
 
97
117
  check_presence_and_length(:pin, 20, PIN_ERROR_MESSAGE)
98
118
  end
99
119
 
120
+ # Checks that {Client#environment} is included in {Client::ENVIRONMENTS}. Not run if
121
+ # {Client#command} is `:get_bank_certificate`.
100
122
  def check_environment
101
123
  return if command == :get_bank_certificate
102
124
 
@@ -105,12 +127,15 @@ module Sepa
105
127
  end
106
128
  end
107
129
 
130
+ # Checks that {Client#customer_id} is valid
108
131
  def check_customer_id
109
132
  unless customer_id && customer_id.respond_to?(:length) && customer_id.length.between?(1, 16)
110
133
  errors.add(:customer_id, CUSTOMER_ID_ERROR_MESSAGE)
111
134
  end
112
135
  end
113
136
 
137
+ # Checks that {Client#bank_encryption_certificate} can be initialized properly. Only run if
138
+ # {Client#bank} is `:danske` and {Client#command} is not `:get_bank_certificate`.
114
139
  def check_encryption_certificate
115
140
  return unless bank == :danske
116
141
  return if command == :get_bank_certificate
@@ -125,6 +150,7 @@ module Sepa
125
150
  errors.add(:bank_encryption_certificate, ENCRYPTION_CERT_ERROR_MESSAGE)
126
151
  end
127
152
 
153
+ # Checks that {Client#status} is included in {Client::STATUSES}.
128
154
  def check_status
129
155
  return unless [:download_file_list, :download_file].include? command
130
156
 
@@ -133,12 +159,16 @@ module Sepa
133
159
  end
134
160
  end
135
161
 
162
+ # Checks presence and length of {Client#file_reference} if {Client#command} is `:download_file`
136
163
  def check_file_reference
137
164
  return unless command == :download_file
138
165
 
139
166
  check_presence_and_length :file_reference, 33, FILE_REFERENCE_ERROR_MESSAGE
140
167
  end
141
168
 
169
+ # Checks that {Client#encryption_private_key} can be initialized properly. Is only run if
170
+ # {Client#bank} is `:danske` and {Client#command} is not `:create_certificate` or
171
+ # `:get_bank_certificate`.
142
172
  def check_encryption_private_key
143
173
  return unless bank == :danske
144
174
  return if [:create_certificate, :get_bank_certificate].include? command
@@ -1,49 +1,90 @@
1
1
  module Sepa
2
+
3
+ # Handles Danske Bank specific {Response} functionality. Mainly decryption and certificate
4
+ # specific stuff.
2
5
  class DanskeResponse < Response
3
6
 
4
7
  validate :valid_get_bank_certificate_response
5
8
  validate :can_be_decrypted_with_given_key
6
9
 
10
+ # @return [String]
11
+ # @see Response#application_response
7
12
  def application_response
8
13
  @application_response ||= decrypt_application_response
9
14
  end
10
15
 
16
+ # Returns the bank's encryption certificate which is used to encrypt messages sent to the bank.
17
+ # The certificate is only present in `:get_bank_certificate` responess.
18
+ #
19
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:get_bank_certificate`
20
+ # @return [nil] if command is any other
11
21
  def bank_encryption_certificate
12
22
  return unless @command == :get_bank_certificate
13
23
 
14
24
  @bank_encryption_certificate ||= extract_cert(doc, 'BankEncryptionCert', DANSKE_PKI)
15
25
  end
16
26
 
27
+ # Returns the bank's signing certificate which is used by the bank to sign the responses. The
28
+ # certificate is only present in `:get_bank_certificate` responses
29
+ #
30
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:get_bank_certificate`
31
+ # @return [nil] if {#command} is any other
17
32
  def bank_signing_certificate
18
33
  return unless @command == :get_bank_certificate
19
34
 
20
35
  @bank_signing_certificate ||= extract_cert(doc, 'BankSigningCert', DANSKE_PKI)
21
36
  end
22
37
 
38
+ # Returns the bank's root certificate which is the certificate that is used to sign bank's other
39
+ # certificates. Only present in `:get_bank_certificate` responses.
40
+ #
41
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:get_bank_certificate`
42
+ # @return [nil] if {#command} is any other
23
43
  def bank_root_certificate
24
44
  return unless @command == :get_bank_certificate
25
45
 
26
46
  @bank_root_certificate ||= extract_cert(doc, 'BankRootCert', DANSKE_PKI)
27
47
  end
28
48
 
49
+ # Returns own encryption certificate which has been signed by the bank. Only present in
50
+ # `:create_certificate` responses
51
+ #
52
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
53
+ # @return [nil] if command is any other
29
54
  def own_encryption_certificate
30
55
  return unless @command == :create_certificate
31
56
 
32
57
  @own_encryption_certificate ||= extract_cert(doc, 'EncryptionCert', DANSKE_PKI)
33
58
  end
34
59
 
60
+ # Returns own signing certificate which has been signed by the bank. Is used to sign requests
61
+ # sent to the bank. Is only present in `:create_certificate` responses.
62
+ #
63
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
64
+ # @return [nil] if command is any other
35
65
  def own_signing_certificate
36
66
  return unless @command == :create_certificate
37
67
 
38
68
  @own_signing_certificate ||= extract_cert(doc, 'SigningCert', DANSKE_PKI)
39
69
  end
40
70
 
71
+ # Returns the CA certificate that has been used to sign own signing and encryption certificates.
72
+ # Only present in `:create_certificate` responses
73
+ #
74
+ # @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
75
+ # @return [nil] if command is any other
41
76
  def ca_certificate
42
77
  return unless @command == :create_certificate
43
78
 
44
79
  @ca_certificate ||= extract_cert(doc, 'CACert', DANSKE_PKI)
45
80
  end
46
81
 
82
+ # Extract certificate that has been used to sign the response. This overrides
83
+ # {Response#certificate} method with specific functionality for `:get_bank_certificate` and
84
+ # `:create_certificate` commands. Otherwise just calls {Response#certificate}
85
+ #
86
+ # @return [OpenSSL::X509::Certificate]
87
+ # @raise [OpenSSL::X509::CertificateError] if certificate cannot be processed
47
88
  def certificate
48
89
  if [:get_bank_certificate, :create_certificate].include? @command
49
90
  @certificate ||= begin
@@ -54,6 +95,13 @@ module Sepa
54
95
  end
55
96
  end
56
97
 
98
+ # Extract response code from the response. Overrides super method when {#command} is
99
+ # `:get_bank_certificate` or `:create_certificate` because response code node is named
100
+ # differently in those responses.
101
+ #
102
+ # @return [String] if response code is found
103
+ # @return [nil] if response code cannot be found
104
+ # @see Response#response_code
57
105
  def response_code
58
106
  return super unless [:get_bank_certificate, :create_certificate].include? @command
59
107
 
@@ -61,6 +109,12 @@ module Sepa
61
109
  node.content if node
62
110
  end
63
111
 
112
+ # Checks whether certificate embedded in the response has been signed with the bank's root
113
+ # certificate. Always returns true when {#command} is `:get_bank_certificate`, because the
114
+ # certificate is not present with that command.
115
+ #
116
+ # @return [true] if certificate is trusted
117
+ # @return [false] if certificate is not trusted
64
118
  def certificate_is_trusted?
65
119
  return true if @command == :get_bank_certificate
66
120
 
@@ -69,6 +123,14 @@ module Sepa
69
123
 
70
124
  private
71
125
 
126
+ # Finds a node by its reference URI from Danske Bank's certificate responses. If {#command} is
127
+ # other than `:get_bank_certificate` or `:create_certificate` returns super. This method is
128
+ # needed because Danske Bank uses a different way to reference nodes in their certificate
129
+ # responses.
130
+ #
131
+ # @param uri [String] reference URI of the node to find
132
+ # @return [Nokogiri::XML::Node] node with signature removed from its document since signature
133
+ # has to be removed for canonicalization and hash calculation
72
134
  def find_node_by_uri(uri)
73
135
  return super unless [:get_bank_certificate, :create_certificate].include? @command
74
136
 
@@ -77,6 +139,15 @@ module Sepa
77
139
  doc_without_signature.at("[xml|id='#{uri}']")
78
140
  end
79
141
 
142
+ # Decrypts the application response in the response. Starts by calling {#decrypt_embedded_key}
143
+ # method to get the key used in encrypting the application response. After this the encrypted
144
+ # data is retrieved from the document and base64 decoded. After this the iv
145
+ # (initialization vector) is extracted from the encrypted data and a decipher with the
146
+ # 'DES-EDE3-CBC' algorithm is initialized (This is used by banks as encryption algorithm) and
147
+ # its key and iv set accordingly and mode changes to decrypt. After this the data is decrypted
148
+ # and returned as string.
149
+ #
150
+ # @return [String] the decrypted application response as raw xml
80
151
  def decrypt_application_response
81
152
  key = decrypt_embedded_key
82
153
 
@@ -96,6 +167,8 @@ module Sepa
96
167
  decipher.update(encypted_data) + decipher.final
97
168
  end
98
169
 
170
+ # Validates get bank certificate response. Response is valid if service fault is not returned
171
+ # from the bank.
99
172
  def valid_get_bank_certificate_response
100
173
  return unless @command == :get_bank_certificate
101
174
 
@@ -104,6 +177,11 @@ module Sepa
104
177
  end
105
178
  end
106
179
 
180
+ # Extracts the encrypted application response from the response and returns it as a nokogiri
181
+ # document
182
+ #
183
+ # @return [Nokogiri::XML] the encrypted application response if it is found
184
+ # @return [nil] if the application response cannot be found
107
185
  def encrypted_application_response
108
186
  @encrypted_application_response ||= begin
109
187
  encrypted_application_response = extract_application_response(BXD)
@@ -111,6 +189,8 @@ module Sepa
111
189
  end
112
190
  end
113
191
 
192
+ # Validates that the encrypted key in the response can be decrypted with the private key given
193
+ # to the response in the parameters. Response is invalid if this cannot be done.
114
194
  def can_be_decrypted_with_given_key
115
195
  return if [:get_bank_certificate, :create_certificate].include? @command
116
196
  return unless encrypted_application_response.css('CipherValue', 'xmlns' => XMLENC)[0]
@@ -120,6 +200,12 @@ module Sepa
120
200
  end
121
201
  end
122
202
 
203
+ # Decrypts (assymetrically) the symmetric encryption key embedded in the response with the
204
+ # private key given to the response in the parameters. The key is later used to decrypt the
205
+ # application response.
206
+ #
207
+ # @return [String] the encryption key as a string
208
+ # @return [nil] if the key cannot be decrypted with the given key
123
209
  def decrypt_embedded_key
124
210
  enc_key = encrypted_application_response.css('CipherValue', 'xmlns' => XMLENC)[0].content
125
211
  enc_key = decode enc_key