sepafm 0.1.5 → 1.0.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: 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