http_signature 0.0.7 → 1.0.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
- SHA1:
3
- metadata.gz: 33793ff4276cb6c366f88d15abb0e38b69cdb468
4
- data.tar.gz: cde3efe53a20f5ef8a94c2ed21b9341300f4ed76
2
+ SHA256:
3
+ metadata.gz: 0d4b1e73dff1838a018f5e0d5bef1c6a6a14c2b8ef552dbbfd0481ac85cb03b7
4
+ data.tar.gz: 1a087ded86d8f84213984d9bd56fb55462f65feb9abc876514249f12fc5166ef
5
5
  SHA512:
6
- metadata.gz: 88cf8f428a7bafd0971b4e8d0650c8b9ee15c8f74794347afa7cdaed32da0462468f4a7f1471f1f4578886009801a822dcf990481d859dac5fa3e9b65e2e8630
7
- data.tar.gz: 516d8a279e8a340df3e2aae7e8b1bd313229dd8e8643c81bda7caea37e321d1e812e692afabe2b4535281c6c35970b2b62286ffdd07178fa5a57ca2c63d0c72f
6
+ metadata.gz: 7796499163d70782ea0fd809316c39a4d2a933cf01cc88f6daaa88d673607e9a138643d666fc5080063ea0bdb1068d32c48642fb487c59d6edcb7626fba7ad8e
7
+ data.tar.gz: 1603d71ad33fc087e456949de3e1534f3cf08c894a3fe10a3f456f6751409ddbbda247a53511d201866cf10f629e2c676fbe2eaa7cb0e0535dae81a2cad6e2a2
@@ -0,0 +1,32 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: '3.4'
19
+ bundler-cache: true
20
+
21
+ - name: Run tests with coverage
22
+ env:
23
+ COVERAGE: "true"
24
+ run: bundle exec rake test
25
+
26
+ - name: Upload coverage artifact
27
+ uses: actions/upload-artifact@v4
28
+ with:
29
+ name: coverage-html
30
+ path: coverage/
31
+ if-no-files-found: warn
32
+
@@ -0,0 +1,15 @@
1
+ name: Standard Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ permissions:
9
+ checks: write
10
+ contents: read
11
+ steps:
12
+ - name: Standard Ruby
13
+ uses: standardrb/standard-ruby-action@v1
14
+ with:
15
+ autofix: false
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
1
  *.gem
2
+ coverage/
3
+ node_modules
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4.0
1
+ 3.4.8
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
+
3
+ ruby "3.4.8"
2
4
 
3
- # Specify your gem's dependencies in rpc.gemspec
4
5
  gemspec
data/Gemfile.lock CHANGED
@@ -1,26 +1,159 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- http_signature (0.0.7)
4
+ http_signature (1.0.0)
5
+ base64
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
9
- faraday (0.15.0)
10
- multipart-post (>= 1.2, < 3)
11
- minitest (5.10.3)
12
- multipart-post (2.0.0)
13
- rake (12.2.1)
10
+ actionpack (8.1.1)
11
+ actionview (= 8.1.1)
12
+ activesupport (= 8.1.1)
13
+ nokogiri (>= 1.8.5)
14
+ rack (>= 2.2.4)
15
+ rack-session (>= 1.0.1)
16
+ rack-test (>= 0.6.3)
17
+ rails-dom-testing (~> 2.2)
18
+ rails-html-sanitizer (~> 1.6)
19
+ useragent (~> 0.16)
20
+ actionview (8.1.1)
21
+ activesupport (= 8.1.1)
22
+ builder (~> 3.1)
23
+ erubi (~> 1.11)
24
+ rails-dom-testing (~> 2.2)
25
+ rails-html-sanitizer (~> 1.6)
26
+ activesupport (8.1.1)
27
+ base64
28
+ bigdecimal
29
+ concurrent-ruby (~> 1.0, >= 1.3.1)
30
+ connection_pool (>= 2.2.5)
31
+ drb
32
+ i18n (>= 1.6, < 2)
33
+ json
34
+ logger (>= 1.4.2)
35
+ minitest (>= 5.1)
36
+ securerandom (>= 0.3)
37
+ tzinfo (~> 2.0, >= 2.0.5)
38
+ uri (>= 0.13.1)
39
+ ast (2.4.3)
40
+ base64 (0.3.0)
41
+ bigdecimal (4.0.1)
42
+ builder (3.3.0)
43
+ concurrent-ruby (1.3.6)
44
+ connection_pool (3.0.2)
45
+ crass (1.0.6)
46
+ docile (1.4.1)
47
+ drb (2.2.3)
48
+ erubi (1.13.1)
49
+ faraday (2.14.0)
50
+ faraday-net_http (>= 2.0, < 3.5)
51
+ json
52
+ logger
53
+ faraday-net_http (3.4.2)
54
+ net-http (~> 0.5)
55
+ i18n (1.14.8)
56
+ concurrent-ruby (~> 1.0)
57
+ json (2.18.0)
58
+ language_server-protocol (3.17.0.5)
59
+ lint_roller (1.1.0)
60
+ logger (1.7.0)
61
+ loofah (2.25.0)
62
+ crass (~> 1.0.2)
63
+ nokogiri (>= 1.12.0)
64
+ minitest (6.0.0)
65
+ prism (~> 1.5)
66
+ net-http (0.9.1)
67
+ uri (>= 0.11.1)
68
+ nokogiri (1.19.0-arm64-darwin)
69
+ racc (~> 1.4)
70
+ nokogiri (1.19.0-x86_64-linux-gnu)
71
+ racc (~> 1.4)
72
+ parallel (1.27.0)
73
+ parser (3.3.10.0)
74
+ ast (~> 2.4.1)
75
+ racc
76
+ prism (1.7.0)
77
+ racc (1.8.1)
78
+ rack (3.2.4)
79
+ rack-session (2.1.1)
80
+ base64 (>= 0.1.0)
81
+ rack (>= 3.0.0)
82
+ rack-test (2.2.0)
83
+ rack (>= 1.3)
84
+ rails-dom-testing (2.3.0)
85
+ activesupport (>= 5.0.0)
86
+ minitest
87
+ nokogiri (>= 1.6)
88
+ rails-html-sanitizer (1.6.2)
89
+ loofah (~> 2.21)
90
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
91
+ rainbow (3.1.1)
92
+ rake (13.3.1)
93
+ regexp_parser (2.11.3)
94
+ rubocop (1.81.7)
95
+ json (~> 2.3)
96
+ language_server-protocol (~> 3.17.0.2)
97
+ lint_roller (~> 1.1.0)
98
+ parallel (~> 1.10)
99
+ parser (>= 3.3.0.2)
100
+ rainbow (>= 2.2.2, < 4.0)
101
+ regexp_parser (>= 2.9.3, < 3.0)
102
+ rubocop-ast (>= 1.47.1, < 2.0)
103
+ ruby-progressbar (~> 1.7)
104
+ unicode-display_width (>= 2.4.0, < 4.0)
105
+ rubocop-ast (1.49.0)
106
+ parser (>= 3.3.7.2)
107
+ prism (~> 1.7)
108
+ rubocop-performance (1.26.1)
109
+ lint_roller (~> 1.1)
110
+ rubocop (>= 1.75.0, < 2.0)
111
+ rubocop-ast (>= 1.47.1, < 2.0)
112
+ ruby-progressbar (1.13.0)
113
+ securerandom (0.4.1)
114
+ simplecov (0.22.0)
115
+ docile (~> 1.1)
116
+ simplecov-html (~> 0.11)
117
+ simplecov_json_formatter (~> 0.1)
118
+ simplecov-html (0.13.2)
119
+ simplecov_json_formatter (0.1.4)
120
+ standard (1.52.0)
121
+ language_server-protocol (~> 3.17.0.2)
122
+ lint_roller (~> 1.0)
123
+ rubocop (~> 1.81.7)
124
+ standard-custom (~> 1.0.0)
125
+ standard-performance (~> 1.8)
126
+ standard-custom (1.0.2)
127
+ lint_roller (~> 1.0)
128
+ rubocop (~> 1.50)
129
+ standard-performance (1.9.0)
130
+ lint_roller (~> 1.1)
131
+ rubocop-performance (~> 1.26.0)
132
+ tzinfo (2.0.6)
133
+ concurrent-ruby (~> 1.0)
134
+ unicode-display_width (3.2.0)
135
+ unicode-emoji (~> 4.1)
136
+ unicode-emoji (4.2.0)
137
+ uri (1.1.1)
138
+ useragent (0.16.11)
14
139
 
15
140
  PLATFORMS
16
- ruby
141
+ arm64-darwin-25
142
+ x86_64-linux
17
143
 
18
144
  DEPENDENCIES
145
+ actionpack (>= 6.1)
19
146
  bundler
20
- faraday
147
+ faraday (>= 2.7)
21
148
  http_signature!
22
- minitest
149
+ minitest (>= 5.24)
150
+ rack
23
151
  rake
152
+ simplecov
153
+ standard
154
+
155
+ RUBY VERSION
156
+ ruby 3.4.8
24
157
 
25
158
  BUNDLED WITH
26
- 1.16.1
159
+ 4.0.2
data/README.md CHANGED
@@ -1,162 +1,156 @@
1
1
  # HTTP Signature
2
- [![CircleCI](https://circleci.com/gh/bolmaster2/http-signature.svg?style=svg)](https://circleci.com/gh/bolmaster2/http-signature)
3
2
 
4
- Create and validate HTTP request signature according to this draft: https://tools.ietf.org/html/draft-cavage-http-signatures-08
3
+ Create and validate HTTP Message Signatures per [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421) using the `Signature-Input` and `Signature` headers.
5
4
 
6
- Aims to only implement the creation and validation of the signature without any external dependencies.
7
- The idea is to implement adapters to popular http libraries to make it easy to use.
5
+ Aims to only implement the creation and validation of signatures without any external dependencies. Adapters are provided for common HTTP libraries.
8
6
 
9
- ## Installation
7
+ __NOTE__: RFC 9421 signs components via two headers:
8
+ ```
9
+ Signature-Input: sig1=("@method" "@authority" "@target-uri" "date");created=...
10
+ Signature: sig1=:BASE64_SIGNATURE_BYTES:
10
11
  ```
12
+
13
+ ## Installation
14
+
15
+ ```shell
11
16
  gem install http_signature
12
17
  ```
13
18
 
14
19
  ## Usage
15
20
 
16
- ```ruby
17
- require 'http_signature'
18
- ```
21
+ ### Create signature
22
+
23
+ `HTTPSignature.create` returns both `Signature-Input` and `Signature` headers that you can include in your request.
24
+
19
25
 
20
- ### Basic
21
- The most basic usage without any extra headers. The default algorithm is `hmac-sha256`. This create the `Signature` header value. Next step is to add the value to the header and 💥 you're done!
22
26
  ```ruby
23
- HTTPSignature.create(
24
- url: 'https://example.com/foo',
27
+ headers = { 'date' => 'Tue, 20 Apr 2021 02:07:55 GMT' }
28
+
29
+ sig_headers = HTTPSignature.create(
30
+ url: 'https://example.com/foo?pet=dog',
31
+ method: :get,
32
+ headers: headers,
25
33
  key_id: 'Test',
26
- key: 'secret 🙈'
34
+ key: 'secret',
35
+ covered_components: %w[@method @target-uri date],
27
36
  )
28
- # 'keyId="Test",algorithm="hmac-sha256",headers="(request-target)",signature="OQ/dHqRW9vFmrW/RCHg7O2Fqx+3uqxJw81p6k9Rcyo4="'
37
+
38
+ request['Signature-Input'] = sig_headers['Signature-Input']
39
+ request['Signature'] = sig_headers['Signature']
29
40
  ```
30
41
 
31
- ### With headers, query parameters and a body
32
- Uses both query parameters (in query string) and a `json` body as a `POST` request.
33
- Also shows how to set `rsa-sha256` as algorithm. The `digest` is as you see basically
34
- a `sha-256` digest of the request body.
42
+
43
+ ### Validate signature
44
+
45
+ Call `valid?` with the incoming request headers (including `Signature-Input` and `Signature`)
35
46
 
36
47
  ```ruby
37
- params = {
38
- param: 'value',
39
- pet: 'dog'
40
- }
41
-
42
- body = '{"hello": "world"}'
43
-
44
- headers = {
45
- 'date': 'Thu, 05 Jan 2014 21:31:40 GMT',
46
- 'content-type': 'application/json',
47
- 'digest': HTTPSignature.create_digest(body),
48
- 'content-length': body.length
49
- }
50
-
51
- HTTPSignature.create(
52
- url: 'https://example.com/foo',
53
- method: :post,
54
- query_string_params: params,
48
+ HTTPSignature.valid?(
49
+ url: "https://example.com/foo",
50
+ method: :get,
55
51
  headers: headers,
56
- key_id: 'Test',
57
- algorithm: 'rsa-sha256',
58
- key: File.read('key.pem'),
59
- body: body
52
+ key: "secret"
60
53
  )
61
54
  ```
62
55
 
63
- ### With digest header auto-added
64
- When digest header is omitted it's auto added as last header generated from the `body`:
56
+ ## Outgoing request examples
57
+
58
+ ### NET::HTTP
65
59
 
66
60
  ```ruby
67
- body = '{"foo": "bar"}'
61
+ require 'net/http'
62
+ require 'http_signature'
68
63
 
69
- HTTPSignature.create(
70
- url: 'https://example.com/foo',
71
- key_id: 'Test',
72
- key: 'secret 🙈',
73
- body: body
74
- )
75
- # 'keyId="Test",algorithm="hmac-sha256",headers="(request-target) digest",signature="3Jm5jnCSKX3fYLd58RqRdafZKeuSbUEPhn7grCGx4vg="'
76
- ```
64
+ uri = URI('http://example.com/hello')
77
65
 
78
- ### Validate asymmetric signature
79
- With an asymmetric algorithm you can't just recreate the same header and see if they
80
- check out, because you need the private key to do that and because the one validating
81
- the signature should only have access to the public key, you need to validate it with that.
66
+ Net::HTTP.start(uri.host, uri.port) do |http|
67
+ request = Net::HTTP::Get.new(uri)
82
68
 
83
- Imagine the incoming HTTP request looks like this:
84
- ```
85
- POST /foo HTTP/1.1
86
- Host: example.com
87
- Date: Thu, 05 Jan 2014 21:31:40 GMT
88
- Content-Type: application/json
89
- Content-Length: 18
90
- Digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
91
- Signature: keyId="Test-1",algorithm="rsa-sha256",headers="(request-target) host date content-type content-length digest",signature="YGPVM1tGHD7CHgTmroy9apLtVazdESzMl4vj1koYHNCMmTEDor4Om5TDZDFaJdny5dF3gq+PQQuPwyknNEvACmSjwVXzljPFxaY/JMZTqAdD0yHTP2Rx0Y/J4GwgKARWTZUmccfVYsXp86PhIlCymzleZzYCzj6shyg9NB7Ht+k="
92
-
93
- {"hello": "world"}
94
- ```
69
+ sig_headers = HTTPSignature.create(
70
+ url: request.uri,
71
+ method: request.method,
72
+ headers: request.each_header.map { |k, v| [k, v] }.to_h,
73
+ key: 'MYSECRETKEY',
74
+ key_id: 'KEY_1',
75
+ algorithm: 'hmac-sha256',
76
+ body: request.body ? request.body : ''
77
+ )
95
78
 
96
- Let's assume we have this request ☝️ in a `request` object for the sake of the example:
97
- ```ruby
98
- HTTPSignature.valid?(
99
- url: request.url,
100
- method: request.method,
101
- headers: request.headers,
102
- body: request.body,
103
- key: OpenSSL::PKey::RSA.new('public_key.pem'),
104
- algorithm: 'rsa-sha256'
105
- )
79
+ request['Signature-Input'] = sig_headers['Signature-Input']
80
+ request['Signature'] = sig_headers['Signature']
81
+
82
+ response = http.request(request) # Net::HTTPResponse
83
+ end
106
84
  ```
107
85
 
108
- ## Example usage with middleware
109
- ### Faraday middleware on outgoing requests
110
- Example of using it on an outgoing request.
86
+ ### Faraday
87
+
88
+ As a faraday middleware
89
+
111
90
  ```ruby
112
91
  require 'http_signature/faraday'
113
92
 
114
- HTTPSignature::Faraday.key = 'MySecureKey' # This should be long and random
115
- HTTPSignature::Faraday.key_id = 'key-1' # For the recipient to know which key to decrypt with
93
+ HTTPSignature::Faraday.key = 'secret'
94
+ HTTPSignature::Faraday.key_id = 'key-1'
116
95
 
117
-
118
- # Tell faraday to use the middleware. Read more about it here: https://github.com/lostisland/faraday#advanced-middleware-usage
119
96
  Faraday.new('http://example.com') do |faraday|
120
97
  faraday.use(HTTPSignature::Faraday)
121
98
  faraday.adapter(Faraday.default_adapter)
122
99
  end
123
100
 
124
- # Now this request will contain the `Signature` header
101
+ # Now this request will contain the `Signature-Input` and `Signature` headers
125
102
  response = conn.get('/')
126
103
 
127
104
  # Request looking like:
128
- # GET / HTTP/1.1
129
- # User-Agent: Faraday v0.15.0
130
- # Signature: keyId="key-1",algorithm="hmac-sha256",headers="(request-target) date",signature="EzFa4vb0z+VFF8VYt9qQlzF9MTf5Izptc02OJ7aajnU="
105
+ # Signature-Input: sig1=("@method" "@authority" "@target-uri" "date");created=...
106
+ # Signature: sig1=:BASE64_SIGNATURE:
131
107
  ```
132
108
 
133
- ### Rack middleware for incoming requests
134
- I've written a quite sloppy but totally usable rack middleware that validates every incoming request.
109
+ ## Incoming request examples
110
+
111
+ ### Rack middleware
112
+ Rack middlewares sits in between your app and the HTTP request and validate the signature before hitting your app. Read more about [rack middlewares here](https://codenoble.com/blog/understanding-rack-middleware/).
113
+
114
+ Here is how it could be used with sinatra:
135
115
 
136
- #### General rack application
137
- Sinatra for example
138
116
  ```ruby
139
117
  require 'http_signature/rack'
140
118
 
141
- HTTPSignature.config(keys: [{ id: 'key-1', value: 'MySecureKey' }])
142
- # You can exclude paths where you don't want to validate the signature:
143
- HTTPSignature::Rack.exclude_paths = ['/']
119
+ HTTPSignature.configure do |config|
120
+ config.keys = [
121
+ {id: 'key-1', value: 'MySecureKey'}
122
+ ]
123
+ end
124
+ HTTPSignature::Rack.exclude_paths = ['/', '/hello/*']
144
125
 
145
126
  use HTTPSignature::Rack
146
127
  run MyApp
147
128
  ```
148
129
 
149
- #### Rails
150
- Checkout [this documentation](http://guides.rubyonrails.org/rails_on_rack.html). But in short, add this inside the config block:
130
+ ### Rails
131
+ Opt-in per controller/action using a before_action. It responds with `401 Unauthorized` if the signature is invalid
132
+
151
133
  ```ruby
152
- require 'http_signature/rack' # This doesn't have to be inside the block
153
- config.middleware.use HTTPSignature::Rack
134
+ # app/controllers/api/base_controller.rb
135
+
136
+ require 'http_signature/rails'
137
+
138
+ class Api::BaseController < ApplicationController
139
+ include HTTPSignature::Rails::Controller
140
+
141
+ before_action :verify_http_signature!
142
+ end
154
143
  ```
155
144
 
156
- Don't forget to set the keys somewhere, an initializer should be suitable. Multiple keys
157
- are supported to be able to easily be rotated.
145
+ Set the keys in an initializer
158
146
  ```ruby
159
- HTTPSignature.config(keys: [{ id: 'key-1', value: 'MySecureKey' }])
147
+ # config/initializers/http_signature.rb
148
+
149
+ HTTPSignature.configure do |config|
150
+ config.keys = [
151
+ {id: 'key-1', value: 'MySecureKey'}
152
+ ]
153
+ end
160
154
  ```
161
155
 
162
156
 
@@ -179,11 +173,9 @@ rake test TEST=test/http_signature_test.rb TESTOPTS="--name=/appends\ the\ query
179
173
  ## License
180
174
  This project is licensed under the terms of the [MIT license](https://opensource.org/licenses/MIT).
181
175
 
182
- ## Todo
183
- - Add more example of use with different http libraries
184
- - Refactor `.valid?` to support all algorithms
185
- - Implement algorithms:
186
- - ecdsa-sha256
187
- - When creating the signing string, follow the spec exactly:
188
- https://tools.ietf.org/html/draft-cavage-http-signatures-08#section-2.3,
189
- e.g, concatenate multiple instances of the same headers and remove surrounding whitespaces
176
+ ## Why/when should I use this?
177
+ When you need to make sure that the request or response has not been tampered with (_integrity_). And you can be sure that the request was sent by someone that had the key (_authenticity_). Don't confuse this with encryption, the signed message is not encrypted. It's just _signed_. You could add a layer of encryption on top of this. Or just use HTTPS and you're _kinda safe_ for not that much hassle, which is totally fine in most cases.
178
+
179
+ [Read more about HMAC here](https://security.stackexchange.com/questions/20129/how-and-when-do-i-use-hmac/20301), even though you can sign your messages with RSA as well, but it's the same principle.
180
+
181
+ Beware that this has not been audited and should be used at your own risk!
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
3
 
4
4
  Rake::TestTask.new do |t|
5
- t.libs << 'test'
5
+ t.libs << "test"
6
6
  t.pattern = "test/**/*_test.rb"
7
7
  t.verbose = false
8
8
  end
data/bin/standardrb ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'standardrb' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("standard", "standardrb")
@@ -1,24 +1,33 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "http_signature/version"
3
4
 
4
5
  Gem::Specification.new do |spec|
5
- spec.name = 'http_signature'
6
- spec.version = '0.0.7'
7
- spec.authors = ['Joel Larsson']
8
- spec.email = ['bolmaster2@gmail.com']
6
+ spec.name = "http_signature"
7
+ spec.version = HTTPSignature::VERSION
8
+ spec.authors = ["Joel Larsson"]
9
+ spec.email = ["bolmaster2@gmail.com"]
9
10
 
10
- spec.summary = 'Create and validate HTTP request signature'
11
- spec.description = 'Create and validate HTTP request signature according to draft: https://tools.ietf.org/html/draft-cavage-http-signatures-09'
12
- spec.homepage = 'https://github.com/bolmaster2/http-signature'
13
- spec.license = 'MIT'
11
+ spec.summary = "Create and validate HTTP Message Signatures"
12
+ spec.description = "Create and validate HTTP Message Signatures according to RFC 9421: https://www.rfc-editor.org/rfc/rfc9421.html"
13
+ spec.homepage = "https://github.com/bolmaster2/http-signature"
14
+ spec.license = "MIT"
14
15
 
15
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
- spec.bindir = 'exe'
17
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
- spec.require_paths = ['lib']
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
19
20
 
20
- spec.add_development_dependency 'bundler'
21
- spec.add_development_dependency 'rake'
22
- spec.add_development_dependency 'minitest'
23
- spec.add_development_dependency 'faraday'
21
+ spec.required_ruby_version = ">= 3.0.0"
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "minitest", ">= 5.24"
26
+ spec.add_development_dependency "rack"
27
+ spec.add_development_dependency "faraday", ">= 2.7"
28
+ spec.add_development_dependency "standard"
29
+ spec.add_development_dependency "simplecov"
30
+ spec.add_development_dependency "actionpack", ">= 6.1"
31
+
32
+ spec.add_dependency "base64"
24
33
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'http_signature'
4
- require 'faraday'
3
+ require "http_signature"
4
+ require "faraday"
5
5
 
6
6
  class HTTPSignature::Faraday < Faraday::Middleware
7
7
  class << self
@@ -9,10 +9,10 @@ class HTTPSignature::Faraday < Faraday::Middleware
9
9
  end
10
10
 
11
11
  def call(env)
12
- raise 'key and key_id needs to be set' if self.class.key.nil? || self.class.key_id.nil?
12
+ raise "key and key_id needs to be set" if self.class.key.nil? || self.class.key_id.nil?
13
13
 
14
14
  body =
15
- if env[:body] && env[:body].respond_to?(:read)
15
+ if env[:body]&.respond_to?(:read)
16
16
  string = env[:body].read
17
17
  env[:body].rewind
18
18
  string
@@ -21,20 +21,22 @@ class HTTPSignature::Faraday < Faraday::Middleware
21
21
  end
22
22
 
23
23
  # Choose which headers to sign
24
- filtered_headers = %w{ Host Date Digest }
25
- headers_to_sign = env[:request_headers].select { |k, v| filtered_headers.include?(k.to_s) }
24
+ filtered_headers = %w[Host Date Content-Digest]
25
+ headers_to_sign = env[:request_headers].select { |k, _v| filtered_headers.include?(k.to_s) }
26
26
 
27
- signature = HTTPSignature.create(
27
+ signature_headers = HTTPSignature.create(
28
28
  url: env[:url],
29
29
  method: env[:method],
30
30
  headers: headers_to_sign,
31
31
  key: self.class.key,
32
32
  key_id: self.class.key_id,
33
- algorithm: 'hmac-sha256',
33
+ algorithm: "hmac-sha256",
34
34
  body: body
35
35
  )
36
36
 
37
- env[:request_headers].merge!('Signature' => signature)
37
+ signature_headers.each do |header, value|
38
+ env[:request_headers][header] = value
39
+ end
38
40
 
39
41
  @app.call(env)
40
42
  end