epics 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a022ab9e8c8af9a64b970a4d927b53f09321b6767545bee5c584538aa4a296a
4
- data.tar.gz: 3dd7d404d54e32fe14993ba0272e666b94f38e1238d304c916d373ea057bff75
3
+ metadata.gz: fe32a608bfa8bc6ba0e5efdd4a7f9970012fcbc77301fbdc17b69e463bae5f99
4
+ data.tar.gz: 5f4d10b3381e803e1db5799a3383fd52bd766c30c087149fb2fdbf6123de2f5e
5
5
  SHA512:
6
- metadata.gz: d821c36ea05aa51c005dd1dc6b86cd28f8067faf746e556e87f098fecd1a1951c2e33f3ee4a2df494a0df54e168b07f3155ea60be132a4663711a39ab03f8116
7
- data.tar.gz: b48e1f0da804c867f0ce292f2db56352745f515607ea2292bae08c689fb6124b7c025aa4463792042a0e85feda8b4a0016b612c97cbb443d0648e5f499e84967
6
+ metadata.gz: 2b5ff6b89a856fe9b10df88fa9a3b289fa2ebf5d44a936d60ef7d6c5c5d5024d66fce09dbbbe7ff51c364833bb5d9ca5ffcb4ff9673bde6d2a18611569f09867
7
+ data.tar.gz: 8a636c50118dc65fe444a8672e9ef691a585749adfa545fc731fe19977d41b7263fe4739258116eaba219d349dcf9e2429c5fd794cc7cab18ffd814a86bacdb0
@@ -16,36 +16,27 @@ blocks:
16
16
  - name: Spec versions
17
17
  task:
18
18
  jobs:
19
- - name: "2.4"
20
- commands:
21
- - checkout
22
- - sem-version ruby 2.4
23
- - cache restore
24
- - bundle install
25
- - cache store
26
- - bundle exec rspec
27
- - name: "2.5"
19
+ - name: "2.6"
28
20
  commands:
29
21
  - checkout
30
- - sem-version ruby 2.5
22
+ - sem-version ruby 2.6
31
23
  - cache restore
32
24
  - bundle install
33
25
  - cache store
34
26
  - bundle exec rspec
35
- - name: "2.6"
27
+ - name: "2.7"
36
28
  commands:
37
29
  - checkout
38
- - sem-version ruby 2.6
30
+ - sem-version ruby 2.7
39
31
  - cache restore
40
32
  - bundle install
41
33
  - cache store
42
34
  - bundle exec rspec
43
- - name: "jruby-9.2.0.0"
35
+ - name: "3.0"
44
36
  commands:
45
37
  - checkout
46
- - sem-version ruby jruby-9.2.0.0
38
+ - sem-version ruby 3.0
47
39
  - cache restore
48
- - gem install bundler
49
40
  - bundle install
50
41
  - cache store
51
42
  - bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 2.0.0
2
+ - [BUGFIX] Add Openssl 3.0 support
3
+ - [BUGFIX] Update CDZ to download data, not upload it
4
+ - [BUGFIX] Support signature for keys later than 2048 bit
5
+ - [HOUSEKEEPING] Open rubyzip dependency to allow newer versions and update it
6
+ - [HOUSEKEEPING] Update supported ruby versions to 2.6+
7
+ - [HOUSEKEEPING] Update faraday, nokogiri, and development dependencies
8
+ - [HOUSEKEEPING] Remove JRuby test execution due to failing tests - needs to be re-added if required
9
+ - [ENHANCEMENT] Adds CRZ order type
10
+ - [ENHANCEMENT] Make date period optional for CDZ order type
11
+
12
+ ### 1.8.1
13
+ - [BUGFIX] Remove masking of transport client errors
14
+
1
15
  ### 1.8.0
2
16
 
3
17
  - [HOUSEKEEPING] updates faraday and rubyzip
data/CONTRIBUTING.md CHANGED
@@ -1,3 +1,44 @@
1
- # Contributing to Epics
1
+ # Individual Contributor Non-Exclusive License Agreement
2
2
 
3
- To get started, <a href="https://www.clahub.com/agreements/railslove/epics">sign the Contributor License Agreement</a>.
3
+ Note: This CLA is for Individual Copyright owner only. If You would like to submit your Contribution as part of your employment or as Legal Entity, please contact Us at team@railslove.com first.
4
+
5
+ Thank you for your interest in contributing to the project **„epics - EBICS client for Ruby“ from Railslove GmbH, An der Bottmuehle 5, 50678 Cologne, Germany (“We” or “Us”).**
6
+ The purpose of this contributor agreement (**“Agreement”**) is to clarify and document the rights granted by contributors to Us.
7
+
8
+ ### 1. DEFINITIONS
9
+ **“You”** means the Individual Copyright owner who submits a Contribution to Us. If You are either a Legal Entity or submit the Contribution as part of your employment, please contact Us at team@railslove.com first.
10
+ **“Contribution”** means any original work of authorship (software and/or documentation) including any modifications or additions to an existing work, Submitted by You to Us, in which You own the Copyright. If You do not own the Copyright in the entire work of authorship, please contact Us at team@railslove.com.
11
+ **“Copyright”** means all rights protecting works of authorship owned or controlled by You, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You.
12
+ **“Material”** means the software or documentation made available by Us to third parties. When this Agreement covers more than one software project, the Material means the software or documentation to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material.
13
+ **“Submit”** means any form of physical, electronic, or written communication sent to Us, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us, but excluding communication that is conspicuously marked or otherwise designated in writing by You as “Not a Contribution.”
14
+ **“Submission Date”** means the date You Submit a Contribution to Us.
15
+ **“Documentation”** means any non-software portion of a Contribution.
16
+
17
+ ### 2. LICENSE GRANT
18
+ 2.1 Copyright License to Us
19
+ Subject to the terms and conditions of this Agreement, You hereby grant to Us a worldwide, royalty-free, NON-exclusive, perpetual and irrevocable license, with the right to transfer an unlimited number of non-exclusive licenses or to grant sublicenses to third parties, under the Copyright covering the Contribution to use the Contribution by all means, including, but not limited to:
20
+ - to publish the Contribution,
21
+ - to modify the Contribution, to prepare derivative works based upon or containing the Contribution and to combine the Contribution with other software code,
22
+ - to reproduce the Contribution in original or modified form,
23
+ - to distribute, to make the Contribution available to the public, display and publicly perform the Contribution in original or modified form.
24
+
25
+ 2.2 Moral Rights remain unaffected to the extent they are recognized and not waivable by applicable law. Notwithstanding, You may add your name in the header of the source code files of Your Contribution and We will respect this attribution when using Your Contribution.
26
+
27
+ ### 3. DISCLAIMER
28
+ THE CONTRIBUTION IS PROVIDED “AS IS”. MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US AND BY US TO YOU. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW.
29
+
30
+ ### 4. Consequential Damage Waiver
31
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU OR US BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED.
32
+
33
+ ### 5. Approximation of Disclaimer and Damage Waiver
34
+ IF THE DISCLAIMER AND DAMAGE WAIVER MENTIONED IN SECTION 3 AND SECTION 4 CANNOT BE GIVEN LEGAL EFFECT UNDER APPLICABLE LOCAL LAW, REVIEWING COURTS SHALL APPLY LOCAL LAW THAT MOST CLOSELY APPROXIMATES AN ABSOLUTE WAIVER OF ALL CIVIL LIABILITY IN CONNECTION WITH THE CONTRIBUTION.
35
+
36
+ ### 6. Term
37
+ 6.1 This Agreement shall come into effect upon Your acceptance of the terms and conditions.
38
+ 6.2 In the event of a termination of this Agreement Sections 3, 4, 5, 6 and 7 shall survive such termination and shall remain in full force thereafter. For the avoidance of doubt, Contributions that are already licensed under a free and open source license at the date of the termination shall remain in full force after the termination of this Agreement.
39
+
40
+ ### 7. Miscellaneous
41
+ 7.1 This Agreement and all disputes, claims, actions, suits or other proceedings arising out of this agreement or relating in any way to it shall be governed by the laws of Germany excluding its private international law provisions.
42
+ 7.2 This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings.
43
+ 7.3 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and that is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law.
44
+ 7.4 You agree to notify Us of any facts or circumstances of which you become aware that would make this Agreement inaccurate in any respect.
data/README.md CHANGED
@@ -244,6 +244,7 @@ EPICS_VERIFY_SSL=false
244
244
  - [Die Deutsche Kreditwirtschaft](http://www.die-deutsche-kreditwirtschaft.de/)
245
245
 
246
246
  ## Contributing
247
+ Railslove has a [Contributor License Agreement (CLA)](https://github.com/railslove/epics/blob/master/CONTRIBUTING.md) which clarifies the intellectual property rights for contributions from individuals or entities. To ensure every developer has signed the CLA, we use [CLA Assistant](https://cla-assistant.io/).
247
248
 
248
249
  0. Contact team@railslove.com for information about the CLA
249
250
  1. Fork it ( https://github.com/[my-github-username]/epics/fork )
@@ -264,4 +265,4 @@ EPICS_VERIFY_SSL=false
264
265
 
265
266
  ---
266
267
 
267
- 2014-2019 - built with love by [Railslove](http://railslove.com) and released under the [GNU LESSER GENERAL PUBLIC LICENSE](https://github.com/railslove/epics/blob/master/LICENSE.txt). We have built quite a number of FinTech products. If you need support we are happy to help. Please contact us at team@railslove.com.
268
+ 2014-2022 - built with love by [Railslove](http://railslove.com) and released under the [GNU LESSER GENERAL PUBLIC LICENSE](https://github.com/railslove/epics/blob/master/LICENSE.txt). We have built quite a number of FinTech products. If you need support we are happy to help. Please contact us at team@railslove.com.
data/epics.gemspec CHANGED
@@ -20,13 +20,13 @@ Gem::Specification.new do |spec|
20
20
  STA HAA HTD HPD PKT HAC HKD C52 C53 C54
21
21
 
22
22
  And the following upload orders:
23
- CD1 CDD CCT CDB CDS CCS CDZ
23
+ CD1 CDD CCT CDB CDS CCS CDZ CRZ
24
24
  description
25
25
 
26
26
  spec.homepage = 'https://github.com/railslove/epics'
27
27
  spec.license = 'LGPL-3.0'
28
28
 
29
- spec.required_ruby_version = '>= 2.4'
29
+ spec.required_ruby_version = '>= 2.6'
30
30
 
31
31
  spec.files = `git ls-files -z`.split("\x0")
32
32
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -40,11 +40,11 @@ Gem::Specification.new do |spec|
40
40
  spec.post_install_message += "Please create an issue on github (railslove/epics) if anything does not work as expected. And contact team@railslove.com if you are looking for support with your integration.\n"
41
41
  spec.post_install_message += "\e[32m" + ('*' * 60) + "\n\e[0m"
42
42
 
43
- spec.add_dependency 'faraday', '>= 1.0.0'
44
- spec.add_dependency 'nokogiri', '>= 1.10.7'
45
- spec.add_dependency 'rubyzip', '2.2.0'
43
+ spec.add_dependency 'faraday', '>= 1.10.0'
44
+ spec.add_dependency 'nokogiri', '>= 1.13.9'
45
+ spec.add_dependency 'rubyzip', '>= 2.3.2'
46
46
 
47
- spec.add_development_dependency 'bundler', '>= 1.6.2'
47
+ spec.add_development_dependency 'bundler', '>= 1.17.3'
48
48
  spec.add_development_dependency 'equivalent-xml'
49
49
  spec.add_development_dependency 'pry'
50
50
  spec.add_development_dependency 'rake', '~> 13.0'
data/lib/epics/cdz.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Epics::CDZ < Epics::GenericRequest
2
2
  attr_accessor :from, :to
3
3
 
4
- def initialize(client, from, to)
4
+ def initialize(client, from = nil, to = nil)
5
5
  super(client)
6
6
  self.from = from
7
7
  self.to = to
@@ -20,13 +20,17 @@ class Epics::CDZ < Epics::GenericRequest
20
20
  xml.OrderDetails {
21
21
  xml.OrderType 'CDZ'
22
22
  xml.OrderAttribute 'DZHNN'
23
- xml.StandardOrderParams {
24
- xml.DateRange {
25
- xml.Start from
26
- xml.End to
23
+ if !!from && !!to
24
+ xml.StandardOrderParams {
25
+ xml.DateRange {
26
+ xml.Start from
27
+ xml.End to
28
+ }
27
29
  }
28
- }
29
- }
30
+ else
31
+ xml.StandardOrderParams
32
+ end
33
+ }
30
34
  xml.BankPubKeyDigests {
31
35
  xml.Authentication(client.bank_x.public_digest, Version: 'X002', Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256")
32
36
  xml.Encryption(client.bank_e.public_digest, Version: 'E002', Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" )
data/lib/epics/client.rb CHANGED
@@ -143,10 +143,6 @@ class Epics::Client
143
143
  upload(Epics::XDS, document)
144
144
  end
145
145
 
146
- def CDZ(document)
147
- upload(Epics::CDZ, document)
148
- end
149
-
150
146
  def CCT(document)
151
147
  upload(Epics::CCT, document)
152
148
  end
@@ -167,6 +163,14 @@ class Epics::Client
167
163
  download(Epics::VMK, from, to)
168
164
  end
169
165
 
166
+ def CDZ(from = nil, to = nil)
167
+ download_and_unzip(Epics::CDZ, from, to)
168
+ end
169
+
170
+ def CRZ(from = nil, to = nil)
171
+ download_and_unzip(Epics::CRZ, from, to)
172
+ end
173
+
170
174
  def C52(from, to)
171
175
  download_and_unzip(Epics::C52, from, to)
172
176
  end
@@ -265,14 +269,16 @@ class Epics::Client
265
269
  JSON.dump(keys.each_with_object({}) {|(k,v),m| m[k]= encrypt(v.key.to_pem)})
266
270
  end
267
271
 
268
- def cipher
269
- @cipher ||= OpenSSL::Cipher.new("aes-256-cbc")
272
+ def new_cipher
273
+ # Re-using the cipher between keys has weird behaviours with openssl3
274
+ # Using a fresh key instead of memoizing it on the client simplifies things
275
+ OpenSSL::Cipher.new('aes-256-cbc')
270
276
  end
271
277
 
272
278
  def encrypt(data)
273
279
  salt = OpenSSL::Random.random_bytes(8)
274
280
 
275
- setup_cipher(:encrypt, self.passphrase, salt)
281
+ cipher = setup_cipher(:encrypt, self.passphrase, salt)
276
282
  Base64.strict_encode64([salt, cipher.update(data) + cipher.final].join)
277
283
  end
278
284
 
@@ -281,13 +287,15 @@ class Epics::Client
281
287
  salt = data[0..7]
282
288
  data = data[8..-1]
283
289
 
284
- setup_cipher(:decrypt, self.passphrase, salt)
290
+ cipher = setup_cipher(:decrypt, self.passphrase, salt)
285
291
  cipher.update(data) + cipher.final
286
292
  end
287
293
 
288
294
  def setup_cipher(method, passphrase, salt)
295
+ cipher = new_cipher
289
296
  cipher.send(method)
290
297
  cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(passphrase, salt, 1, cipher.key_len)
298
+ cipher
291
299
  end
292
300
 
293
301
  def verify_ssl?
data/lib/epics/crz.rb ADDED
@@ -0,0 +1,46 @@
1
+ class Epics::CRZ < Epics::GenericRequest
2
+ attr_accessor :from, :to
3
+
4
+ def initialize(client, from = nil, to = nil)
5
+ super(client)
6
+ self.from = from
7
+ self.to = to
8
+ end
9
+
10
+ def header
11
+ Nokogiri::XML::Builder.new do |xml|
12
+ xml.header(authenticate: true) {
13
+ xml.static {
14
+ xml.HostID host_id
15
+ xml.Nonce nonce
16
+ xml.Timestamp timestamp
17
+ xml.PartnerID partner_id
18
+ xml.UserID user_id
19
+ xml.Product("EPICS - a ruby ebics kernel", 'Language' => 'de')
20
+ xml.OrderDetails {
21
+ xml.OrderType 'CRZ'
22
+ xml.OrderAttribute 'DZHNN'
23
+ if !!from && !!to
24
+ xml.StandardOrderParams {
25
+ xml.DateRange {
26
+ xml.Start from
27
+ xml.End to
28
+ }
29
+ }
30
+ else
31
+ xml.StandardOrderParams
32
+ end
33
+ }
34
+ xml.BankPubKeyDigests {
35
+ xml.Authentication(client.bank_x.public_digest, Version: 'X002', Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256")
36
+ xml.Encryption(client.bank_e.public_digest, Version: 'E002', Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" )
37
+ }
38
+ xml.SecurityMedium '0000'
39
+ }
40
+ xml.mutable {
41
+ xml.TransactionPhase 'Initialisation'
42
+ }
43
+ }
44
+ end.doc.root
45
+ end
46
+ end
data/lib/epics/error.rb CHANGED
@@ -308,7 +308,7 @@ class Epics::Error < StandardError
308
308
  },
309
309
  "091301" => {
310
310
  "symbol" => "EBICS_SIGNATURE_VERIFICATION_FAILED",
311
- "short_text" => "Verification of the ES has failed In the case of asynchronouslyimplemented orders, the error can occur during preliminary verification."
311
+ "short_text" => "Verification of the ES has failed In the case of asynchronously implemented orders, the error can occur during preliminary verification."
312
312
  },
313
313
  "091302" => {
314
314
  "symbol" => "EBICS_ACCOUNT_AUTHORISATION_FAILED",
@@ -334,4 +334,3 @@ class Epics::Error < StandardError
334
334
  end
335
335
 
336
336
  end
337
- class Epics::Error::UnknownError < StandardError; end
data/lib/epics/key.rb CHANGED
@@ -29,51 +29,19 @@ class Epics::Key
29
29
  self.key.e.to_s(16)
30
30
  end
31
31
 
32
- def sign(msg, salt = OpenSSL::Random.random_bytes(32) )
33
- Base64.encode64(mod_pow(OpenSSL::BN.new(emsa_pss(msg, salt).to_s, 2), self.key.d, self.key.n).to_s(2)).gsub("\n", "")
34
- end
35
-
36
- def recover(msg)
37
- mod_pow(OpenSSL::BN.new(msg.to_s, 2), self.key.e, self.key.n).to_s(2)
32
+ def sign(msg)
33
+ Base64.encode64(
34
+ key.sign_pss(
35
+ 'SHA256',
36
+ msg,
37
+ salt_length: :digest,
38
+ mgf1_hash: 'SHA256',
39
+ ),
40
+ ).gsub("\n", '')
38
41
  end
39
42
 
40
43
  def digester
41
44
  @digester ||= OpenSSL::Digest::SHA256.new
42
45
  end
43
46
 
44
- private
45
-
46
- ##
47
- # http://de.wikipedia.org/wiki/Probabilistic_Signature_Scheme
48
- ##
49
- def emsa_pss(msg, salt)
50
- m_tick_hash = digester.digest [("\x00" * 8), digester.digest(msg), salt].join
51
-
52
- ps = "\x00" * 190
53
- db = [ps, "\x01", salt].join
54
-
55
- db_mask = Epics::MGF1.new.generate(m_tick_hash, db.size)
56
- masked_db = Epics::MGF1.new.xor(db, db_mask)
57
-
58
- masked_db_msb = OpenSSL::BN.new(masked_db[0], 2).to_i.to_s(2).rjust(8, "0")
59
- masked_db_msb[0] = "0"
60
-
61
- masked_db[0] = OpenSSL::BN.new(masked_db_msb.to_i(2).to_s).to_s(2)
62
-
63
- [masked_db, m_tick_hash, ["BC"].pack("H*") ].join
64
- end
65
-
66
- def mod_pow(base, power, mod)
67
- base = base.to_i
68
- power = power.to_i
69
- mod = mod.to_i
70
- result = 1
71
- while power > 0
72
- result = (result * base) % mod if power & 1 == 1
73
- base = (base * base) % mod
74
- power >>= 1
75
- end
76
- OpenSSL::BN.new(result.to_s)
77
- end
78
-
79
47
  end
@@ -9,12 +9,8 @@ class Epics::ParseEbics < Faraday::Middleware
9
9
  def call(env)
10
10
  @app.call(env).on_complete do |response|
11
11
  response.body = ::Epics::Response.new(@client, response.body)
12
- raise Epics::Error::TechnicalError, response.body.technical_code if response.body.technical_error?
13
- raise Epics::Error::BusinessError, response.body.business_code if response.body.business_error?
12
+ raise(Epics::Error::TechnicalError, response.body.technical_code) if response.body.technical_error?
13
+ raise(Epics::Error::BusinessError, response.body.business_code) if response.body.business_error?
14
14
  end
15
- rescue Epics::Error::TechnicalError, Epics::Error::BusinessError
16
- raise # re-raise as otherwise they would be swallowed by the following rescue
17
- rescue StandardError => e
18
- raise Epics::Error::UnknownError, e
19
15
  end
20
16
  end
data/lib/epics/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Epics
4
- VERSION = '1.8.0'
4
+ VERSION = '2.0.0'
5
5
  end
data/lib/epics.rb CHANGED
@@ -10,7 +10,6 @@ require 'securerandom'
10
10
  require 'time'
11
11
  require "epics/version"
12
12
  require "epics/key"
13
- require "epics/mgf"
14
13
  require "epics/response"
15
14
  require "epics/error"
16
15
  require "epics/middleware/xmlsig"
@@ -39,6 +38,7 @@ require "epics/b2b"
39
38
  require "epics/xds"
40
39
  require "epics/cds"
41
40
  require "epics/cdz"
41
+ require "epics/crz"
42
42
  require "epics/xct"
43
43
  require "epics/hia"
44
44
  require "epics/ini"
@@ -1,6 +1,7 @@
1
1
  RSpec.describe Epics::GenericUploadRequest do
2
2
  let(:client) { Epics::Client.new( File.open(File.join( File.dirname(__FILE__), 'fixtures', 'SIZBN001.key')), 'secret' , 'https://194.180.18.30/ebicsweb/ebicsweb', 'SIZBN001', 'EBIX', 'EBICS') }
3
- subject { described_class.new(client, "\x01" * 12) }
3
+ let(:document) { "\x01" * 12 }
4
+ subject { described_class.new(client, document) }
4
5
 
5
6
  describe '#pad' do
6
7
 
@@ -22,7 +23,17 @@ RSpec.describe Epics::GenericUploadRequest do
22
23
  before { allow(OpenSSL::Random).to receive(:random_bytes).with(32).and_return(Base64.strict_decode64("7wtROfiX4tyN60cygJUSsHkhzxX1RVJa8vGNYnflvKc=")) } # digest requires 32 bytes
23
24
 
24
25
  it 'will be the signed document' do
25
- expect(subject.signature_value).to eq("BQBMyxGHYoAbbmbMJRFbGrvUNinY15+qeeRLF708VL+tuENnbJMO6xHLWxU1rksOnu4xDzxfua9b3IxIaxLyTTFDuVi6bbu3sBslhIt2frdigo0xBL14KUJQ/pYiMj+2pfNYhtVxzamrnvgPSLNAEn36JykK2d347chT87HlZ7CAGNBS7lJHAzRP1v7Hkc+kKttkkWCpOGk06R6FUCxxVKXmQketMEl/scsMyJ3JtBe/EcjEZdDe5WcqZYUu5ARrfEiAeyutVRZnu17c3nKwkmWl7UqFAwp16cS8IPNL4i5FGCytgKl/kyaoxaE/P1lrGOkHcCTsSR0bAbARhndfdQ==")
26
+ key = subject.client.a.key
27
+
28
+ verification_result = key.verify_pss(
29
+ 'SHA256',
30
+ Base64.decode64(subject.signature_value),
31
+ OpenSSL::Digest::SHA256.new.digest(document),
32
+ salt_length: :digest,
33
+ mgf1_hash: 'SHA256',
34
+ )
35
+
36
+ expect(verification_result).to eq(true)
26
37
  end
27
38
  end
28
39
 
@@ -35,4 +46,4 @@ RSpec.describe Epics::GenericUploadRequest do
35
46
  end
36
47
 
37
48
  end
38
- end
49
+ end
data/spec/key_spec.rb CHANGED
@@ -11,22 +11,22 @@ RSpec.describe Epics::Key do
11
11
 
12
12
 
13
13
  describe '#sign' do
14
- # echo QwpW2a/Cu43TmibTIABrLuyZsiWY9oL8fARob0YoytU= | base64 -d | openssl dgst -sha256 -sign spec/fixtures/e002.pem -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 | base64 -w0
15
- let(:openssl) { "bZyyz4vPqRTyU7hfJ1cv6FgihhQOi8NTbk8nSuPEoXeuODJOQkCvxRDw1QoUGa181EbaPACYwJbQ9uwgwgb/b3k+bQ4KdJzCjbCrh7rKmQvLmnLgfQWIxp5hZdw7ebaR36rlpoHQ8yzlm0hhVLCDu2+HMIu5SA4kEd4ci9ZfVRm+aDVOwQZNLXNyKWAW/ZYkbsH+TzX4euIh831JBxGq967U5DVz6Aa8qqJPUafYiSE4H8x36Nw3qW0ib2DDcvGFTqtA6MeJyI1Quzko5+kSdnZkpIeZr/SXB1WnocYWR1oYoVG4+P+cMyCNiYSV4/NVEL4jmUbfdCSmUYo5cfPlJg==" }
16
-
17
- # r = subject.recover(sig)
18
- # masked_db = r[0..222]
19
- # hm = r[223..-2]
20
- # db_mask = MGF1.new.generate(hm, masked_db.size)
21
- # db = MGF1.new.xor(masked_db, db_mask)
22
- # salt = db[-32..-1]
23
- # Base64.encode64(salt)
24
- let(:salt) { "HkCke9oBSGTo2J20Xq8LZ/ouRHfB/ySlXf4+Cr45RV0=" }
25
-
26
14
  let(:dsi) { OpenSSL::Digest::SHA256.new.digest("ruby is great") }
27
15
 
28
- it 'will be compliant with openssl' do
29
- expect( subject.sign( dsi, Base64.decode64(salt)) ).to eq(openssl)
16
+ it 'will generated a digest that can be verified with openssl key.verify_pss' do
17
+ signed_digest = subject.sign(dsi)
18
+
19
+ key = subject.key
20
+
21
+ verification_result = key.verify_pss(
22
+ 'SHA256',
23
+ Base64.decode64(signed_digest),
24
+ dsi,
25
+ salt_length: :digest,
26
+ mgf1_hash: 'SHA256',
27
+ )
28
+
29
+ expect(verification_result).to eq(true)
30
30
  end
31
31
 
32
32
  end
@@ -23,17 +23,13 @@ RSpec.describe Epics::ParseEbics do
23
23
  expect(subject.post('/ok').body).to be_kind_of(Epics::Response)
24
24
  end
25
25
 
26
- it 'will handle a timeout with raising an Epics::Error::TechnicalError' do
27
- expect { subject.post('/timeout') }.to raise_error(Epics::Error::UnknownError, 'timeout')
28
- end
29
-
30
26
  context 'failures' do
31
- it 'will handle a timeout with raising an Epics::Error::TechnicalError' do
32
- expect { subject.post('/timeout') }.to raise_error(Epics::Error::UnknownError, 'timeout')
27
+ it 'will raise a timeout correctly' do
28
+ expect { subject.post('/timeout') }.to raise_error(Faraday::TimeoutError, 'timeout')
33
29
  end
34
30
 
35
- it 'will handle a no connection error with raising an Epics::Error::TechnicalError' do
36
- expect { subject.post('/no_connection') }.to raise_error(Epics::Error::UnknownError, 'peer has finished all lan parties and gone home')
31
+ it 'will properly raise non-epics errors' do
32
+ expect { subject.post('/no_connection') }.to raise_error(Faraday::ConnectionFailed, 'peer has finished all lan parties and gone home')
37
33
  end
38
34
  end
39
35
  end
@@ -1,8 +1,27 @@
1
1
  RSpec.describe Epics::CDZ do
2
2
  let(:client) { Epics::Client.new( File.open(File.join( File.dirname(__FILE__), '..', 'fixtures', 'SIZBN001.key')), 'secret' , 'https://194.180.18.30/ebicsweb/ebicsweb', 'SIZBN001', 'EBIX', 'EBICS') }
3
- subject { described_class.new(client, "2014-09-01", "2014-09-30") }
4
3
 
5
- describe '#to_xml' do
6
- specify { expect(subject.to_xml).to be_a_valid_ebics_doc }
4
+ context 'with date range' do
5
+ subject { described_class.new(client, "2014-09-01", "2014-09-30") }
6
+
7
+ describe '#to_xml' do
8
+ specify { expect(subject.to_xml).to be_a_valid_ebics_doc }
9
+
10
+ it 'does includes a date range as standard order parameter' do
11
+ expect(subject.to_xml).to include('<StandardOrderParams><DateRange><Start>2014-09-01</Start><End>2014-09-30</End></DateRange></StandardOrderParams>')
12
+ end
13
+ end
14
+ end
15
+
16
+ context 'without date range' do
17
+ subject { described_class.new(client) }
18
+
19
+ describe '#to_xml' do
20
+ specify { expect(subject.to_xml).to be_a_valid_ebics_doc }
21
+
22
+ it 'does not include a standard order parameter' do
23
+ expect(subject.to_xml).to include('<StandardOrderParams/>')
24
+ end
25
+ end
7
26
  end
8
27
  end
@@ -0,0 +1,27 @@
1
+ RSpec.describe Epics::CRZ do
2
+ let(:client) { Epics::Client.new( File.open(File.join( File.dirname(__FILE__), '..', 'fixtures', 'SIZBN001.key')), 'secret' , 'https://194.180.18.30/ebicsweb/ebicsweb', 'SIZBN001', 'EBIX', 'EBICS') }
3
+
4
+ context 'with date range' do
5
+ subject { described_class.new(client, "2014-09-01", "2014-09-30") }
6
+
7
+ describe '#to_xml' do
8
+ specify { expect(subject.to_xml).to be_a_valid_ebics_doc }
9
+
10
+ it 'does includes a date range as standard order parameter' do
11
+ expect(subject.to_xml).to include('<StandardOrderParams><DateRange><Start>2014-09-01</Start><End>2014-09-30</End></DateRange></StandardOrderParams>')
12
+ end
13
+ end
14
+ end
15
+
16
+ context 'without date range' do
17
+ subject { described_class.new(client) }
18
+
19
+ describe '#to_xml' do
20
+ specify { expect(subject.to_xml).to be_a_valid_ebics_doc }
21
+
22
+ it 'does not include a standard order parameter' do
23
+ expect(subject.to_xml).to include('<StandardOrderParams/>')
24
+ end
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epics
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Brillert
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-03 00:00:00.000000000 Z
11
+ date: 2023-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.0
19
+ version: 1.10.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 1.0.0
26
+ version: 1.10.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.10.7
33
+ version: 1.13.9
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 1.10.7
40
+ version: 1.13.9
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubyzip
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 2.2.0
47
+ version: 2.3.2
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 2.2.0
54
+ version: 2.3.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 1.6.2
61
+ version: 1.17.3
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 1.6.2
68
+ version: 1.17.3
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: equivalent-xml
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -146,7 +146,7 @@ description: |2
146
146
  STA HAA HTD HPD PKT HAC HKD C52 C53 C54
147
147
 
148
148
  And the following upload orders:
149
- CD1 CDD CCT CDB CDS CCS CDZ
149
+ CD1 CDD CCT CDB CDS CCS CDZ CRZ
150
150
  email:
151
151
  - lars@railslove.com
152
152
  executables: []
@@ -177,6 +177,7 @@ files:
177
177
  - lib/epics/cds.rb
178
178
  - lib/epics/cdz.rb
179
179
  - lib/epics/client.rb
180
+ - lib/epics/crz.rb
180
181
  - lib/epics/error.rb
181
182
  - lib/epics/generic_request.rb
182
183
  - lib/epics/generic_upload_request.rb
@@ -189,7 +190,6 @@ files:
189
190
  - lib/epics/htd.rb
190
191
  - lib/epics/ini.rb
191
192
  - lib/epics/key.rb
192
- - lib/epics/mgf.rb
193
193
  - lib/epics/middleware/parse_ebics.rb
194
194
  - lib/epics/middleware/xmlsig.rb
195
195
  - lib/epics/ptk.rb
@@ -241,7 +241,6 @@ files:
241
241
  - spec/generic_upload_spec.rb
242
242
  - spec/hpb_spec.rb
243
243
  - spec/key_spec.rb
244
- - spec/mgf_spec.rb
245
244
  - spec/middleware/parse_ebics_spec.rb
246
245
  - spec/orders/azv_spec.rb
247
246
  - spec/orders/b2b_spec.rb
@@ -254,6 +253,7 @@ files:
254
253
  - spec/orders/cdb_spec.rb
255
254
  - spec/orders/cdd_spec.rb
256
255
  - spec/orders/cdz_spec.rb
256
+ - spec/orders/crz_spec.rb
257
257
  - spec/orders/haa_spec.rb
258
258
  - spec/orders/hac_spec.rb
259
259
  - spec/orders/hia_spec.rb
@@ -298,15 +298,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
298
298
  requirements:
299
299
  - - ">="
300
300
  - !ruby/object:Gem::Version
301
- version: '2.4'
301
+ version: '2.6'
302
302
  required_rubygems_version: !ruby/object:Gem::Requirement
303
303
  requirements:
304
304
  - - ">="
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
307
  requirements: []
308
- rubygems_version: 3.0.2
309
- signing_key:
308
+ rubygems_version: 3.4.13
309
+ signing_key:
310
310
  specification_version: 4
311
311
  summary: a ruby implementation of the EBICS protocol
312
312
  test_files:
@@ -350,7 +350,6 @@ test_files:
350
350
  - spec/generic_upload_spec.rb
351
351
  - spec/hpb_spec.rb
352
352
  - spec/key_spec.rb
353
- - spec/mgf_spec.rb
354
353
  - spec/middleware/parse_ebics_spec.rb
355
354
  - spec/orders/azv_spec.rb
356
355
  - spec/orders/b2b_spec.rb
@@ -363,6 +362,7 @@ test_files:
363
362
  - spec/orders/cdb_spec.rb
364
363
  - spec/orders/cdd_spec.rb
365
364
  - spec/orders/cdz_spec.rb
365
+ - spec/orders/crz_spec.rb
366
366
  - spec/orders/haa_spec.rb
367
367
  - spec/orders/hac_spec.rb
368
368
  - spec/orders/hia_spec.rb
data/lib/epics/mgf.rb DELETED
@@ -1,41 +0,0 @@
1
- class Epics::MGF1
2
- def initialize(digest = OpenSSL::Digest::SHA256)
3
- @digest = digest.new
4
- @hlen = 32
5
- end
6
-
7
- def generate(seed, masklen)
8
- if masklen > (2 << 31) * @hlen
9
- raise ArgumentError, "mask too long"
10
- end
11
- t = ""
12
- divceil(masklen, @hlen).times do |counter|
13
- t += @digest.digest(seed + i2osp(counter, 4))
14
- end
15
- t[0, masklen]
16
- end
17
-
18
- def i2osp(x, len)
19
- if x >= 256 ** len
20
- raise ArgumentError, "integer too large"
21
- end
22
- [x].pack("N").gsub(/^\x00+/, '').rjust(len, "\x00")
23
- end
24
-
25
- def divceil(a, b)
26
- (a + b - 1) / b
27
- end
28
-
29
- def xor(a, b)
30
- if a.size != b.size
31
- raise ArgumentError, "different length for a and b"
32
- end
33
- a = a.unpack('C*')
34
- b = b.unpack('C*')
35
- a.size.times do |idx|
36
- a[idx] ^= b[idx]
37
- end
38
- a.pack("C*")
39
- end
40
-
41
- end
data/spec/mgf_spec.rb DELETED
@@ -1,36 +0,0 @@
1
- RSpec.describe Epics::MGF1 do
2
-
3
- describe '#generate' do
4
- it { expect(subject.generate('foo', 0)).to eq('')}
5
- it { expect(subject.generate('bar', 1)).to eq('8')}
6
- it { expect(subject.generate('noIdea', 2).bytes.to_a).to eq([86, 174])}
7
- it { expect(subject.generate('What', 4).bytes.to_a).to eq([238, 183, 195, 188])}
8
- it { expect(subject.generate('ImDoing', 8).bytes.to_a).to eq([134, 205, 115, 236, 187, 67, 223, 2])}
9
- it { expect { subject.generate('seed', 137438953473) }.to raise_error(ArgumentError, 'mask too long') }
10
- end
11
-
12
- describe '#i2osp' do
13
- it { expect(subject.i2osp(1, 1).bytes.to_a).to eq([1])}
14
- it { expect(subject.i2osp(1, 2).bytes.to_a).to eq([0, 1])}
15
- it { expect(subject.i2osp(1, 3).bytes.to_a).to eq([0, 0, 1])}
16
- it { expect(subject.i2osp(2, 1).bytes.to_a).to eq([2])}
17
- it { expect(subject.i2osp(4, 4).bytes.to_a).to eq([0, 0, 0, 4])}
18
- it { expect { subject.i2osp(256, 1) }.to raise_error(ArgumentError, 'integer too large') }
19
- end
20
-
21
- describe '#divceil' do
22
- it { expect(subject.divceil(1, 1)).to eq(1) }
23
- it { expect(subject.divceil(8, 2)).to eq(4) }
24
- it { expect(subject.divceil(32, 4)).to eq(8) }
25
- it { expect(subject.divceil(140, 21)).to eq(7) }
26
- it { expect(subject.divceil(987654321, 123456789)).to eq(9) }
27
- end
28
-
29
- describe '#xor' do
30
- it { expect(subject.xor('a', 'a').bytes.to_a).to eq([0]) }
31
- it { expect(subject.xor('a', 'b').bytes.to_a).to eq([3]) }
32
- it { expect(subject.xor('foo', 'bar').bytes.to_a).to eq([4, 14, 29]) }
33
- it { expect(subject.xor('encyclopedia', 'aidepolcycne').bytes.to_a).to eq([4, 7, 7, 28, 19, 3, 3, 19, 28, 7, 7, 4]) }
34
- it { expect { subject.xor('to raise', 'or not') }.to raise_error(ArgumentError, 'different length for a and b') }
35
- end
36
- end