epics 1.8.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.semaphore/semaphore.yml +6 -15
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +43 -2
- data/README.md +2 -1
- data/epics.gemspec +6 -6
- data/lib/epics/cdz.rb +11 -7
- data/lib/epics/client.rb +16 -8
- data/lib/epics/crz.rb +46 -0
- data/lib/epics/error.rb +1 -1
- data/lib/epics/key.rb +9 -41
- data/lib/epics/version.rb +1 -1
- data/lib/epics.rb +1 -1
- data/spec/generic_upload_spec.rb +14 -3
- data/spec/key_spec.rb +14 -14
- data/spec/orders/cdz_spec.rb +22 -3
- data/spec/orders/crz_spec.rb +27 -0
- metadata +20 -20
- data/lib/epics/mgf.rb +0 -41
- data/spec/mgf_spec.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe32a608bfa8bc6ba0e5efdd4a7f9970012fcbc77301fbdc17b69e463bae5f99
|
4
|
+
data.tar.gz: 5f4d10b3381e803e1db5799a3383fd52bd766c30c087149fb2fdbf6123de2f5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b5ff6b89a856fe9b10df88fa9a3b289fa2ebf5d44a936d60ef7d6c5c5d5024d66fce09dbbbe7ff51c364833bb5d9ca5ffcb4ff9673bde6d2a18611569f09867
|
7
|
+
data.tar.gz: 8a636c50118dc65fe444a8672e9ef691a585749adfa545fc731fe19977d41b7263fe4739258116eaba219d349dcf9e2429c5fd794cc7cab18ffd814a86bacdb0
|
data/.semaphore/semaphore.yml
CHANGED
@@ -16,36 +16,27 @@ blocks:
|
|
16
16
|
- name: Spec versions
|
17
17
|
task:
|
18
18
|
jobs:
|
19
|
-
- name: "2.
|
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.
|
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.
|
27
|
+
- name: "2.7"
|
36
28
|
commands:
|
37
29
|
- checkout
|
38
|
-
- sem-version ruby 2.
|
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: "
|
35
|
+
- name: "3.0"
|
44
36
|
commands:
|
45
37
|
- checkout
|
46
|
-
- sem-version ruby
|
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,14 @@
|
|
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
|
+
|
1
12
|
### 1.8.1
|
2
13
|
- [BUGFIX] Remove masking of transport client errors
|
3
14
|
|
data/CONTRIBUTING.md
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
-
#
|
1
|
+
# Individual Contributor Non-Exclusive License Agreement
|
2
2
|
|
3
|
-
|
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-
|
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.
|
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',
|
44
|
-
spec.add_dependency 'nokogiri', '>= 1.
|
45
|
-
spec.add_dependency 'rubyzip',
|
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.
|
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
|
-
|
24
|
-
xml.
|
25
|
-
xml.
|
26
|
-
|
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
|
269
|
-
|
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
|
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",
|
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
|
33
|
-
Base64.encode64(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
data/lib/epics/version.rb
CHANGED
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"
|
data/spec/generic_upload_spec.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
29
|
-
|
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
|
data/spec/orders/cdz_spec.rb
CHANGED
@@ -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
|
-
|
6
|
-
|
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:
|
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:
|
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.
|
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.
|
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.
|
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.
|
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
|
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
|
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.
|
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.
|
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.
|
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.
|
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
|