nordea-filetransfer 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Edgars Beigarts
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,159 @@
1
+ # Ruby client for Nordea FileTransfer
2
+
3
+ ```
4
+ Payload ApplicationRequest SOAP Envelope
5
+ +-------------------+ +---------------------+ +--------------------+
6
+ C | | | | | |
7
+ O | Content | | Customer ID | | SOAP Header |
8
+ R | | | Timestamp | | +----------------+ |
9
+ P | | | Environment | | | Signature | |
10
+ O | | | Target ID | | | ... | |
11
+ R | | | Encryption | | +----------------+ |
12
+ A | | | Compression | | |
13
+ T | | | Software ID | | |
14
+ E | | | File Type | | |
15
+ | | | +-----------------+ | | |
16
+ L | +-------> Content Base64 | | | SOAP Body |
17
+ E | | | +-----------------+ | | +----------------+ |
18
+ G | | | | | | Request Header | |
19
+ A | | | +-------> AppReq Base64 | |
20
+ C | | | | | +----------------+ |
21
+ Y | | | | | |
22
+ +-------------------+ +---------------------+ +--------------------+
23
+
24
+ 1. | 2. | 3. | 4. | 5.
25
+ Generate | Import | Builds XML structure | Transport | Creates WS Message
26
+ Legacy data | Payload | and signs it | App.Req. | and signs it
27
+
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ $ gem install nordea-filetransfer
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```ruby
39
+ require "noredea/file_transfer"
40
+
41
+ Nordea::FileTransfer.configure do |config|
42
+ config.language = "EN"
43
+ config.environment = "PRODUCTION"
44
+ config.user_agent = "Ruby"
45
+ config.software_id = "Ruby"
46
+ config.cert_file = "path/to/cert.pem"
47
+ config.private_key_file = "path/to/key.pem"
48
+ config.sender_id = 11111111
49
+ end
50
+
51
+ client = Nordea::FileTransfer::Client.new
52
+
53
+ response = client.get_user_info do |header, request|
54
+ header.receiver_id = 123456789
55
+ request.customer_id = 162355330
56
+ end
57
+
58
+ response.response_header
59
+ # => Nordea::FileTransfer::ResponseHeader
60
+
61
+ response.application_response
62
+ # => Nordea::FileTransfer::ApplicationResponse
63
+ ```
64
+
65
+ ### Get User Info
66
+
67
+ > The service will provide the client with information of
68
+ > authorized user file types and service ID’s.
69
+
70
+ ```ruby
71
+ response = client.get_user_info do |header, request|
72
+ header.receiver_id = 123456789
73
+ request.customer_id = 162355330,
74
+ end
75
+
76
+ response.application_response.user_file_types
77
+ # => [Nordea::FileTransfer::UserFileType, ...]
78
+ ```
79
+
80
+ ### Download File List
81
+
82
+ > The service will provide the client with a list of
83
+ > files that are available for download from Nordea.
84
+
85
+ ```ruby
86
+ response = client.download_file_list do |header, request|
87
+ header.receiver_id = 123456789
88
+ request.customer_id = 162355330
89
+ request.status = "ALL"
90
+ request.target_id = "11111111A1"
91
+ request.file_type = "NDCORPAYL"
92
+ end
93
+
94
+ response.application_response.file_descriptors
95
+ # => [Nordea::FileTransfer::FileDescriptor, ...]
96
+ ```
97
+
98
+ ### Download File
99
+
100
+ > The service will provide the client with requested files.
101
+ > Downloadable files can be checked by DownloadFileList –service. The query may be:
102
+ >
103
+ > - download single file
104
+ > - download multiple files
105
+ > - download all files of type
106
+ > - download all files
107
+
108
+ ```ruby
109
+ response = client.download_file do |header, request|
110
+ header.receiver_id = 123456789
111
+ request.customer_id = 162355330
112
+ request.file_references = ["2012082621423418"]
113
+ request.target_id = "11111111A1"
114
+ request.file_type = "VKEUR"
115
+ end
116
+
117
+ response.application_response.content
118
+ # => VK0100020120821154650Listakurssit alle 40.000 eur maksuille 21.08.12 15:35
119
+ # VK01001199901010730000001EUREUR00000100000000000010000000000001000000000000100000000000010000000+K000000000K
120
+ # VK01001201208211535490001USDEUR00000124280000000012578000000001227800000000127180000000012138000+K000000000K
121
+ # VK01001201208211535470001JPYEUR00009881000000001008100000000096810000000010252000000000951000000+K000000000K
122
+ # ...
123
+ ```
124
+
125
+ ### Upload File
126
+
127
+ > The Service will provide the transport of the customers file to Nordea.
128
+ > The response from Nordea will be a transport acknowledgement with details
129
+ > regarding the status of the transport.
130
+ >
131
+ > Backend system will process the files in batch mode. This means that the only
132
+ > verification of a file transfer, successful or not, will be a transfer
133
+ > acknowledgement. The client will not usually receive any other notification and
134
+ > the result must be retrieved with a new call later.
135
+
136
+ ```ruby
137
+ response = client.upload_file do |header, request|
138
+ header.receiver_id = 123456789
139
+ request.customer_id = 162355330
140
+ request.target_id = "11111111A1"
141
+ request.service_id = "0012345678"
142
+ request.file_type = "CNFTC000S"
143
+ request.user_filename = "TEST.TXT"
144
+ request.content = "..."
145
+ end
146
+ ```
147
+
148
+ ## References
149
+
150
+ * [Nordea: Web Services Security and Communication (PDF)](http://www.nordea.fi/sitemod/upload/root/fi_org/liite/e/yritys/pdf/web_services_ohjelmistotalot.pdf)
151
+ * [Nordea: Web Services (PDF)](http://www.nordea.fi/sitemod/upload/root/fi_org/liite/e/yritys/pdf/web_services.pdf)
152
+ * [Nordea: File Transfer Service Description (PDF)](http://www.nordea.fi/sitemod/upload/Root/fi_org/liite/e/yritys/pdf/erasiir.pdf)
153
+ * [Nordea: File Transfer Instructions (HTML)](http://www.nordea.fi/Corporate+customers/Payments+and+cards/Advice+on+payments+and+cards/Instructions/1433022.html)
154
+ * [Nordea: File Transfer Example files (HTML)](http://www.nordea.fi/Corporate+customers/Payments+and+cards/Advice+on+payments+and+cards/Example+files/1466002.html)
155
+ * [Nordea: File Transfer WSDL (XML)](https://filetransfer.nordea.com/services/CorporateFileService?wsdl)
156
+ * [Nordea: File Transfer WSDL: XSD1 (XML)](https://filetransfer.nordea.com/services/CorporateFileService.xsd1.xsd)
157
+ * [Nordea: File Transfer WSDL: XSD2 (XML)](https://filetransfer.nordea.com/services/CorporateFileService.xsd2.xsd)
158
+ * [Nordea: File Transfer WSDL: ApplicationRequest.xsd (XML)](http://www.nordea.fi/sitemod/upload/root/fi_org/liite/ApplicationRequest.xsd)
159
+ * [Nordea: File Transfer WSDL: ApplicationResponse.xsd (XML)](http://www.nordea.fi/sitemod/upload/root/fi_org/liite/ApplicationResponse.xsd)
@@ -0,0 +1 @@
1
+ require "nordea/file_transfer"
@@ -0,0 +1,28 @@
1
+ require 'savon'
2
+ require 'virtus'
3
+ require 'signer'
4
+ require 'active_support/core_ext'
5
+
6
+ require 'nordea/file_transfer/version'
7
+
8
+ module Nordea
9
+ module FileTransfer
10
+ autoload :Config, 'nordea/file_transfer/config'
11
+ autoload :Client, 'nordea/file_transfer/client'
12
+ autoload :Error, 'nordea/file_transfer/error'
13
+ autoload :Attributes, 'nordea/file_transfer/attributes'
14
+
15
+ autoload :Request, 'nordea/file_transfer/request'
16
+ autoload :RequestHeader, 'nordea/file_transfer/request_header'
17
+ autoload :ApplicationRequest, 'nordea/file_transfer/application_request'
18
+
19
+ autoload :Response, 'nordea/file_transfer/response'
20
+ autoload :ResponseHeader, 'nordea/file_transfer/response_header'
21
+ autoload :ApplicationResponse, 'nordea/file_transfer/application_response'
22
+ autoload :FileTypeService, 'nordea/file_transfer/file_type_service'
23
+ autoload :UserFileType, 'nordea/file_transfer/user_file_type'
24
+ autoload :FileDescriptor, 'nordea/file_transfer/file_descriptor'
25
+
26
+ extend Config
27
+ end
28
+ end
@@ -0,0 +1,67 @@
1
+ module Nordea
2
+ module FileTransfer
3
+ # http://www.nordea.fi/sitemod/upload/root/fi_org/liite/ApplicationRequest.xsd
4
+ class ApplicationRequest
5
+ include Virtus
6
+
7
+ attribute :customer_id, String, :required => true
8
+ attribute :command, String
9
+ attribute :timestamp, DateTime, :required => true
10
+ attribute :start_date, Date
11
+ attribute :end_date, Date
12
+ attribute :status, String, :length => 1..10 # (NEW|DOWNLOADED|ALL)
13
+ attribute :service_id, String
14
+ attribute :environment, String, :required => true # (PRODUCTION|TEST)
15
+ attribute :file_references, Array[String]
16
+ attribute :user_filename, String
17
+ attribute :target_id, String
18
+ attribute :execution_serial, String
19
+ attribute :encryption, Boolean
20
+ attribute :encryption_method, String
21
+ attribute :compression, Boolean
22
+ attribute :compression_method, String
23
+ attribute :amount_total, BigDecimal
24
+ attribute :transaction_count, Integer
25
+ attribute :software_id, String
26
+ attribute :customer_extension, String
27
+ attribute :file_type, String, :length => 1..40
28
+ attribute :content, Attributes::EncodedBase64String
29
+
30
+ def to_hash
31
+ hash = {
32
+ "ApplicationRequest" => { },
33
+ :attributes! => {
34
+ "ApplicationRequest" => { "xmlns" => "http://bxd.fi/xmldata/" }
35
+ }
36
+ }
37
+ attributes.each do |key, value|
38
+ next unless value
39
+ if value.is_a?(Array) && value.size > 0
40
+ hash["ApplicationRequest"][key.to_s.camelcase] = { key.to_s.camelcase[0..-2] => value }
41
+ else
42
+ hash["ApplicationRequest"][key.to_s.camelcase] = value
43
+ end
44
+ end
45
+ hash
46
+ end
47
+
48
+ def to_xml
49
+ Gyoku.xml(to_hash)
50
+ end
51
+
52
+ def to_signed_xml(options)
53
+ signer = Signer.new(to_xml)
54
+ signer.cert = options[:cert]
55
+ signer.private_key = options[:private_key]
56
+ signer.security_node = signer.document.root
57
+ signer.digest!(signer.document, :id => "", :enveloped => true)
58
+ signer.sign!(:issuer_serial => true)
59
+ signer.canonicalize
60
+ end
61
+
62
+ def to_signed_and_encoded_xml(options)
63
+ Base64.encode64(to_signed_xml(options)).gsub("\n", "")
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ module Nordea
2
+ module FileTransfer
3
+ # http://www.nordea.fi/sitemod/upload/root/fi_org/liite/ApplicationResponse.xsd
4
+ class ApplicationResponse
5
+ include Virtus
6
+
7
+ attribute :customer_id, String
8
+ attribute :timestamp, DateTime
9
+ attribute :response_code, String
10
+ attribute :response_text, String
11
+ attribute :execution_serial, String
12
+ attribute :encrypted, Boolean
13
+ attribute :encryption_method, String
14
+ attribute :compressed, Boolean
15
+ attribute :compression_method, String
16
+ attribute :amount_total, BigDecimal
17
+ attribute :transaction_count, Integer
18
+ attribute :file_descriptors, Array[FileDescriptor], :default => []
19
+ attribute :customer_extension, String
20
+ attribute :file_type, String
21
+ attribute :user_file_types, Array[UserFileType], :default => []
22
+
23
+ attribute :content, Attributes::DecodedBase64String
24
+ attribute :signature, Hash
25
+
26
+ def initialize(attributes = {})
27
+ if attributes.is_a?(String)
28
+ attributes = Nori.parse(Base64.decode64(attributes))[:application_response]
29
+ end
30
+ if attributes[:user_file_types]
31
+ attributes[:user_file_types] = Array.wrap(attributes[:user_file_types][:user_file_type])
32
+ end
33
+ if attributes[:file_descriptors]
34
+ attributes[:file_descriptors] = Array.wrap(attributes[:file_descriptors][:file_descriptor])
35
+ end
36
+ super(attributes)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require "base64"
2
+
3
+ module Nordea
4
+ module FileTransfer
5
+ module Attributes
6
+ class EncodedBase64String < Virtus::Attribute::Object
7
+ primitive String
8
+
9
+ def coerce(value)
10
+ value && Base64.encode64(value).chomp
11
+ end
12
+ end
13
+
14
+ class DecodedBase64String < Virtus::Attribute::Object
15
+ primitive String
16
+
17
+ def coerce(value)
18
+ value && Base64.decode64(value)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,122 @@
1
+ require "securerandom"
2
+
3
+ module Nordea
4
+ module FileTransfer
5
+ class Client
6
+ include Config
7
+
8
+ def initialize(options = {})
9
+ Nordea::FileTransfer.config.keys.each do |key|
10
+ send("#{key}=", options[key] || Nordea::FileTransfer.config.send(key))
11
+ end
12
+
13
+ @savon_client = Savon::Client.new do |wsdl, http, wsse|
14
+ # Do not fetch wsdl document, use namespace and endpoint instead.
15
+ wsdl.document = "https://filetransfer.nordea.com/services/CorporateFileService?wsdl"
16
+ wsdl.endpoint = "https://filetransfer.nordea.com/services/CorporateFileService"
17
+ certs = Akami::WSSE::Certs.new(:cert_file => @cert_file, :private_key_file => @private_key_file)
18
+ wsse.signature = Akami::WSSE::Signature.new(certs)
19
+ wsse.verify_response = false
20
+ end
21
+ end
22
+
23
+ # Get User Info
24
+ #
25
+ # The service will provide the client with information of
26
+ # authorized user file types and service ID’s.
27
+ def get_user_info(&block)
28
+ request :get_user_info, &block
29
+ end
30
+
31
+ # Download File List
32
+ #
33
+ # The service will provide the client with a list of
34
+ # files that are available for download from Nordea.
35
+ def download_file_list(&block)
36
+ request :download_file_list, &block
37
+ end
38
+
39
+ # Download File
40
+ #
41
+ # The service will provide the client with requested files.
42
+ # Downloadable files can be checked by DownloadFileList –service.
43
+ #
44
+ # The query may be:
45
+ #
46
+ # * download single file
47
+ # * download multiple files
48
+ # * download all files of type
49
+ # * download all files
50
+ def download_file(&block)
51
+ request :download_file, &block
52
+ end
53
+
54
+ # Upload File
55
+ #
56
+ # The Service will provide the transport of the customers file to Nordea.
57
+ # The response from Nordea will be a transport acknowledgement with details
58
+ # regarding the status of the transport.
59
+ #
60
+ # Backend system will process the files in batch mode. This means that the only
61
+ # verification of a file transfer, successful or not, will be a transfer
62
+ # acknowledgement. The client will not usually receive any other notification and
63
+ # the result must be retrieved with a new call later.
64
+ def upload_file(&block)
65
+ request :upload_file, &block
66
+ end
67
+
68
+ private
69
+
70
+ def cert
71
+ OpenSSL::X509::Certificate.new(File.read(cert_file))
72
+ end
73
+
74
+ def private_key
75
+ OpenSSL::PKey::RSA.new(File.read(private_key_file), private_key_password)
76
+ end
77
+
78
+ def request(action)
79
+ response = @savon_client.request action do
80
+ soap.namespaces["xmlns"] = "http://model.bxd.fi"
81
+ soap.namespaces["xmlns:xsns"] = "http://bxd.fi/CorporateFileService"
82
+
83
+ timestamp = Time.now
84
+
85
+ req = Request.new
86
+ req.cert = cert
87
+ req.private_key = private_key
88
+
89
+ req.request_header = RequestHeader.new
90
+ req.request_header.sender_id = sender_id
91
+ req.request_header.request_id = SecureRandom.hex(32)
92
+ req.request_header.timestamp = timestamp
93
+ req.request_header.language = language
94
+ req.request_header.user_agent = user_agent
95
+ req.request_header.receiver_id = receiver_id
96
+
97
+ req.application_request = ApplicationRequest.new
98
+ req.application_request.customer_id = customer_id
99
+ req.application_request.command = action.to_s.camelcase
100
+ req.application_request.timestamp = timestamp
101
+ req.application_request.environment = environment
102
+ req.application_request.software_id = software_id
103
+
104
+ if block_given?
105
+ yield req.request_header, req.application_request
106
+ end
107
+
108
+ soap.body = req.to_hash
109
+ end
110
+ response_params = response.to_hash[:"#{action}out"]
111
+ if response_params[:response_header][:response_code] == "00"
112
+ Response.new(response_params)
113
+ else
114
+ raise Error.new(
115
+ response_params[:response_header][:response_code],
116
+ response_params[:response_header][:response_text]
117
+ )
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end