rack-contrib-sign 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e063e40cf6ff43aa7ccd9f89e905d4f87a733baf
4
+ data.tar.gz: 7a20e29567951a4d2908bb5a64aea76820fb4c87
5
+ SHA512:
6
+ metadata.gz: 7d2255f91a0a46d4f65a26ab6589a1c480ef9caa5fa0a2b27f55900cb90c367f4f1689e06ea836df5552a074f7c3256aa939b0e0a6bd9f41f64d3092461321a2
7
+ data.tar.gz: e4013973326b23f2f14101a725b775f908409ccefaa313208257460b76e2fafddad8166c4014de3a671d51f50ea73df4947343e83d229f25029f06da19e373ea
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ guard :rspec, all_on_start: false, all_after_pass: false, notification: false do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 ZippyKid
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Rack::Contrib::Sign
2
+
3
+ Implement thorough request signing in Rack.
4
+
5
+ ## Installation
6
+
7
+
8
+ gem 'rack-contrib-sign'
9
+
10
+ And then execute:
11
+
12
+ $ bundle
13
+
14
+ Or install it yourself as:
15
+
16
+ $ gem install rack-contrib-sign
17
+
18
+ ## Usage
19
+
20
+ Install in Rack by adding the following to your config.ru:
21
+
22
+ ```ruby
23
+ require 'rack/contrib/sign'
24
+ use Rack::Contrib::Sign::Middleware
25
+ ```
26
+
27
+ ## Specific Authentication Details
28
+
29
+ This gem works by creating a receipt which gets HMAC hashed with a secret.
30
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
6
+
@@ -0,0 +1,15 @@
1
+
2
+ require 'logger'
3
+
4
+ require "rack/contrib/sign/version"
5
+ require 'rack/contrib/sign/middleware'
6
+ require 'rack/contrib/sign/receipt'
7
+
8
+ module Rack
9
+ module Contrib
10
+ module Sign
11
+
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,109 @@
1
+
2
+ module Rack
3
+ module Contrib
4
+ module Sign
5
+ class Middleware
6
+ def initialize app, opts
7
+
8
+ @app = app
9
+ @logger = opts[:logger]
10
+ @realm = opts[:realm]
11
+ @credentials = opts[:credentials]
12
+ @header_prefix = (opts[:prefix] || "").gsub(/-/, '_').downcase
13
+ end
14
+
15
+ def call env
16
+ creds = extract_credentials env['HTTP_AUTHORIZATION']
17
+ unless creds
18
+ @logger.info "Denied: Authorization header not present or invalid."
19
+ return [401, {}, []]
20
+ end
21
+
22
+ receipt = build_receipt env, creds
23
+ unless receipt.api_secret
24
+ @logger.info "Denied: API key not recognized."
25
+ return [401, {}, []]
26
+ end
27
+
28
+ sign = receipt.to_s
29
+
30
+ digest = OpenSSL::Digest::Digest.new('sha1')
31
+ validation = OpenSSL::HMAC.hexdigest(digest, receipt.api_secret, sign)
32
+
33
+ unless validation == creds[:signature]
34
+ @logger.error "Denied: Authorization signature does not match"
35
+ @logger.info "Denied: EXPECTED: %s GOT: %s" % [
36
+ validation,
37
+ creds[:signature]
38
+ ]
39
+ @logger.debug "Generated signing data:"
40
+ @logger.debug sign
41
+ return [401, {}, []]
42
+ end
43
+
44
+ @app.call env
45
+ end
46
+
47
+ # Extract environmental data into a Receipt
48
+ def build_receipt env, credentials
49
+ receipt = Rack::Contrib::Sign::Receipt.new
50
+ receipt.uri = env['REQUEST_URI']
51
+ receipt.request_method = env['REQUEST_METHOD']
52
+ receipt.body = extract_body env
53
+
54
+ extract_headers(env).each { |h,v| receipt.headers[h] = v }
55
+
56
+ receipt.api_key = credentials[:key]
57
+ receipt.api_secret = get_secret(credentials[:key])
58
+
59
+ receipt
60
+ end
61
+
62
+ # Extract the body from the environment, ensuring to rewind
63
+ # the input back to zero, so future access gets the arguments.
64
+ def extract_body env
65
+ env['rack.input'].read
66
+ ensure
67
+ env['rack.input'].rewind
68
+ end
69
+
70
+ # Extract all the headers with our Prefix from the ENV
71
+ # and return the hash
72
+ def extract_headers env
73
+ headers = {}
74
+
75
+ env.sort_by { |k,v| k.to_s.downcase }.each do |key,val|
76
+ next unless key =~ /^http_#{@header_prefix}/i
77
+ header = key.sub(/^http_/i, '').gsub(/_/, '-')
78
+ headers[header] = val
79
+ end
80
+
81
+ headers
82
+ end
83
+
84
+ # Pass in the Authorization header, and get back the key
85
+ # and signature.
86
+ def extract_credentials auth_header
87
+ return false if auth_header.nil?
88
+
89
+ pattern = /^(?<realm>.*) (?<api_key>.*):(?<signature>.*)$/
90
+ matches = auth_header.match(pattern)
91
+
92
+ return false if matches.nil?
93
+ return false unless matches[:realm] == @realm
94
+
95
+ {
96
+ key: matches[:api_key],
97
+ signature: matches[:signature]
98
+ }
99
+ end
100
+
101
+ def get_secret api_key
102
+ return false unless @credentials.has_key? api_key
103
+
104
+ return @credentials.fetch(api_key)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,48 @@
1
+
2
+ module Rack
3
+ module Contrib
4
+ module Sign
5
+ class Receipt
6
+ attr_reader :request_method
7
+ attr_reader :headers
8
+ attr_accessor :api_key
9
+ attr_accessor :api_secret
10
+ attr_accessor :body
11
+ attr_accessor :uri
12
+
13
+ def initialize
14
+ @headers = {}
15
+ end
16
+
17
+ def request_method= s
18
+ @request_method = s.upcase
19
+ end
20
+
21
+ def to_s
22
+ preamble + header_text
23
+ end
24
+
25
+ def preamble
26
+ s = ""
27
+ s << "%s %s\n" % [request_method, uri]
28
+ s << "%s\n" % api_key
29
+ s << "%s\n" % api_secret
30
+ s << "%s\n" % body
31
+ s << "--\n"
32
+ s
33
+ end
34
+
35
+ def header_text
36
+ s = ""
37
+
38
+ headers.sort_by { |k,v| k.downcase }.each do |header, value|
39
+ s << "%s:%s\n" % [header.downcase, value]
40
+ end
41
+
42
+ s
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,7 @@
1
+ module Rack
2
+ module Contrib
3
+ module Sign
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rack/contrib/sign/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rack-contrib-sign"
8
+ spec.version = Rack::Contrib::Sign::VERSION
9
+ spec.authors = ["Graham Christensen"]
10
+ spec.email = ["info@zippykid.com"]
11
+ spec.description = %q{Implement secure API request igning.}
12
+ spec.summary = %q{Validates headers and API keys in Authorization}
13
+ spec.homepage = "https://github.com/zippykid/rack-contrib-sign"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov"
25
+ spec.add_development_dependency('guard')
26
+ spec.add_development_dependency('guard-rspec')
27
+
28
+ end
29
+
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::Contrib::Sign::Middleware do
4
+ let (:app) do
5
+ app = double()
6
+ app.stub(:call => 'Hello, world!')
7
+
8
+ app
9
+ end
10
+ let (:log_string) { StringIO.new }
11
+ let (:logger) do
12
+ logger = Logger.new(log_string, Logger::DEBUG)
13
+ logger.formatter = proc do |severity, datetime, progname, msg|
14
+ "#{severity} - #{msg}\n"
15
+ end
16
+
17
+ logger
18
+ end
19
+ let (:cred_provider) { Hash.new }
20
+ let (:ware) { Rack::Contrib::Sign::Middleware.new(
21
+ app,
22
+ logger: logger,
23
+ realm: "foo-bar",
24
+ prefix: "HI-",
25
+ credentials: cred_provider,
26
+ )}
27
+
28
+ describe "#build_receipt" do
29
+ it "sets various options" do
30
+ env = {
31
+ 'REQUEST_METHOD' => 'POST',
32
+ 'REQUEST_URI' => 'foo/bar',
33
+ 'HTTP_HI_FOOO' => 'YIPEE',
34
+ 'rack.input' => StringIO.new('foo=bar')
35
+ }
36
+ cred_provider['123'] = 'abc'
37
+ creds = { key: '123', signature: 'foo' }
38
+
39
+ receipt = ware.build_receipt(env, creds)
40
+
41
+ receipt.uri.should eq('foo/bar')
42
+ receipt.request_method.should eq('POST')
43
+ receipt.body.should eq('foo=bar')
44
+ receipt.api_key.should eq('123')
45
+ receipt.api_secret.should eq('abc')
46
+ receipt.headers.should eq({
47
+ 'HI-FOOO' => 'YIPEE',
48
+ })
49
+
50
+ end
51
+ end
52
+
53
+ describe "#extract_body" do
54
+ it "returns the body of a request from the environment" do
55
+ env = {
56
+ 'rack.input' => StringIO.new('fooz=baz')
57
+ }
58
+
59
+ ware.extract_body(env).should eq('fooz=baz')
60
+ end
61
+
62
+ it "rewinds the input after reading" do
63
+ str = StringIO.new('fooz=baz')
64
+ env = {
65
+ 'rack.input' => str
66
+ }
67
+
68
+ str.pos.should eq(0)
69
+ end
70
+ end
71
+
72
+
73
+ describe "#extract_headers" do
74
+ it "returns headers prefixed with HI-" do
75
+ headers = {
76
+ 'HTTP_HI_FOO' => ':/',
77
+ 'HTTP_BYE_FOO' => ':(',
78
+ 'HTTP_HI_oentuheou' => ':)'
79
+ }
80
+
81
+ found_headers = ware.extract_headers(headers)
82
+
83
+ expected_headers = {
84
+ 'HI-FOO' => ':/',
85
+ 'HI-oentuheou' => ':)'
86
+ }
87
+ found_headers.should eq(expected_headers)
88
+ end
89
+ end
90
+
91
+ describe "#extract_credentials" do
92
+ it "returns false when nil is provided" do
93
+ header = nil
94
+
95
+ ware.extract_credentials(header).should eq(false)
96
+ end
97
+
98
+ it "returns false when the header is garbled" do
99
+ header = "LOL WHAT I DON'T EVEN"
100
+
101
+ ware.extract_credentials(header).should eq(false)
102
+ end
103
+
104
+ it "returns my key and signature when a formatted string is provided" do
105
+ header = 'foo-bar mykey:signature'
106
+
107
+ ware.extract_credentials(header).should eq(key: 'mykey', signature: 'signature')
108
+ end
109
+
110
+ it "returns false if the realm fails to match" do
111
+ header = 'foo-bar-baz mykey:signature'
112
+
113
+ ware.extract_credentials(header).should eq(false)
114
+ end
115
+
116
+ end
117
+
118
+ describe "#call" do
119
+ context "I have no other tests" do
120
+ it "abandons ship if there is no authorization header" do
121
+ env = {}
122
+
123
+ returned = ware.call(env)
124
+
125
+ returned.should eq([401, {}, []])
126
+ log_string.string.should eq("INFO - Denied: Authorization header not present or invalid.\n")
127
+ end
128
+
129
+ it "abandons ship if the API key is not known" do
130
+ env = {
131
+ 'HTTP_AUTHORIZATION' => 'foo-bar 123:foo',
132
+ 'REQUEST_METHOD' => '?',
133
+ 'rack.input' => StringIO.new()
134
+ }
135
+
136
+ returned = ware.call(env)
137
+
138
+ returned.should eq([401, {}, []])
139
+ log_string.string.should eq("INFO - Denied: API key not recognized.\n")
140
+ end
141
+
142
+ it "401s when I don't sign it right" do
143
+ env = {
144
+ 'HTTP_AUTHORIZATION' => 'foo-bar abc:YABBA DABBA DOOO',
145
+ 'REQUEST_METHOD' => 'POST',
146
+ 'REQUEST_URI' => 'http://foo/bar/baz',
147
+ 'rack.input' => StringIO.new('foo=bar'),
148
+ }
149
+
150
+ returned = ware.call(env)
151
+
152
+ returned.should eq([401, {}, []])
153
+ end
154
+ it "works when I sign it right" do
155
+ cred_provider['123'] = 'abc'
156
+ env = {
157
+ 'HTTP_AUTHORIZATION' => 'foo-bar 123:0d501b6934dc0ec5f1452947a7afd108e41c91af',
158
+ 'REQUEST_METHOD' => 'POST',
159
+ 'REQUEST_URI' => 'http://foo/bar/baz',
160
+ 'rack.input' => StringIO.new('foo=bar'),
161
+ 'HTTP_HI_FOOOO' => 'aoenuoneuh',
162
+ 'HTTP_BYE_FOOO' => 'oeucorgcgc'
163
+ }
164
+
165
+ returned = ware.call(env)
166
+
167
+ log_string.string.should eq('')
168
+ app.should have_received(:call).once.with(env)
169
+ returned.should eq('Hello, world!')
170
+ end
171
+ end
172
+ end
173
+ end
174
+
@@ -0,0 +1,91 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Rack::Contrib::Sign::Receipt do
5
+ let (:receipt) { Rack::Contrib::Sign::Receipt.new }
6
+ it { should respond_to(:api_key) }
7
+ it { should respond_to(:api_key=) }
8
+ it { should respond_to(:api_secret) }
9
+ it { should respond_to(:api_secret=) }
10
+ it { should respond_to(:body) }
11
+ it { should respond_to(:body=) }
12
+ it { should respond_to(:request_method) }
13
+ it { should respond_to(:request_method=) }
14
+ it { should respond_to(:uri) }
15
+ it { should respond_to(:uri=) }
16
+ it { should respond_to(:headers) }
17
+
18
+ describe "#request_method" do
19
+ it "upcases the method" do
20
+ receipt.request_method = 'post'
21
+ receipt.request_method.should eq('POST')
22
+ end
23
+ end
24
+
25
+ describe "#headers" do
26
+ it "defaults to an empty hash" do
27
+ receipt.headers.should eq({})
28
+ end
29
+
30
+ it "keeps around my headers" do
31
+ receipt.headers['A-a'] = 'foo'
32
+ receipt.headers['B-b'] = 'bar'
33
+
34
+ headers = receipt.headers
35
+
36
+ headers.should eq({
37
+ 'A-a' => 'foo',
38
+ 'B-b' => 'bar'
39
+ })
40
+ end
41
+ end
42
+
43
+ describe "#preamble" do
44
+ it "incorporates all the preamble elements in a string block" do
45
+ receipt.api_key = 'abc'
46
+ receipt.api_secret = '123'
47
+ receipt.body = 'foo=bar'
48
+ receipt.request_method = 'post'
49
+ receipt.uri = 'http://example.com/123'
50
+
51
+ returned = receipt.preamble
52
+
53
+ r = "POST http://example.com/123\n"
54
+ r << "abc\n"
55
+ r << "123\n"
56
+ r << "foo=bar\n"
57
+ r << "--\n"
58
+
59
+ returned.should eq(r)
60
+ end
61
+ end
62
+
63
+ describe "#header_test" do
64
+ it "sorts the headers alphabetically and lowercases them" do
65
+ receipt.headers['B-b'] = 'bar'
66
+ receipt.headers['A-a'] = 'foo'
67
+
68
+ headers = receipt.header_text
69
+
70
+ r = ""
71
+ r << "a-a:foo\n"
72
+ r << "b-b:bar\n"
73
+
74
+ headers.should eq(r)
75
+ end
76
+ end
77
+
78
+ describe "#to_s" do
79
+ it "mushes to gether the preamble and headers" do
80
+ receipt.stub(:preamble => "foo\n--\n")
81
+ receipt.stub(:header_text=> "bar\n")
82
+
83
+ returned = receipt.to_s
84
+
85
+ receipt.should have_received(:preamble)
86
+ receipt.should have_received(:header_text)
87
+ returned.should eq("foo\n--\nbar\n")
88
+ end
89
+ end
90
+ end
91
+
@@ -0,0 +1,11 @@
1
+
2
+ require "spec_helper"
3
+
4
+ describe Rack::Contrib::Sign do
5
+ describe "#VERSION" do
6
+ it "has a version" do
7
+ Rack::Contrib::Sign::VERSION.should_not eq('')
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,14 @@
1
+ require 'simplecov'
2
+ require 'stringio'
3
+
4
+ SimpleCov.start do
5
+ add_group "Rack Code", "/lib"
6
+ end
7
+
8
+ require 'rspec'
9
+ require 'rack/contrib/sign'
10
+
11
+ RSpec.configure do |config|
12
+ config.mock_with :rspec
13
+ end
14
+
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-contrib-sign
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Graham Christensen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Implement secure API request igning.
98
+ email:
99
+ - info@zippykid.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .rspec
106
+ - Gemfile
107
+ - Guardfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - lib/rack/contrib/sign.rb
112
+ - lib/rack/contrib/sign/middleware.rb
113
+ - lib/rack/contrib/sign/receipt.rb
114
+ - lib/rack/contrib/sign/version.rb
115
+ - rack-contrib-sign.gemspec
116
+ - spec/rack/contrib/sign/middleware_spec.rb
117
+ - spec/rack/contrib/sign/receipt_spec.rb
118
+ - spec/rack/contrib/sign/version_spec.rb
119
+ - spec/spec_helper.rb
120
+ homepage: https://github.com/zippykid/rack-contrib-sign
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.0.5
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Validates headers and API keys in Authorization
144
+ test_files:
145
+ - spec/rack/contrib/sign/middleware_spec.rb
146
+ - spec/rack/contrib/sign/receipt_spec.rb
147
+ - spec/rack/contrib/sign/version_spec.rb
148
+ - spec/spec_helper.rb