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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81118d7e11ae925cc6430b6c8bd2ffd2afa948ee5c867c433f39c382522221b8
4
- data.tar.gz: 97ddaeb532907a37de4fcede16e0365eca040ca0400b3f3062b6f951e276c1b2
3
+ metadata.gz: 8764b1c890efb8ca4d619b84264ba4fcd0a10cdbd6d1fd505da2b733662d329c
4
+ data.tar.gz: a44447ecf5aec8045ade36f08702f8a134f98d5eff010843ba730902dfd0552e
5
5
  SHA512:
6
- metadata.gz: 11bd6d234f2aa23f685fc8628fc95b66aef1d668e888f83a12adfbc92882ed0e3a1f75943af66dfdc9014b867ea503afd423f7bb70cef47194f1a1c928e6fc78
7
- data.tar.gz: 783515919ad0436aa0e851999b86a288b8e73b1a240465f21e39606a422bb903eb61356b2641188c9558d88ad8517c2493f0013e882df22939b073f0e68bbcf5
6
+ metadata.gz: 8a30ada191b9256e197c851ff8c09dd9cfc89c3b72ac28c0c726da288dd925868c944f7f461cd40af55a28499ae7581718e2ef4a471dd36531e312b776c7fca1
7
+ data.tar.gz: 94d709de117a166321a587cf5db08b2fea8657547fc4a3dd1cf2844c68db4d9fa63d72ed3a2d56f43639c31400831ab611ac6081d545835af2146bfd09f60248
data/.gitignore CHANGED
@@ -16,3 +16,6 @@ mkmf.log
16
16
  .ruby*
17
17
  *.gem
18
18
  *.env
19
+ /.idea
20
+ /bin
21
+ .rakeTasks
@@ -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", "date"]
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
- digest = signature_algorithm == "rsa-sha256" ? OpenSSL::Digest::SHA256.new : OpenSSL::Digest::SHA512.new
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.utc.iso8601
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 = header_value(header_to_sign)
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 "date"
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
@@ -1,3 +1,3 @@
1
1
  module Ibanity
2
- VERSION = "1.4"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -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
@@ -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: '1.4'
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-09-24 00:00:00.000000000 Z
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