http_signature 0.1.0 → 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: 821df2c08e3f1d58e737250711d5d45d6baf561d
4
- data.tar.gz: 3ee3456c48c461e7ae328b42f5c4808a7fe9cb9d
2
+ SHA256:
3
+ metadata.gz: 0d4b1e73dff1838a018f5e0d5bef1c6a6a14c2b8ef552dbbfd0481ac85cb03b7
4
+ data.tar.gz: 1a087ded86d8f84213984d9bd56fb55462f65feb9abc876514249f12fc5166ef
5
5
  SHA512:
6
- metadata.gz: 75c29e3608b55604dcc9bbbcae30d8907e3b830b8001fc563f2c606a88f7f071e54470d56c28ee3d2d9406aa173445b176e1c1bfe9c02ca2c3994b1559b0fe9c
7
- data.tar.gz: 73ec032a5fdf6813d1ac273aadf4b90d9f583c72e023299f62383c82f8ad92d17c72010b8571a9bb7d211c2781d9f477a901f89b6da3992bc5291159d298fed2
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,114 +1,61 @@
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:
10
8
  ```
11
- gem install http_signature
9
+ Signature-Input: sig1=("@method" "@authority" "@target-uri" "date");created=...
10
+ Signature: sig1=:BASE64_SIGNATURE_BYTES:
12
11
  ```
13
12
 
14
- ## Usage
13
+ ## Installation
15
14
 
16
- ```ruby
17
- require 'http_signature'
15
+ ```shell
16
+ gem install http_signature
18
17
  ```
19
18
 
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
- ```ruby
23
- HTTPSignature.create(
24
- url: 'https://example.com/foo',
25
- key_id: 'Test',
26
- key: 'secret 🙈'
27
- )
28
- # 'keyId="Test",algorithm="hmac-sha256",headers="(request-target)",signature="OQ/dHqRW9vFmrW/RCHg7O2Fqx+3uqxJw81p6k9Rcyo4="'
29
- ```
19
+ ## Usage
30
20
 
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.
21
+ ### Create signature
35
22
 
36
- ```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,
55
- headers: headers,
56
- key_id: 'Test',
57
- algorithm: 'rsa-sha256',
58
- key: File.read('key.pem'),
59
- body: body
60
- )
61
- ```
23
+ `HTTPSignature.create` returns both `Signature-Input` and `Signature` headers that you can include in your request.
62
24
 
63
- ### With digest header auto-added
64
- When digest header is omitted it's auto added as last header generated from the `body`:
65
25
 
66
26
  ```ruby
67
- body = '{"foo": "bar"}'
27
+ headers = { 'date' => 'Tue, 20 Apr 2021 02:07:55 GMT' }
68
28
 
69
- HTTPSignature.create(
70
- url: 'https://example.com/foo',
29
+ sig_headers = HTTPSignature.create(
30
+ url: 'https://example.com/foo?pet=dog',
31
+ method: :get,
32
+ headers: headers,
71
33
  key_id: 'Test',
72
- key: 'secret 🙈',
73
- body: body
34
+ key: 'secret',
35
+ covered_components: %w[@method @target-uri date],
74
36
  )
75
- # 'keyId="Test",algorithm="hmac-sha256",headers="(request-target) digest",signature="3Jm5jnCSKX3fYLd58RqRdafZKeuSbUEPhn7grCGx4vg="'
37
+
38
+ request['Signature-Input'] = sig_headers['Signature-Input']
39
+ request['Signature'] = sig_headers['Signature']
76
40
  ```
77
41
 
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.
82
42
 
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
- ```
43
+ ### Validate signature
44
+
45
+ Call `valid?` with the incoming request headers (including `Signature-Input` and `Signature`)
95
46
 
96
- Let's assume we have this request ☝️ in a `request` object for the sake of the example:
97
47
  ```ruby
98
48
  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'
49
+ url: "https://example.com/foo",
50
+ method: :get,
51
+ headers: headers,
52
+ key: "secret"
105
53
  )
106
54
  ```
107
55
 
108
- ## Example usage
56
+ ## Outgoing request examples
57
+
109
58
  ### NET::HTTP
110
- Example of using it with `NET::HTTP`. There's no real integration written so it's basically just
111
- getting the request object's data and create the signature and adding it to the headers.
112
59
 
113
60
  ```ruby
114
61
  require 'net/http'
@@ -119,7 +66,7 @@ uri = URI('http://example.com/hello')
119
66
  Net::HTTP.start(uri.host, uri.port) do |http|
120
67
  request = Net::HTTP::Get.new(uri)
121
68
 
122
- signature = HTTPSignature.create(
69
+ sig_headers = HTTPSignature.create(
123
70
  url: request.uri,
124
71
  method: request.method,
125
72
  headers: request.each_header.map { |k, v| [k, v] }.to_h,
@@ -129,66 +76,81 @@ Net::HTTP.start(uri.host, uri.port) do |http|
129
76
  body: request.body ? request.body : ''
130
77
  )
131
78
 
132
- request['Signature'] = signature
79
+ request['Signature-Input'] = sig_headers['Signature-Input']
80
+ request['Signature'] = sig_headers['Signature']
133
81
 
134
82
  response = http.request(request) # Net::HTTPResponse
135
83
  end
136
84
  ```
137
85
 
138
- ### Faraday middleware
139
- Example of using it with an outgoing faraday request. IMO, this is the smoothest usage.
140
- Basically you set the keys and tell faraday to use the middleware.
86
+ ### Faraday
87
+
88
+ As a faraday middleware
141
89
 
142
90
  ```ruby
143
91
  require 'http_signature/faraday'
144
92
 
145
- HTTPSignature::Faraday.key = 'MySecureKey' # This should be long and random
146
- 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'
147
95
 
148
- # Tell faraday to use the middleware. Read more about it here: https://github.com/lostisland/faraday#advanced-middleware-usage
149
96
  Faraday.new('http://example.com') do |faraday|
150
97
  faraday.use(HTTPSignature::Faraday)
151
98
  faraday.adapter(Faraday.default_adapter)
152
99
  end
153
100
 
154
- # Now this request will contain the `Signature` header
101
+ # Now this request will contain the `Signature-Input` and `Signature` headers
155
102
  response = conn.get('/')
156
103
 
157
104
  # Request looking like:
158
- # GET / HTTP/1.1
159
- # User-Agent: Faraday v0.15.0
160
- # 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:
161
107
  ```
162
108
 
163
- ### Rack middleware for incoming requests
164
- I've written a quite sloppy but totally usable rack middleware that validates incoming requests.
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:
165
115
 
166
- #### General Rack application
167
- Sinatra for example
168
116
  ```ruby
169
117
  require 'http_signature/rack'
170
118
 
171
- HTTPSignature.config(keys: [{ id: 'key-1', value: 'MySecureKey' }])
172
- # You can exclude paths where you don't want to validate the signature, it's using
173
- # regexp so you can use `*` and stuff like that. Just watch out so you don't exclude
174
- # more paths than intended. Regexp can trick you when you least expect it 👻.
119
+ HTTPSignature.configure do |config|
120
+ config.keys = [
121
+ {id: 'key-1', value: 'MySecureKey'}
122
+ ]
123
+ end
175
124
  HTTPSignature::Rack.exclude_paths = ['/', '/hello/*']
176
125
 
177
126
  use HTTPSignature::Rack
178
127
  run MyApp
179
128
  ```
180
129
 
181
- #### Rails
182
- 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
+
183
133
  ```ruby
184
- require 'http_signature/rack' # This doesn't have to be inside the block
185
- 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
186
143
  ```
187
144
 
188
- Don't forget to set the keys somewhere, an initializer should be suitable. Multiple keys
189
- are supported to be able to easily be rotated.
145
+ Set the keys in an initializer
190
146
  ```ruby
191
- 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
192
154
  ```
193
155
 
194
156
 
@@ -211,11 +173,9 @@ rake test TEST=test/http_signature_test.rb TESTOPTS="--name=/appends\ the\ query
211
173
  ## License
212
174
  This project is licensed under the terms of the [MIT license](https://opensource.org/licenses/MIT).
213
175
 
214
- ## Todo
215
- - Add more example of use with different http libraries
216
- - Refactor `.valid?` to support all algorithms
217
- - Implement algorithms:
218
- - ecdsa-sha256
219
- - When creating the signing string, follow the spec exactly:
220
- https://tools.ietf.org/html/draft-cavage-http-signatures-08#section-2.3,
221
- 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,25 +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
+ require "http_signature/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'http_signature'
7
- spec.version = HTTPSignature::VERSION
8
- spec.authors = ['Joel Larsson']
9
- 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"]
10
10
 
11
- spec.summary = 'Create and validate HTTP request signature'
12
- spec.description = 'Create and validate HTTP request signature according to draft: https://tools.ietf.org/html/draft-cavage-http-signatures-09'
13
- spec.homepage = 'https://github.com/bolmaster2/http-signature'
14
- 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"
15
15
 
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']
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"]
20
20
 
21
- spec.add_development_dependency 'bundler'
22
- spec.add_development_dependency 'rake'
23
- spec.add_development_dependency 'minitest'
24
- 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"
25
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]
24
+ filtered_headers = %w[Host Date Content-Digest]
25
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]['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