nordea-filetransfer 0.2.1

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