ibanity 1.4 → 1.5.0
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +9 -0
- data/lib/ibanity/http_signature.rb +23 -18
- data/lib/ibanity/version.rb +1 -1
- data/spec/lib/ibanity/http_signature_spec.rb +39 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/crypto_helper.rb +21 -0
- data/spec/support/fixtures/signature/test-certificate.pem +21 -0
- data/spec/support/fixtures/signature/test-private_key.pem +28 -0
- data/spec/support/fixtures/signature/test-public_key.pem +9 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8764b1c890efb8ca4d619b84264ba4fcd0a10cdbd6d1fd505da2b733662d329c
|
4
|
+
data.tar.gz: a44447ecf5aec8045ade36f08702f8a134f98d5eff010843ba730902dfd0552e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a30ada191b9256e197c851ff8c09dd9cfc89c3b72ac28c0c726da288dd925868c944f7f461cd40af55a28499ae7581718e2ef4a471dd36531e312b776c7fca1
|
7
|
+
data.tar.gz: 94d709de117a166321a587cf5db08b2fea8657547fc4a3dd1cf2844c68db4d9fa63d72ed3a2d56f43639c31400831ab611ac6081d545835af2146bfd09f60248
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.5
|
4
|
+
|
5
|
+
* Proper release of previous enhancements
|
6
|
+
|
7
|
+
## 1.4
|
8
|
+
|
9
|
+
*Don't use this version as it was not properly released !*
|
10
|
+
|
3
11
|
## 1.3
|
4
12
|
|
5
13
|
### Enhancements
|
@@ -10,6 +18,7 @@
|
|
10
18
|
|
11
19
|
### Enhancements
|
12
20
|
|
21
|
+
* Default signature algorithm is now ["hs2019"](https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2)
|
13
22
|
* Add support for periodic and bulk payments
|
14
23
|
* Add snake-case transformation for deeply nested data structures
|
15
24
|
|
@@ -2,6 +2,9 @@ require "base64"
|
|
2
2
|
|
3
3
|
module Ibanity
|
4
4
|
class HttpSignature
|
5
|
+
PSS_DIGEST_ALGORITHM = "SHA256"
|
6
|
+
SIGNATURE_ALGORITHM = "hs2019"
|
7
|
+
|
5
8
|
def initialize(certificate:, certificate_id:, key:, method:, uri:, query_params:, headers:, payload:)
|
6
9
|
@certificate = certificate
|
7
10
|
@certificate_id = certificate_id
|
@@ -13,6 +16,21 @@ module Ibanity
|
|
13
16
|
@query_params = query_params
|
14
17
|
end
|
15
18
|
|
19
|
+
def signature_headers
|
20
|
+
{
|
21
|
+
"Digest" => payload_digest,
|
22
|
+
"Signature" => [
|
23
|
+
%(keyId="#{@certificate_id}"),
|
24
|
+
%(created="#{date}"),
|
25
|
+
%(algorithm="#{SIGNATURE_ALGORITHM}"),
|
26
|
+
%(headers="#{headers_to_sign.join(" ")}"),
|
27
|
+
%(signature="#{base64_signature}"),
|
28
|
+
].join(",")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
16
34
|
def payload_digest
|
17
35
|
digest = OpenSSL::Digest::SHA512.new
|
18
36
|
string_payload = @payload.nil? ? "" : @payload
|
@@ -21,12 +39,8 @@ module Ibanity
|
|
21
39
|
"SHA-512=#{base64}"
|
22
40
|
end
|
23
41
|
|
24
|
-
def signature_algorithm
|
25
|
-
@certificate.signature_algorithm.match("sha256") ? "rsa-sha256" : "rsa-sha512"
|
26
|
-
end
|
27
|
-
|
28
42
|
def headers_to_sign
|
29
|
-
result = ["(request-target)", "host", "digest", "
|
43
|
+
result = ["(request-target)", "host", "digest", "(created)"]
|
30
44
|
result << "authorization" unless @headers["Authorization"].nil?
|
31
45
|
@headers.keys.each do |header|
|
32
46
|
result << header.to_s.downcase if header.to_s.match(/ibanity/i)
|
@@ -40,8 +54,7 @@ module Ibanity
|
|
40
54
|
end
|
41
55
|
|
42
56
|
def base64_signature
|
43
|
-
|
44
|
-
signature = @key.sign(digest, signing_string)
|
57
|
+
signature = @key.sign_pss(PSS_DIGEST_ALGORITHM, signing_string, salt_length: :digest, mgf1_hash: PSS_DIGEST_ALGORITHM)
|
45
58
|
Base64.urlsafe_encode64(signature)
|
46
59
|
end
|
47
60
|
|
@@ -50,13 +63,13 @@ module Ibanity
|
|
50
63
|
end
|
51
64
|
|
52
65
|
def date
|
53
|
-
@date ||= Time.now.
|
66
|
+
@date ||= Time.now.to_i
|
54
67
|
end
|
55
68
|
|
56
69
|
def signing_string
|
57
70
|
result = []
|
58
71
|
headers_to_sign.each do |header_to_sign|
|
59
|
-
value
|
72
|
+
value = header_value(header_to_sign)
|
60
73
|
result << "#{header_to_sign}: #{value}"
|
61
74
|
end
|
62
75
|
result.join("\n")
|
@@ -70,20 +83,12 @@ module Ibanity
|
|
70
83
|
host
|
71
84
|
when "digest"
|
72
85
|
payload_digest
|
73
|
-
when "
|
86
|
+
when "(created)"
|
74
87
|
date
|
75
88
|
else
|
76
89
|
camelized_header = header.split("-").collect(&:capitalize).join("-")
|
77
90
|
@headers[camelized_header]
|
78
91
|
end
|
79
92
|
end
|
80
|
-
|
81
|
-
def signature_headers
|
82
|
-
{
|
83
|
-
"Date" => date,
|
84
|
-
"Digest" => payload_digest,
|
85
|
-
"Signature" => "keyId=\"#{@certificate_id}\" algorithm=\"#{signature_algorithm}\" headers=\"#{headers_to_sign.join(" ")}\" signature=\"#{base64_signature}\""
|
86
|
-
}
|
87
|
-
end
|
88
93
|
end
|
89
94
|
end
|
data/lib/ibanity/version.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "ibanity/http_signature"
|
2
|
+
|
3
|
+
RSpec.describe Ibanity::HttpSignature do
|
4
|
+
|
5
|
+
describe ".signature_headers" do
|
6
|
+
let(:signature) do
|
7
|
+
Ibanity::HttpSignature.new(
|
8
|
+
certificate: CryptoHelper.load_certificate("test"),
|
9
|
+
certificate_id: "ec0c29ef-3b39-4b6f-93ff-866bed032399",
|
10
|
+
key: CryptoHelper.load_private_key("test"),
|
11
|
+
method: "post",
|
12
|
+
uri: "https://api.ibanity.com/xs2a/customer-access-tokens",
|
13
|
+
headers: {"ibanity-idempotency-key" => "cf17b515-5f6f-4213-a8fe-e4cd40653d00"},
|
14
|
+
payload: "{\"foo\": \"bar\"}",
|
15
|
+
query_params: {}
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:parts_regex) do
|
20
|
+
/keyId="(?<keyId>.*)",\s?created="(?<created>.*)?",?\s?algorithm="(?<algorithm>.*)",\s?headers="(?<headers>.*)",?\s?signature="(?<signature>.*)"/
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:signature_parts) do
|
24
|
+
signature.signature_headers["Signature"].match(parts_regex).named_captures
|
25
|
+
end
|
26
|
+
|
27
|
+
["Digest", "Signature"].each do |header|
|
28
|
+
it "contains the '#{header}' header" do
|
29
|
+
expect(signature.signature_headers).to include(header)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
["keyId", "algorithm", "headers", "signature", "created"].each do |part|
|
34
|
+
it "has a signature containing the part '#{part}'" do
|
35
|
+
expect(signature_parts).to include(part)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,6 +13,8 @@
|
|
13
13
|
# it.
|
14
14
|
#
|
15
15
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
17
|
+
|
16
18
|
RSpec.configure do |config|
|
17
19
|
# rspec-expectations config goes here. You can use an alternate
|
18
20
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
module CryptoHelper
|
5
|
+
FIXTURE_DIRECTORY = Pathname.getwd().join("spec", "support", "fixtures", "signature")
|
6
|
+
|
7
|
+
def self.load_certificate(name)
|
8
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-certificate.pem"))
|
9
|
+
::OpenSSL::X509::Certificate.new(pem)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load_public_key(name)
|
13
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-public_key.pem"))
|
14
|
+
::OpenSSL::PKey::RSA.new(pem)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load_private_key(name)
|
18
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-private_key.pem"))
|
19
|
+
::OpenSSL::PKey::RSA.new(pem)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDdjCCAl4CCQCxpvuEfl5slTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJC
|
3
|
+
RTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJydXNzZWxzMRAwDgYDVQQK
|
4
|
+
DAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEwHwYJKoZIhvcNAQkBFhJj
|
5
|
+
b21wYW55QGliYW5pdHkuYmUwHhcNMTkwNjI3MTE1NjAyWhcNMjkwNjI0MTE1NjAy
|
6
|
+
WjB9MQswCQYDVQQGEwJCRTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJy
|
7
|
+
dXNzZWxzMRAwDgYDVQQKDAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEw
|
8
|
+
HwYJKoZIhvcNAQkBFhJjb21wYW55QGliYW5pdHkuYmUwggEiMA0GCSqGSIb3DQEB
|
9
|
+
AQUAA4IBDwAwggEKAoIBAQDcaDiqP4EkTYXzDqCLZGiEEQnx0iazY/f3IMZNnYVf
|
10
|
+
BDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVRch0+n4KV/4Toe0Oq9VP6xKqOXYtZ
|
11
|
+
ZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowzAyr3EzivW1v19uhWdqguhPEPopr/
|
12
|
+
2sue3vloZrigamOov29iFkiFLtSqAyEZI7x48w/3X2nkZ1UivYxBRrLnulVMUJDZ
|
13
|
+
zvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJnW1F6riwd6hud9xokDZSvredC/XhM
|
14
|
+
byl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESRMtOVmyrvAgMBAAEwDQYJKoZIhvcN
|
15
|
+
AQELBQADggEBAKMwFzfoXXxasB/6ZlnAMy7aWmb8xp55E6aZZoZXhoHHA03z+Jj2
|
16
|
+
cVy/PMgNDOk5MLf4ddpj7iVf42iLAGpgqo0oQjE11UCwYBBDIQ3vjR+MctoN2B+L
|
17
|
+
Qpx7OGDoqSnVucVTS9KmWbJM3PAfbeexSRfqRJ3Jn2DvQDx1k32L//KtP1FRMtku
|
18
|
+
Dqoizz7NSLjrmIkXLAuepKdfDSVKnLHD1fB6gKvDNPBNivlFqceZe0XoXdlGwZcC
|
19
|
+
7aTdzYzZNCbg1w1bTxv7dom3ubAM1DPKUEA3afW25691ZsBf9W52hb/tOlVOw78j
|
20
|
+
+gUJtiEKTkcfmrfCgPDrcDjsm+iaQclAhK4=
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,28 @@
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcaDiqP4EkTYXz
|
3
|
+
DqCLZGiEEQnx0iazY/f3IMZNnYVfBDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVR
|
4
|
+
ch0+n4KV/4Toe0Oq9VP6xKqOXYtZZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowz
|
5
|
+
Ayr3EzivW1v19uhWdqguhPEPopr/2sue3vloZrigamOov29iFkiFLtSqAyEZI7x4
|
6
|
+
8w/3X2nkZ1UivYxBRrLnulVMUJDZzvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJn
|
7
|
+
W1F6riwd6hud9xokDZSvredC/XhMbyl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESR
|
8
|
+
MtOVmyrvAgMBAAECggEAOS3olXJIJIzgFUBUMhVob+qjs9KbK6rhp4EfMP+OnCnR
|
9
|
+
H+26K8rpcAPw/H9hAujrN0rRtHO1dktsmOaL47UqAZP6fP2NfoqKsOHYhXqLLjOe
|
10
|
+
ltu51ohmHioa9AGfS+IYoJYJzzy88aq6mHlX6iVYbVW8M8FMYTIDS549k5rRr1Iu
|
11
|
+
SqGQSoIo8vGKhMyp6UbIvBhx1CRs2xeoknL0H5uEHnqB6oJTqfnbkQ1sVX4vZuHl
|
12
|
+
+WOIKQPlFKy74Lcs9ap1Dr9llD/PoVB3b2KbLRJTda352ezMLspb6CVUOFw7S0eB
|
13
|
+
vHVFlR+V922GaMvEmxZ58ZY+DwqBGPeuiG7/kYFNAQKBgQD8e64NptLgw7Wk8mvn
|
14
|
+
tGTB28ycUkc9wT/NdiePqlUT56ynD4oCBGcbEu6hH5ntYR93Kpi7fINTKglkVGdK
|
15
|
+
MkU/QOV0bs7wItqmQvkMeUbypnWXeQPICs3z/synytwbDYl7/FslTPxdjAgodQZJ
|
16
|
+
FY3Lui9bqe05VjvefEtEb9/yrwKBgQDfeimt/bVmA6Ldg4k+K72aAwP+g8l8Dyg1
|
17
|
+
Fba2vSFoS/MyvhCqTgP6Uh2fl8qXOqGJEv0koD3yRADa5/FlHSCeLhsyYqsLd/Zm
|
18
|
+
0Ogts7dhVm2v9jvVdmnWUQnGp/mPAGX6gB6Q1WHHEAdUNp6qAG7GatrJcttU0+7U
|
19
|
+
9cYKyc9bwQKBgC7oi53dsLAxrD3JDGMwEMgzngAtCS9gCAqUOSVn8AaStHEVYf6d
|
20
|
+
8soE6nDk/iQsNzxcnaO3rm51EOmjBM20KUlnNTo8nBXhY94f80VuAtByPMa3pQw1
|
21
|
+
da4vWLaT6fDcwv5WFFkJxJlcuudJVrGdX4rKPKI7H+fXLahYT2OXpXPhAoGBAIO9
|
22
|
+
Vli1WXw75ITFB+DYlDr4UCB3vA0gOkmg9Ucgk1MSgtmE5fofZ4TnZ4MvTkR8UcGm
|
23
|
+
qggvVpU8tWxWkx1SYGofL/Ux6Tcnjt/pgxV9/jqpYpv6gidCWP34Y9TyLNG6IGPd
|
24
|
+
pycmQy/AKTHhyQLaonLhhvx+cwG8texgvlCZy12BAoGAYsahYudgvuUi/IKjQvkH
|
25
|
+
0F/kwBnd0mRHttsEMIVjrG1Y82EUh5Ja05IGpOSSMeBVhIlJ/DnwFOoSmIVzGfsA
|
26
|
+
4GHtXmHd1xByxjW4nbr4NH7u8ElULkOPjcxSLgXhDb5KtG1XwCPEMUqvApcM6cfv
|
27
|
+
CQn8vQRR2J42gXEcTmt0zVQ=
|
28
|
+
-----END PRIVATE KEY-----
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Gg4qj+BJE2F8w6gi2Ro
|
3
|
+
hBEJ8dIms2P39yDGTZ2FXwQ0i5d5tsdft3IeD3vxN+QGoNcHm57w4f1VUXIdPp+C
|
4
|
+
lf+E6HtDqvVT+sSqjl2LWWQFVl87NU43U/3ZPq0V2vsJ8qtipJTydGqMMwMq9xM4
|
5
|
+
r1tb9fboVnaoLoTxD6Ka/9rLnt75aGa4oGpjqL9vYhZIhS7UqgMhGSO8ePMP919p
|
6
|
+
5GdVIr2MQUay57pVTFCQ2c78nbt7LZbupkpWkNzKXYM8s+FeNTSJszXiZ1tReq4s
|
7
|
+
HeobnfcaJA2Ur63nQv14TG8pdC3aygAc8h5zhUgZSJCBw3kFD2vWCgREkTLTlZsq
|
8
|
+
7wIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ibanity
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -101,8 +101,13 @@ files:
|
|
101
101
|
- lib/ibanity/http_signature.rb
|
102
102
|
- lib/ibanity/util.rb
|
103
103
|
- lib/ibanity/version.rb
|
104
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
104
105
|
- spec/lib/ibanity/util_spec.rb
|
105
106
|
- spec/spec_helper.rb
|
107
|
+
- spec/support/crypto_helper.rb
|
108
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
109
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
110
|
+
- spec/support/fixtures/signature/test-public_key.pem
|
106
111
|
homepage: https://documentation.ibanity.com/api/ruby
|
107
112
|
licenses:
|
108
113
|
- MIT
|
@@ -127,5 +132,10 @@ signing_key:
|
|
127
132
|
specification_version: 4
|
128
133
|
summary: Ibanity Ruby Client
|
129
134
|
test_files:
|
135
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
130
136
|
- spec/lib/ibanity/util_spec.rb
|
131
137
|
- spec/spec_helper.rb
|
138
|
+
- spec/support/crypto_helper.rb
|
139
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
140
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
141
|
+
- spec/support/fixtures/signature/test-public_key.pem
|