http_signature 0.0.7 → 0.1.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/.rubocop.yml +5 -0
- data/README.md +40 -8
- data/http_signature.gemspec +2 -1
- data/lib/http_signature.rb +19 -20
- data/lib/http_signature/faraday.rb +3 -3
- data/lib/http_signature/version.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 821df2c08e3f1d58e737250711d5d45d6baf561d
|
4
|
+
data.tar.gz: 3ee3456c48c461e7ae328b42f5c4808a7fe9cb9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75c29e3608b55604dcc9bbbcae30d8907e3b830b8001fc563f2c606a88f7f071e54470d56c28ee3d2d9406aa173445b176e1c1bfe9c02ca2c3994b1559b0fe9c
|
7
|
+
data.tar.gz: 73ec032a5fdf6813d1ac273aadf4b90d9f583c72e023299f62383c82f8ad92d17c72010b8571a9bb7d211c2781d9f477a901f89b6da3992bc5291159d298fed2
|
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -105,16 +105,46 @@ HTTPSignature.valid?(
|
|
105
105
|
)
|
106
106
|
```
|
107
107
|
|
108
|
-
## Example usage
|
109
|
-
###
|
110
|
-
Example of using it
|
108
|
+
## Example usage
|
109
|
+
### 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
|
+
|
113
|
+
```ruby
|
114
|
+
require 'net/http'
|
115
|
+
require 'http_signature'
|
116
|
+
|
117
|
+
uri = URI('http://example.com/hello')
|
118
|
+
|
119
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
120
|
+
request = Net::HTTP::Get.new(uri)
|
121
|
+
|
122
|
+
signature = HTTPSignature.create(
|
123
|
+
url: request.uri,
|
124
|
+
method: request.method,
|
125
|
+
headers: request.each_header.map { |k, v| [k, v] }.to_h,
|
126
|
+
key: 'MYSECRETKEY',
|
127
|
+
key_id: 'KEY_1',
|
128
|
+
algorithm: 'hmac-sha256',
|
129
|
+
body: request.body ? request.body : ''
|
130
|
+
)
|
131
|
+
|
132
|
+
request['Signature'] = signature
|
133
|
+
|
134
|
+
response = http.request(request) # Net::HTTPResponse
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
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.
|
141
|
+
|
111
142
|
```ruby
|
112
143
|
require 'http_signature/faraday'
|
113
144
|
|
114
145
|
HTTPSignature::Faraday.key = 'MySecureKey' # This should be long and random
|
115
146
|
HTTPSignature::Faraday.key_id = 'key-1' # For the recipient to know which key to decrypt with
|
116
147
|
|
117
|
-
|
118
148
|
# Tell faraday to use the middleware. Read more about it here: https://github.com/lostisland/faraday#advanced-middleware-usage
|
119
149
|
Faraday.new('http://example.com') do |faraday|
|
120
150
|
faraday.use(HTTPSignature::Faraday)
|
@@ -131,16 +161,18 @@ response = conn.get('/')
|
|
131
161
|
```
|
132
162
|
|
133
163
|
### Rack middleware for incoming requests
|
134
|
-
I've written a quite sloppy but totally usable rack middleware that validates
|
164
|
+
I've written a quite sloppy but totally usable rack middleware that validates incoming requests.
|
135
165
|
|
136
|
-
#### General
|
166
|
+
#### General Rack application
|
137
167
|
Sinatra for example
|
138
168
|
```ruby
|
139
169
|
require 'http_signature/rack'
|
140
170
|
|
141
171
|
HTTPSignature.config(keys: [{ id: 'key-1', value: 'MySecureKey' }])
|
142
|
-
# You can exclude paths where you don't want to validate the signature
|
143
|
-
|
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 👻.
|
175
|
+
HTTPSignature::Rack.exclude_paths = ['/', '/hello/*']
|
144
176
|
|
145
177
|
use HTTPSignature::Rack
|
146
178
|
run MyApp
|
data/http_signature.gemspec
CHANGED
@@ -1,9 +1,10 @@
|
|
1
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
6
|
spec.name = 'http_signature'
|
6
|
-
spec.version =
|
7
|
+
spec.version = HTTPSignature::VERSION
|
7
8
|
spec.authors = ['Joel Larsson']
|
8
9
|
spec.email = ['bolmaster2@gmail.com']
|
9
10
|
|
data/lib/http_signature.rb
CHANGED
@@ -5,6 +5,8 @@ require 'securerandom'
|
|
5
5
|
require 'base64'
|
6
6
|
require 'uri'
|
7
7
|
|
8
|
+
# Implements signing of a request according to https://tools.ietf.org/html/draft-cavage-http-signatures
|
9
|
+
# specification.
|
8
10
|
module HTTPSignature
|
9
11
|
# Create signature based on the data sent in
|
10
12
|
#
|
@@ -18,12 +20,10 @@ module HTTPSignature
|
|
18
20
|
# @param method [Symbol] Request method, default is `:get`
|
19
21
|
# @param algorithm [String] Algorithm to use when signing, check `supported_algorithms` for
|
20
22
|
# @return [String] The signature header value to use in "Signature" header
|
21
|
-
def self.create(
|
22
|
-
key_id: SecureRandom.hex(8),
|
23
|
-
method: :get,
|
24
|
-
algorithm: 'hmac-sha256'
|
23
|
+
def self.create(
|
24
|
+
url:, query_string_params: {}, body: '', headers: {}, key:, key_id: SecureRandom.hex(8),
|
25
|
+
method: :get, algorithm: 'hmac-sha256'
|
25
26
|
)
|
26
|
-
|
27
27
|
raise 'Unsupported algorithm :(' unless supported_algorithms.include?(algorithm)
|
28
28
|
|
29
29
|
uri = URI(url)
|
@@ -32,12 +32,11 @@ module HTTPSignature
|
|
32
32
|
headers = convert_headers(headers)
|
33
33
|
query = create_query_string(uri, query_string_params)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
algorithm: algorithm)
|
35
|
+
sign_string = create_signing_string(method: method, path: path, query: query, headers: headers)
|
36
|
+
signature = sign(sign_string, key: key, algorithm: algorithm)
|
37
|
+
create_signature_header(
|
38
|
+
key_id: key_id, headers: headers, signature: signature, algorithm: algorithm
|
39
|
+
)
|
41
40
|
end
|
42
41
|
|
43
42
|
def self.sign(string, key:, algorithm:)
|
@@ -86,7 +85,7 @@ module HTTPSignature
|
|
86
85
|
# @return [String]
|
87
86
|
def self.create_signing_string(method:, path:, query:, headers:)
|
88
87
|
[
|
89
|
-
"(request-target): #{method.
|
88
|
+
"(request-target): #{method.downcase} #{path}#{query}"
|
90
89
|
].concat(headers).join("\n")
|
91
90
|
end
|
92
91
|
|
@@ -109,6 +108,7 @@ module HTTPSignature
|
|
109
108
|
uri = URI(url)
|
110
109
|
path = uri.path
|
111
110
|
signature = headers.delete(:signature)
|
111
|
+
headers = add_digest(headers, body)
|
112
112
|
headers = convert_headers(headers)
|
113
113
|
query = create_query_string(uri, query_string_params)
|
114
114
|
|
@@ -141,11 +141,13 @@ module HTTPSignature
|
|
141
141
|
# When query string params is also set on the url, append the params defined
|
142
142
|
# in `query_string_params` and make a joint query string
|
143
143
|
def self.create_query_string(uri, query_string_params)
|
144
|
-
if uri.query
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
return if !uri.query && query_string_params.empty?
|
145
|
+
|
146
|
+
delimiter = uri.query.nil? || query_string_params.empty? ? '' : '&'
|
147
|
+
|
148
|
+
['?', uri.query.to_s, delimiter, URI.encode_www_form(query_string_params)].join
|
148
149
|
end
|
150
|
+
|
149
151
|
# Convert a header hash into an array with header strings
|
150
152
|
# { header: 'value'} -> ['header: value']
|
151
153
|
def self.convert_headers(headers)
|
@@ -156,7 +158,6 @@ module HTTPSignature
|
|
156
158
|
|
157
159
|
def self.add_digest(headers, body)
|
158
160
|
headers[:digest] = create_digest(body) unless body.empty?
|
159
|
-
|
160
161
|
headers
|
161
162
|
end
|
162
163
|
|
@@ -165,9 +166,7 @@ module HTTPSignature
|
|
165
166
|
end
|
166
167
|
|
167
168
|
def self.key(id)
|
168
|
-
key = @keys.select
|
169
|
-
o[:id] == id
|
170
|
-
end.first
|
169
|
+
key = @keys.select { |o| o[:id] == id }.first
|
171
170
|
|
172
171
|
key&.dig(:value) || (raise "Key with id #{id} could not be found")
|
173
172
|
end
|
@@ -21,8 +21,8 @@ class HTTPSignature::Faraday < Faraday::Middleware
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Choose which headers to sign
|
24
|
-
filtered_headers = %w
|
25
|
-
headers_to_sign = env[:request_headers].select { |k,
|
24
|
+
filtered_headers = %w[Host Date Digest]
|
25
|
+
headers_to_sign = env[:request_headers].select { |k, _v| filtered_headers.include?(k.to_s) }
|
26
26
|
|
27
27
|
signature = HTTPSignature.create(
|
28
28
|
url: env[:url],
|
@@ -34,7 +34,7 @@ class HTTPSignature::Faraday < Faraday::Middleware
|
|
34
34
|
body: body
|
35
35
|
)
|
36
36
|
|
37
|
-
env[:request_headers]
|
37
|
+
env[:request_headers]['Signature'] = signature
|
38
38
|
|
39
39
|
@app.call(env)
|
40
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_signature
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Larsson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ extra_rdoc_files: []
|
|
75
75
|
files:
|
76
76
|
- ".circleci/config.yml"
|
77
77
|
- ".gitignore"
|
78
|
+
- ".rubocop.yml"
|
78
79
|
- ".ruby-version"
|
79
80
|
- Gemfile
|
80
81
|
- Gemfile.lock
|
@@ -84,6 +85,7 @@ files:
|
|
84
85
|
- lib/http_signature.rb
|
85
86
|
- lib/http_signature/faraday.rb
|
86
87
|
- lib/http_signature/rack.rb
|
88
|
+
- lib/http_signature/version.rb
|
87
89
|
homepage: https://github.com/bolmaster2/http-signature
|
88
90
|
licenses:
|
89
91
|
- MIT
|