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 +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
|