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 +4 -4
- data/.yardopts +6 -0
- data/lib/sepa/application_request.rb +87 -0
- data/lib/sepa/application_response.rb +37 -2
- data/lib/sepa/attribute_checks.rb +30 -0
- data/lib/sepa/banks/danske/danske_response.rb +86 -0
- data/lib/sepa/banks/danske/soap_danske.rb +81 -3
- data/lib/sepa/banks/nordea/nordea_response.rb +18 -0
- data/lib/sepa/banks/nordea/soap_nordea.rb +25 -2
- data/lib/sepa/client.rb +203 -18
- data/lib/sepa/error_messages.rb +54 -13
- data/lib/sepa/response.rb +118 -11
- data/lib/sepa/soap_builder.rb +53 -2
- data/lib/sepa/utilities.rb +167 -6
- data/lib/sepa/version.rb +3 -1
- data/lib/sepafm.rb +57 -4
- data/readme.md +74 -60
- data/test/sepa/sepa_test.rb +1 -1
- metadata +5 -3
@@ -1,8 +1,15 @@
|
|
1
1
|
module Sepa
|
2
|
+
|
3
|
+
# Contains Danske Bank specific soap building functionality
|
2
4
|
module DanskeSoapRequest
|
3
5
|
|
4
6
|
private
|
5
7
|
|
8
|
+
# Determines which kind of request to build depending on command. Certificate requests differ
|
9
|
+
# from generic requests.
|
10
|
+
#
|
11
|
+
# @return [Nokogiri::XML] the built soap as a nokogiri document
|
12
|
+
# @todo remove `:get_user_info` since Danske Bank doesn't support it
|
6
13
|
def find_correct_build
|
7
14
|
case @command
|
8
15
|
when :create_certificate
|
@@ -14,6 +21,12 @@ module Sepa
|
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
24
|
+
# Encrypts the application request with the public key of the bank encryption certificate got
|
25
|
+
# from the parameters. The actual encryption is done by {#encrypt_ar} and {#encrypt_key}
|
26
|
+
# methods. After the encryption, the encrypted application request xml is built by
|
27
|
+
# {#build_encrypted_ar} method
|
28
|
+
#
|
29
|
+
# @return [Nokogiri::XML] the encrypted application request as a nokogiri document
|
17
30
|
def encrypt_application_request
|
18
31
|
encryption_certificate = x509_certificate(@bank_encryption_certificate)
|
19
32
|
encryption_public_key = encryption_certificate.public_key
|
@@ -24,14 +37,23 @@ module Sepa
|
|
24
37
|
end
|
25
38
|
|
26
39
|
# Encrypts a given symmetric encryption key with a public key and returns it in base64 encoded
|
27
|
-
# format
|
40
|
+
# format.
|
41
|
+
#
|
42
|
+
# @param key [String] the key that will be encrypted
|
43
|
+
# @param public_key [OpenSSL::PKey::RSA] the public key that will be used to do the encryption
|
44
|
+
# @return [String] the encrypted key as a base64 encoded string
|
45
|
+
# @todo make more generic and move to utilities
|
28
46
|
def encrypt_key(key, public_key)
|
29
47
|
encrypted_key = public_key.public_encrypt(key)
|
30
48
|
encode encrypted_key
|
31
49
|
end
|
32
50
|
|
33
|
-
# Encrypts the application request and returns it in base64 encoded format.
|
34
|
-
#
|
51
|
+
# Encrypts the application request and returns it in base64 encoded format. Also returns the
|
52
|
+
# key needed to decrypt it. The encryption algorithm is 'DES-EDE3-CBC' and the iv is prepended
|
53
|
+
# to the encrypted data.
|
54
|
+
#
|
55
|
+
# @return [Array(String, String)] the encrypted application request and the key needed to
|
56
|
+
# decrypt it
|
35
57
|
def encrypt_ar
|
36
58
|
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
|
37
59
|
|
@@ -46,6 +68,15 @@ module Sepa
|
|
46
68
|
return encrypted_data, key
|
47
69
|
end
|
48
70
|
|
71
|
+
# Builds the xml structure for the encrypted application request that can be base64 encoded
|
72
|
+
# and embedded to the soap.
|
73
|
+
#
|
74
|
+
# @param cert [#to_s] the certificate which public key was used for the asymmetric encryption
|
75
|
+
# @param encrypted_data [#to_s] the encrypted application request
|
76
|
+
# @param encrypted_key [#to_s] the encrypted key that was used for the symmetric encryption
|
77
|
+
# @return [Nokogiri::XML] the encrypted application request xml structure as a nokogiri
|
78
|
+
# document
|
79
|
+
# @todo rename
|
49
80
|
def build_encrypted_ar(cert, encrypted_data, encrypted_key)
|
50
81
|
ar = Nokogiri::XML File.open "#{AR_TEMPLATE_PATH}/encrypted_request.xml"
|
51
82
|
set_node(ar, 'dsig|X509Certificate', cert)
|
@@ -54,6 +85,12 @@ module Sepa
|
|
54
85
|
ar
|
55
86
|
end
|
56
87
|
|
88
|
+
# Sets contents for generic request's nodes. Generic requests are:
|
89
|
+
# * Upload file
|
90
|
+
# * Download file
|
91
|
+
# * Download file list
|
92
|
+
#
|
93
|
+
# @todo make ReceiverId dynamic
|
57
94
|
def set_generic_request_contents
|
58
95
|
set_node(@template, 'bxd|SenderId', @customer_id)
|
59
96
|
set_node(@template, 'bxd|RequestId', request_id)
|
@@ -63,6 +100,9 @@ module Sepa
|
|
63
100
|
set_node(@template, 'bxd|ReceiverId', "DABAFIHH")
|
64
101
|
end
|
65
102
|
|
103
|
+
# Sets contents for create certificate requests.
|
104
|
+
#
|
105
|
+
# @todo rename
|
66
106
|
def set_create_cert_contents
|
67
107
|
set_node(@template, 'pkif|SenderId', @customer_id)
|
68
108
|
set_node(@template, 'pkif|CustomerId', @customer_id)
|
@@ -72,6 +112,9 @@ module Sepa
|
|
72
112
|
set_node(@template, 'pkif|Environment', @environment)
|
73
113
|
end
|
74
114
|
|
115
|
+
# Sets contents for get bank certificate requests
|
116
|
+
#
|
117
|
+
# @todo rename
|
75
118
|
def set_bank_certificate_contents
|
76
119
|
set_node(@template, 'pkif|SenderId', @customer_id)
|
77
120
|
set_node(@template, 'pkif|CustomerId', @customer_id)
|
@@ -80,6 +123,14 @@ module Sepa
|
|
80
123
|
set_node(@template, 'pkif|InterfaceVersion', 1)
|
81
124
|
end
|
82
125
|
|
126
|
+
# Builds Danske Bank's generic request soap. The processing order is as follows:
|
127
|
+
# 1. The contents of the soap are set
|
128
|
+
# 2. The application request is encrypted
|
129
|
+
# 3. The encrypted application request xml structure is embedded in the soap
|
130
|
+
# 4. The header is processed
|
131
|
+
# 5. The body is added to the header
|
132
|
+
#
|
133
|
+
# @return [Nokogiri::XML] the complete soap
|
83
134
|
def build_danske_generic_request
|
84
135
|
set_generic_request_contents
|
85
136
|
encrypted_request = encrypt_application_request
|
@@ -89,6 +140,11 @@ module Sepa
|
|
89
140
|
add_body_to_header
|
90
141
|
end
|
91
142
|
|
143
|
+
# Builds Danske Bank's create certificate request soap. Environment is set to `:customertest`
|
144
|
+
# if set to `:test`. This request is encrypted but not signed.
|
145
|
+
#
|
146
|
+
# @return [Nokogiri::XML] the complete soap
|
147
|
+
# @todo rename
|
92
148
|
def build_certificate_request
|
93
149
|
@environment = :customertest if @environment == :test
|
94
150
|
set_create_cert_contents
|
@@ -96,11 +152,20 @@ module Sepa
|
|
96
152
|
add_encrypted_request_to_soap(encrypted_request)
|
97
153
|
end
|
98
154
|
|
155
|
+
# Builds get bank certificate request soap. This request is neither signed nor encrypted.
|
156
|
+
#
|
157
|
+
# @return [Nokogiri::XML] the complete soap
|
99
158
|
def build_get_bank_certificate_request
|
100
159
|
set_bank_certificate_contents
|
101
160
|
add_bank_certificate_body_to_soap
|
102
161
|
end
|
103
162
|
|
163
|
+
# Adds encrypted application request xml structure to the soap. This method is used when
|
164
|
+
# building create certificate requests and the encrypted application request xml structure
|
165
|
+
# will not be base64 encoded.
|
166
|
+
#
|
167
|
+
# @param encrypted_request [Nokogiri::XML] the encrypted application request xml structure
|
168
|
+
# @return [Nokogiri::XML] the soap with the encrypted application request added to it
|
104
169
|
def add_encrypted_request_to_soap(encrypted_request)
|
105
170
|
encrypted_request = Nokogiri::XML(encrypted_request.to_xml)
|
106
171
|
encrypted_request = encrypted_request.root
|
@@ -109,6 +174,12 @@ module Sepa
|
|
109
174
|
@template
|
110
175
|
end
|
111
176
|
|
177
|
+
# Adds the encrypted application request xml structure to generic request soap.
|
178
|
+
# The application request is base64 encoded before it is added to the soap.
|
179
|
+
#
|
180
|
+
# @param encrypted_request [Nokogiri::XML] the encrypted application request xml structure
|
181
|
+
# @return [Nokogiri::XML] the soap with the encrypted application request added to it
|
182
|
+
# @todo refactor possible unnecessary conversion away and rename
|
112
183
|
def add_encrypted_generic_request_to_soap(encrypted_request)
|
113
184
|
encrypted_request = Nokogiri::XML(encrypted_request.to_xml)
|
114
185
|
encrypted_request = encrypted_request.root
|
@@ -118,6 +189,9 @@ module Sepa
|
|
118
189
|
@template
|
119
190
|
end
|
120
191
|
|
192
|
+
# Adds get bank certificate application request to the soap
|
193
|
+
#
|
194
|
+
# @return [Nokogiri::XML] the soap with the application request added to it
|
121
195
|
def add_bank_certificate_body_to_soap
|
122
196
|
ar = @application_request.to_nokogiri
|
123
197
|
|
@@ -127,6 +201,10 @@ module Sepa
|
|
127
201
|
@template
|
128
202
|
end
|
129
203
|
|
204
|
+
# Generates a random 10-character request id for Danske Bank's requests.
|
205
|
+
#
|
206
|
+
# @return [String] 10-character hexnumeric request id
|
207
|
+
# @todo move to utilities
|
130
208
|
def request_id
|
131
209
|
SecureRandom.hex(5)
|
132
210
|
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module Sepa
|
2
|
+
|
3
|
+
# Handles Nordea specific response logic. Mainly certificate specific stuff.
|
2
4
|
class NordeaResponse < Response
|
3
5
|
include Utilities
|
4
6
|
|
7
|
+
# Extracts own signing certificate from the response.
|
8
|
+
#
|
9
|
+
# @return [String] own signing certificate as string it it is found
|
10
|
+
# @return [nil] if the certificate cannot be found
|
5
11
|
def own_signing_certificate
|
6
12
|
application_response = extract_application_response(NORDEA_PKI)
|
7
13
|
at = 'xmlns|Certificate > xmlns|Certificate'
|
@@ -14,6 +20,12 @@ module Sepa
|
|
14
20
|
cert.to_s
|
15
21
|
end
|
16
22
|
|
23
|
+
# Returns the response code in the response. Overrides {Response#response_code} if {#command} is
|
24
|
+
# `:get_certificate`, because the namespace is different with that command.
|
25
|
+
#
|
26
|
+
# @return [String] response code if it is found
|
27
|
+
# @return [nil] if response code cannot be found
|
28
|
+
# @see Response#response_code
|
17
29
|
def response_code
|
18
30
|
return super unless command == :get_certificate
|
19
31
|
|
@@ -21,6 +33,12 @@ module Sepa
|
|
21
33
|
node.content if node
|
22
34
|
end
|
23
35
|
|
36
|
+
# Checks whether the certificate embedded in the response soap has been signed with Nordea's
|
37
|
+
# root certificate.
|
38
|
+
#
|
39
|
+
# @return [true] if certificate is trusted
|
40
|
+
# @return [false] if certificate fails to verify
|
41
|
+
# @see DanskeResponse#certificate_is_trusted?
|
24
42
|
def certificate_is_trusted?
|
25
43
|
verify_certificate_against_root_certificate(certificate, NORDEA_ROOT_CERTIFICATE)
|
26
44
|
end
|
@@ -1,8 +1,14 @@
|
|
1
1
|
module Sepa
|
2
|
+
|
3
|
+
# Contains Nordea specific soap building functionality
|
2
4
|
module NordeaSoapRequest
|
3
5
|
|
4
6
|
private
|
5
7
|
|
8
|
+
# Determines which soap request to build based on command. Certificate requests are built
|
9
|
+
# differently than generic requests.
|
10
|
+
#
|
11
|
+
# @return [Nokogiri::XML] the soap as a nokogiri document
|
6
12
|
def find_correct_build
|
7
13
|
case @command
|
8
14
|
when :get_certificate
|
@@ -12,11 +18,17 @@ module Sepa
|
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
15
|
-
#
|
21
|
+
# Sets contents for certificate request
|
22
|
+
#
|
23
|
+
# @return [Nokogiri::XML] the template with contents added to it
|
16
24
|
def build_certificate_request
|
17
25
|
set_body_contents
|
18
26
|
end
|
19
27
|
|
28
|
+
# Sets soap body contents. Application request is base64 encoded here.
|
29
|
+
#
|
30
|
+
# @return [Nokogiri::XML] the soap with contents added to it
|
31
|
+
# @todo rename, because apparently only sets certificate contents
|
20
32
|
def set_body_contents
|
21
33
|
set_node(@template, 'cer|ApplicationRequest', @application_request.to_base64)
|
22
34
|
set_node(@template, 'cer|SenderId', @customer_id)
|
@@ -26,13 +38,20 @@ module Sepa
|
|
26
38
|
@template
|
27
39
|
end
|
28
40
|
|
29
|
-
# Builds
|
41
|
+
# Builds generic request which is a request made with commands:
|
42
|
+
# * Get User Info
|
43
|
+
# * Download File
|
44
|
+
# * Download File List
|
45
|
+
# * Upload File
|
46
|
+
#
|
47
|
+
# @return [Nokogiri::XML] the generic request soap
|
30
48
|
def build_common_request
|
31
49
|
common_set_body_contents
|
32
50
|
process_header
|
33
51
|
add_body_to_header
|
34
52
|
end
|
35
53
|
|
54
|
+
# Sets nodes for generic requests, application request is base64 encoded here.
|
36
55
|
def common_set_body_contents
|
37
56
|
set_node(@template, 'bxd|ApplicationRequest', @application_request.to_base64)
|
38
57
|
set_node(@template, 'bxd|SenderId', @customer_id)
|
@@ -43,6 +62,10 @@ module Sepa
|
|
43
62
|
set_node(@template, 'bxd|ReceiverId', @target_id)
|
44
63
|
end
|
45
64
|
|
65
|
+
# Generates a random request id for Nordea request
|
66
|
+
#
|
67
|
+
# @return [String] hexnumeric request id
|
68
|
+
# @todo move to utilities
|
46
69
|
def request_id
|
47
70
|
SecureRandom.hex(17)
|
48
71
|
end
|
data/lib/sepa/client.rb
CHANGED
@@ -1,31 +1,181 @@
|
|
1
|
+
# Main module for this gem
|
1
2
|
module Sepa
|
3
|
+
|
4
|
+
# Handles parameter validation, key initialization, {SoapBuilder} initialization, communicating
|
5
|
+
# with the bank and {Response} initialization.
|
2
6
|
class Client
|
3
7
|
include ActiveModel::Validations
|
4
8
|
include Utilities
|
5
9
|
include ErrorMessages
|
6
10
|
include AttributeChecks
|
7
11
|
|
8
|
-
attr_accessor :bank,
|
9
|
-
:command,
|
10
|
-
:content,
|
11
|
-
:customer_id,
|
12
|
-
:target_id,
|
13
|
-
:environment,
|
14
|
-
:file_reference,
|
15
|
-
:file_type,
|
16
|
-
:language,
|
17
|
-
:status,
|
18
|
-
:pin,
|
19
|
-
:signing_private_key,
|
20
|
-
:own_signing_certificate,
|
21
|
-
:signing_csr,
|
22
|
-
:encryption_private_key,
|
23
|
-
:bank_encryption_certificate,
|
24
|
-
:encryption_csr
|
25
12
|
|
13
|
+
# The bank that is used in this client. One of {BANKS}.
|
14
|
+
#
|
15
|
+
# @return [Symbol]
|
16
|
+
attr_accessor :bank
|
17
|
+
|
18
|
+
# The command that is used with this client. One of {AttributeChecks#allowed_commands}.
|
19
|
+
#
|
20
|
+
# @return [Symbol]
|
21
|
+
attr_accessor :command
|
22
|
+
|
23
|
+
# The payload in base64 encoded form. Used with upload file command.
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
# @example Dummy payload
|
27
|
+
# 'a2lzc2E='
|
28
|
+
attr_accessor :content
|
29
|
+
|
30
|
+
# Customer id got from the bank.
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
# @example Nordea's testing customer id
|
34
|
+
# '11111111'
|
35
|
+
attr_accessor :customer_id
|
36
|
+
|
37
|
+
# A file categorization id used by Nordea. Can be retrieved with get_user_info request. Not
|
38
|
+
# used with Danske Bank
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
# @example Nordea's testing target id
|
42
|
+
# '11111111A1'
|
43
|
+
attr_accessor :target_id
|
44
|
+
|
45
|
+
# The environment to be used. One of {ENVIRONMENTS}.
|
46
|
+
#
|
47
|
+
# @return [Symbol]
|
48
|
+
attr_accessor :environment
|
49
|
+
|
50
|
+
# File reference number used in download_file requests.
|
51
|
+
#
|
52
|
+
# @return [String]
|
53
|
+
# @example
|
54
|
+
# '11111111A12006030319503000000010'
|
55
|
+
attr_accessor :file_reference
|
56
|
+
|
57
|
+
# The file type of the file that is about to be uploaded or downloaded. These vary by bank.
|
58
|
+
#
|
59
|
+
# @return [String]
|
60
|
+
# @example Nordea's electronic bank statement
|
61
|
+
# 'TITO'
|
62
|
+
attr_accessor :file_type
|
63
|
+
|
64
|
+
# The language to be used in this client. One of {LANGUAGES}.
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
attr_accessor :language
|
68
|
+
|
69
|
+
# Used to filter files in download_file_list request. One of {STATUSES}.
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
attr_accessor :status
|
73
|
+
|
74
|
+
# The one-time pin got for bank. Used with certificate requests.
|
75
|
+
#
|
76
|
+
# @return [String]
|
77
|
+
# @example Danske Bank's testing pin
|
78
|
+
# '1234'
|
79
|
+
attr_accessor :pin
|
80
|
+
|
81
|
+
# Signing private key which is used to sign the request
|
82
|
+
#
|
83
|
+
# @return [String]
|
84
|
+
# @example Nordea's testing private key
|
85
|
+
# '-----BEGIN RSA PRIVATE KEY-----
|
86
|
+
# MIICXQIBAAKBgQDC0UR8C1sm4bNDDBG6ZmS9iHYGMZhWwAxR6Iq06d7dtlJ6Kx8K
|
87
|
+
# r5NeovWAj0uh/J4BD0j+wObq0vzTKsPmJpJSpWboDvf0yyalb+LJlxV/uazzEA3n
|
88
|
+
# URJSA3pqTBkJT2kfraeAkOPaBSyS1jR+myhWwBF2u84WTR9NJRcpZ3ottwIDAQAB
|
89
|
+
# AoGBAKrfddv+8eI2kE68ZUhCyxVafXqNQXrFU4j8F7z6bBm28rxo2f87ZFzbPc2W
|
90
|
+
# 4dWghs2TJIkdlOxeRpbIqa5SIn+HBel8+6wo2gLO4g0bfT44Y1bqjRkdiPlSCJW0
|
91
|
+
# PV1hSd5SRVt7+0yGfCWy559Fzhc/mQQUkhkytc0zYeEwULYxAkEA3uTN7rvZuEcE
|
92
|
+
# sPUehmg8PyBUGYK9KFkr9FiI0cL8FpxZ0l9pW5DQI7pT9HWhrJp+78SKamcT8cHK
|
93
|
+
# 1OMBakxeXQJBAN/A52wpt2H6IM8Cxza3toQZhqo1mq4bcarUWq65IJ5jnfFtGdR2
|
94
|
+
# 9XUh65YlElUqyDWyuWXRFdeUabu1Qznj8yMCQDzLJUvvGpQDcskdIiVAuuXw2F9Y
|
95
|
+
# 5GTj5XQwzaiAyScVn/4cHe1mkw6bnJh5mQ4t2V9mOOaKlMsEs2DbRaCLkdUCQGWF
|
96
|
+
# Gbsqpkiu+0nRgd+itQ30ovQBREAwtX8DwG08E7+phRTwImMS4kWV8VT7VvkLYzFx
|
97
|
+
# +MpodleMv/hpwqm2ci8CQQCUEgwDBEp+FM+2Y5N1KwSGzGBL9LtpnAsqcLG9JxhO
|
98
|
+
# f4Mwz4xhPXMVlvq1wESLPrDUFQpZ4eOZ4XX2MTo4GH39
|
99
|
+
# -----END RSA PRIVATE KEY-----'
|
100
|
+
attr_accessor :signing_private_key
|
101
|
+
|
102
|
+
# Own signing certificate in "pem" format. Embedded in the request
|
103
|
+
#
|
104
|
+
# @return [String]
|
105
|
+
# @example Nordea's testing signing certificate
|
106
|
+
# '-----BEGIN CERTIFICATE-----
|
107
|
+
# MIIDwTCCAqmgAwIBAgIEAX1JuTANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT
|
108
|
+
# RTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMR8wHQYDVQQDExZOb3Jk
|
109
|
+
# ZWEgQ29ycG9yYXRlIENBIDAxMRQwEgYDVQQFEws1MTY0MDYtMDEyMDAeFw0xMzA1
|
110
|
+
# MDIxMjI2MzRaFw0xNTA1MDIxMjI2MzRaMEQxCzAJBgNVBAYTAkZJMSAwHgYDVQQD
|
111
|
+
# DBdOb3JkZWEgRGVtbyBDZXJ0aWZpY2F0ZTETMBEGA1UEBRMKNTc4MDg2MDIzODCB
|
112
|
+
# nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwtFEfAtbJuGzQwwRumZkvYh2BjGY
|
113
|
+
# VsAMUeiKtOne3bZSeisfCq+TXqL1gI9LofyeAQ9I/sDm6tL80yrD5iaSUqVm6A73
|
114
|
+
# 9MsmpW/iyZcVf7ms8xAN51ESUgN6akwZCU9pH62ngJDj2gUsktY0fpsoVsARdrvO
|
115
|
+
# Fk0fTSUXKWd6LbcCAwEAAaOCAR0wggEZMAkGA1UdEwQCMAAwEQYDVR0OBAoECEBw
|
116
|
+
# 2cj7+XMAMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEALddbbzwun
|
117
|
+
# MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVh
|
118
|
+
# LnNlL0NDQTAxMA4GA1UdDwEB/wQEAwIFoDCBhQYDVR0fBH4wfDB6oHigdoZ0bGRh
|
119
|
+
# cCUzQS8vbGRhcC5uYi5zZS9jbiUzRE5vcmRlYStDb3Jwb3JhdGUrQ0ErMDElMkNv
|
120
|
+
# JTNETm9yZGVhK0JhbmsrQUIrJTI4cHVibCUyOSUyQ2MlM0RTRSUzRmNlcnRpZmlj
|
121
|
+
# YXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBACLUPB1Gmq6286/s
|
122
|
+
# ROADo7N+w3eViGJ2fuOTLMy4R0UHOznKZNsuk4zAbS2KycbZsE5py4L8o+IYoaS8
|
123
|
+
# 8YHtEeckr2oqHnPpz/0Eg7wItj8Ad+AFWJqzbn6Hu/LQhlnl5JEzXzl3eZj9oiiJ
|
124
|
+
# 1q/2CGXvFomY7S4tgpWRmYULtCK6jode0NhgNnAgOI9uy76pSS16aDoiQWUJqQgV
|
125
|
+
# ydowAnqS9h9aQ6gedwbOdtkWmwKMDVXU6aRz9Gvk+JeYJhtpuP3OPNGbbC5L7NVd
|
126
|
+
# no+B6AtwxmG3ozd+mPcMeVuz6kKLAmQyIiBSrRNa5OrTkq/CUzxO9WUgTnm/Sri7
|
127
|
+
# zReR6mU=
|
128
|
+
# -----END CERTIFICATE-----'
|
129
|
+
attr_accessor :own_signing_certificate
|
130
|
+
|
131
|
+
# The signing certificate signing request. Used in certificate requests.
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
# @example
|
135
|
+
# '-----BEGIN CERTIFICATE REQUEST-----
|
136
|
+
# MIIBczCB3QIBADA0MRIwEAYDVQQDEwlEZXZsYWIgT3kxETAPBgNVBAUTCDExMTEx
|
137
|
+
# MTExMQswCQYDVQQGEwJGSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAo9wU
|
138
|
+
# c2Ys5hSso4nEanbc+RIhL71aS6GBGiWAegXjhlyb6dpwigrZBFPw4u6UZV/Vq7Y7
|
139
|
+
# Ku3uBq5rfZwk+lA+c/B634Eu0zWdI+EYfQxKVRrBrmhiGplKEtglHXbNmmMOn07e
|
140
|
+
# LPUaB0Ipx/6h/UczJGBINdtcuIbYVu0r7ZfyWbUCAwEAAaAAMA0GCSqGSIb3DQEB
|
141
|
+
# BQUAA4GBAIhh2o8mN4Byn+w1jdbhq6lxEXYqdqdh1F6GCajt2lQMUBgYP23I5cS/
|
142
|
+
# Z+SYNhu8vbj52cGQPAwEDN6mm5yLpcXu40wYzgWyfStLXV9d/b4hMy9qLMW00Dzb
|
143
|
+
# jo2ekdSDdw8qxKyxj1piv8oYzMd4fCjCpL+WDZtq7mdLErVZ92gH
|
144
|
+
# -----END CERTIFICATE REQUEST-----'
|
145
|
+
attr_accessor :signing_csr
|
146
|
+
|
147
|
+
# Own encryption private key. Used to decrypt the response. In "pem" format.
|
148
|
+
#
|
149
|
+
# @return [String]
|
150
|
+
# @see #signing_private_key The format is the same as in signing private key
|
151
|
+
attr_accessor :encryption_private_key
|
152
|
+
|
153
|
+
# Bank's encryption certificate. The request is encrypted with this so that the bank can decrypt
|
154
|
+
# the request with their private key. In "pem" format.
|
155
|
+
#
|
156
|
+
# @return [String]
|
157
|
+
# @see #own_signing_certificate The format is the same as in own signing certificate
|
158
|
+
attr_accessor :bank_encryption_certificate
|
159
|
+
|
160
|
+
# Encryption certificate signing request. This needs to be generated and is then sent to the
|
161
|
+
# bank to be signed.
|
162
|
+
#
|
163
|
+
# @return [String]
|
164
|
+
# @see #signing_csr The format is the same as in signing csr
|
165
|
+
attr_accessor :encryption_csr
|
166
|
+
|
167
|
+
# The list of banks that are currently supported by this gem
|
26
168
|
BANKS = [:nordea, :danske]
|
169
|
+
|
170
|
+
# Languages that are currently supported by the gem
|
27
171
|
LANGUAGES = ['FI', 'SE', 'EN']
|
172
|
+
|
173
|
+
# Environments that are currently supported by the gem
|
28
174
|
ENVIRONMENTS = [:production, :test]
|
175
|
+
|
176
|
+
# Statuses that can be given to download file list command. When NEW is given, only those files
|
177
|
+
# that have not yet been downloaded will be listed. DOWNLOADED will list only downloaded files
|
178
|
+
# and ALL will list every file
|
29
179
|
STATUSES = ['NEW', 'DOWNLOADED', 'ALL']
|
30
180
|
|
31
181
|
validates :bank, inclusion: { in: BANKS }
|
@@ -46,6 +196,10 @@ module Sepa
|
|
46
196
|
validate :check_file_reference
|
47
197
|
validate :check_encryption_private_key
|
48
198
|
|
199
|
+
# Initializes the class. An optional hash of attributes can be given. Environment is set to
|
200
|
+
# production if not given, language to 'EN' and status to 'NEW'.
|
201
|
+
#
|
202
|
+
# @param hash [Hash] All the attributes of the client can be given to the construcor in a hash
|
49
203
|
def initialize(hash = {})
|
50
204
|
self.attributes hash
|
51
205
|
self.environment ||= :production
|
@@ -67,12 +221,29 @@ module Sepa
|
|
67
221
|
@environment = value.downcase.to_sym
|
68
222
|
end
|
69
223
|
|
224
|
+
# Sets the attributes given in a hash
|
225
|
+
#
|
226
|
+
# @param hash [Hash] Hash of parameters
|
227
|
+
# @example
|
228
|
+
# {
|
229
|
+
# bank: :nordea,
|
230
|
+
# command: :download_file_list
|
231
|
+
# }
|
70
232
|
def attributes(hash)
|
71
233
|
hash.each do |name, value|
|
72
234
|
send("#{name}=", value)
|
73
235
|
end
|
74
236
|
end
|
75
237
|
|
238
|
+
# Sends request to the bank specified in the attributes. First a new {SoapBuilder} class is
|
239
|
+
# initialized with a hash of the parameters given to the client with the {#create_hash} method.
|
240
|
+
# After this, a Savon client is initialized with a WSDL file got from {#wsdl}. After this, the
|
241
|
+
# Savon client makes the actual call to the server with the {#command} and the constructed
|
242
|
+
# {SoapBuilder}. After the call, the xml is extracted from the Savon response and the response
|
243
|
+
# is then checked for any Savon::Error errors. After this a {Response} is initialized using
|
244
|
+
# the {#initialize_response} method with the xml response and possible errors.
|
245
|
+
# @raise [ArgumentError] if some of the parameters are not valid
|
246
|
+
# @return [Response]
|
76
247
|
def send_request
|
77
248
|
raise ArgumentError, errors.messages unless valid?
|
78
249
|
|
@@ -93,6 +264,11 @@ module Sepa
|
|
93
264
|
|
94
265
|
private
|
95
266
|
|
267
|
+
# Creates a hash of all instance variables and their values. Before the actual hash is
|
268
|
+
# created, the {#signing_private_key} is converted to OpenSSL::PKey::RSA using
|
269
|
+
# {#initialize_signing_private_key} method.
|
270
|
+
#
|
271
|
+
# @return [Hash] All instance variables in a hash with their names as symbols as keys
|
96
272
|
def create_hash
|
97
273
|
initialize_signing_private_key
|
98
274
|
iv = {}
|
@@ -108,11 +284,14 @@ module Sepa
|
|
108
284
|
iv
|
109
285
|
end
|
110
286
|
|
287
|
+
# Converts the {#signing_private_key} from String to OpenSSL::PKey::RSA
|
288
|
+
# @return [OpenSSL::PKey::RSA]
|
111
289
|
def initialize_signing_private_key
|
112
290
|
@signing_private_key = rsa_key(@signing_private_key) if @signing_private_key
|
113
291
|
end
|
114
292
|
|
115
|
-
# Returns path to WSDL file
|
293
|
+
# Returns path to WSDL file according to {#bank} and {#command}
|
294
|
+
# @return [String] Path to the WSDL file of the bank and command
|
116
295
|
def wsdl
|
117
296
|
case bank
|
118
297
|
when :nordea
|
@@ -132,6 +311,12 @@ module Sepa
|
|
132
311
|
"#{WSDL_PATH}/#{file}"
|
133
312
|
end
|
134
313
|
|
314
|
+
# Initializes {Response} as correct class for a bank. Also converts possible
|
315
|
+
# {#encryption_private_key} from String to OpenSSL::PKey::RSA.
|
316
|
+
#
|
317
|
+
# @param error [String] Possible error got from {#send_request}
|
318
|
+
# @param response [String] A soap response in plain xml
|
319
|
+
# @return [Response] A {Response} with a correct class for a bank
|
135
320
|
def initialize_response(error, response)
|
136
321
|
options = {
|
137
322
|
response: response,
|
data/lib/sepa/error_messages.rb
CHANGED
@@ -1,27 +1,68 @@
|
|
1
1
|
module Sepa
|
2
|
+
|
3
|
+
# Contains error messages used in this gem
|
2
4
|
module ErrorMessages
|
3
|
-
|
5
|
+
|
6
|
+
# Error message which is shown when {Client#customer_id} validation fails
|
7
|
+
CUSTOMER_ID_ERROR_MESSAGE =
|
8
|
+
'Customer Id needs to be present and needs to have a length of less than 17 characters'
|
9
|
+
|
10
|
+
# Error message which is shown when {Client#environment} validation fails
|
4
11
|
ENVIRONMENT_ERROR_MESSAGE = 'Environment needs to be either production or test'
|
12
|
+
|
13
|
+
# Error message which is shown when {Client#target_id} validation fails
|
5
14
|
TARGET_ID_ERROR_MESSAGE = 'Target Id needs to be present and under 80 characters'
|
15
|
+
|
16
|
+
# Error message which is shown when {Client#file_type} validation fails
|
6
17
|
FILE_TYPE_ERROR_MESSAGE = 'File type needs to be present and under 35 characters'
|
18
|
+
|
19
|
+
# Error message which is shown when {Client#content} validation fails
|
7
20
|
CONTENT_ERROR_MESSAGE = 'Content needs to be present for this command'
|
21
|
+
|
22
|
+
# Error message which is shown when {Client#signing_csr} validation fails
|
8
23
|
SIGNING_CERT_REQUEST_ERROR_MESSAGE = 'Invalid signing certificate request'
|
24
|
+
|
25
|
+
# Error message which is shown when {Client#encryption_csr} validation fails
|
9
26
|
ENCRYPTION_CERT_REQUEST_ERROR_MESSAGE = 'Invalid encryption certificate request'
|
10
|
-
|
27
|
+
|
28
|
+
# Error message which is shown when {Client#pin} validation fails
|
29
|
+
PIN_ERROR_MESSAGE =
|
30
|
+
'Pin needs to be present for this command and cannot be more than 10 characters'
|
31
|
+
|
32
|
+
# Error message which is shown when {Client#bank_encryption_certificate} validation fails
|
11
33
|
ENCRYPTION_CERT_ERROR_MESSAGE = 'Invalid encryption certificate'
|
12
|
-
STATUS_ERROR_MESSAGE = 'Status is required for this command and must be either NEW, DOWNLOADED or ALL'
|
13
|
-
FILE_REFERENCE_ERROR_MESSAGE = 'File reference is required for this command and must be under 33 characters'
|
14
|
-
ENCRYPTION_PRIVATE_KEY_ERROR_MESSAGE = 'Encryption private key is needed for this bank and this command'
|
15
|
-
NOT_OK_RESPONSE_CODE_ERROR_MESSAGE = 'The response from the bank suggested there was ' \
|
16
|
-
'something wrong with your request, check your parameters and try again'
|
17
34
|
|
18
|
-
|
19
|
-
|
35
|
+
# Error message which is shown when {Client#status} validation fails
|
36
|
+
STATUS_ERROR_MESSAGE =
|
37
|
+
'Status is required for this command and must be either NEW, DOWNLOADED or ALL'
|
38
|
+
|
39
|
+
# Error message which is shown when {Client#file_reference} validation fails
|
40
|
+
FILE_REFERENCE_ERROR_MESSAGE =
|
41
|
+
'File reference is required for this command and must be under 33 characters'
|
42
|
+
|
43
|
+
# Error message which is shown when {Client#encryption_private_key} validation fails
|
44
|
+
ENCRYPTION_PRIVATE_KEY_ERROR_MESSAGE =
|
45
|
+
'Encryption private key is needed for this bank and this command'
|
46
|
+
|
47
|
+
# Error message which is shown when {Response#response_code} validation fails
|
48
|
+
NOT_OK_RESPONSE_CODE_ERROR_MESSAGE =
|
49
|
+
'The response from the bank suggested there was something wrong with your request, check ' \
|
50
|
+
'your parameters and try again'
|
51
|
+
|
52
|
+
# Error message which is shown when the response got from the bank cannot be decrypted with the
|
53
|
+
# private key that is given to the client
|
54
|
+
DECRYPTION_ERROR_MESSAGE =
|
55
|
+
'The response could not be decrypted with the private key that you gave. Check that the ' \
|
56
|
+
'key is the private key of your own encryption certificate'
|
20
57
|
|
21
|
-
|
22
|
-
|
58
|
+
# Error message which is shown when the hash embedded in the {Response} soap doesn't match the
|
59
|
+
# locally calculated one.
|
60
|
+
HASH_ERROR_MESSAGE =
|
61
|
+
'The hashes in the response did not match which means that the data in the response is not ' \
|
62
|
+
'intact'
|
23
63
|
|
24
|
-
|
25
|
-
|
64
|
+
# Error message which is shown when the signature in {Response} cannot be verified.
|
65
|
+
SIGNATURE_ERROR_MESSAGE =
|
66
|
+
'The signature in the response did not verify and the response cannot be trusted'
|
26
67
|
end
|
27
68
|
end
|