http_signatures 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d470a2f4d0e20f91439770b757fec53dfe6e0cf7
4
+ data.tar.gz: 44e3fc97e52f403f4a71c7c0d9aead5440128409
5
+ SHA512:
6
+ metadata.gz: 6ae9785147e0d0d07deec0af632caafdc67ea901eea51ead27c990ef0bc98e9c39b0b465e7961898271f231aa035fd823ff2a9b026f0ed6c6a3a2344d5142fec
7
+ data.tar.gz: 69334e7da16049f64d3ccba567a4737c75071290c698699111bfae112449d20bdd570295f9a8053948b6dca023502d395df37f435475f682f407907b21b600f3
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 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 99designs
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,72 @@
1
+ # HTTP Signatures
2
+
3
+ Ruby implementation of [HTTP Signatures][draft03] draft specification;
4
+ cryptographically sign and verify HTTP requests and responses.
5
+
6
+
7
+ ## Usage
8
+
9
+ Configure a context with your algorithm, keys, headers to sign. In Rails,
10
+ this is best placed in an initializer.
11
+
12
+ ```rb
13
+ require "http_signatures"
14
+
15
+ $context = HttpSignatures::Context.new(
16
+ keys: {"examplekey" => "secret-key-here"},
17
+ algorithm: "hmac-sha256",
18
+ headers: %w{(request-target) Date Content-Length},
19
+ )
20
+ ```
21
+
22
+ ### Messages
23
+
24
+ A message is an HTTP request or response. A subset of the interface of
25
+ Ruby's Net::HTTPRequest and Net::HTTPResponse is expected; the ability to
26
+ set/read headers via `message["name"]`, and for requests, the presence
27
+ of `message#method` and `message#path` for `(request-target)` support.
28
+
29
+ ```rb
30
+ require "net/http"
31
+ require "time"
32
+ message = Net::HTTP::Get.new(
33
+ "/path?query=123",
34
+ "Date" => Time.now.rfc822,
35
+ "Content-Length" => "0",
36
+ )
37
+ ```
38
+
39
+ ### Signing a message
40
+
41
+ ```rb
42
+ $context.signer("examplekey").sign(message)
43
+ ```
44
+
45
+ Now `message` contains the signature headers:
46
+
47
+ ```rb
48
+ message["Signature"]
49
+ # keyId="examplekey",algorithm="hmac-sha256",headers="...",signature="..."
50
+
51
+ message["Authorization"]
52
+ # Signature keyId="examplekey",algorithm="hmac-sha256",headers="...",signature="..."
53
+ ```
54
+
55
+ ### Verifying a signed message
56
+
57
+ Message verification is not implemented, but will look like this:
58
+
59
+ * The key ID, algorithm name, header list and provided signature will be parsed
60
+ from the `Signature` and/or `Authorization` header.
61
+ * The signing string will be derived by selecting the listed headers from the
62
+ message.
63
+ * The valid signature will be derived by applying the algorithm and secret key.
64
+ * The message is valid if the provided signature matches the valid signature.
65
+
66
+
67
+ ## Contributing
68
+
69
+ Pull Requests are welcome.
70
+
71
+
72
+ [draft03]: http://tools.ietf.org/html/draft-cavage-http-signatures-03
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'http_signatures/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "http_signatures"
8
+ spec.version = HttpSignatures::VERSION
9
+ spec.authors = ["Paul Annesley"]
10
+ spec.email = ["paul@annesley.cc"]
11
+ spec.summary = "Sign and verify HTTP messages"
12
+ spec.homepage = "https://github.com/99designs/http-signatures-ruby"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec", "~> 3.0"
23
+ end
@@ -0,0 +1,22 @@
1
+ require "openssl"
2
+
3
+ module HttpSignatures
4
+ module Algorithm
5
+ class Hmac
6
+
7
+ def initialize(digest_name)
8
+ @digest_name = digest_name
9
+ @digest = OpenSSL::Digest.new(digest_name)
10
+ end
11
+
12
+ def name
13
+ "hmac-#{@digest_name}"
14
+ end
15
+
16
+ def sign(key, data)
17
+ OpenSSL::HMAC.digest(@digest, key, data)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module HttpSignatures
2
+ module Algorithm
3
+ class Null
4
+
5
+ def name
6
+ "null"
7
+ end
8
+
9
+ def sign(key, data)
10
+ "null"
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module HttpSignatures
2
+ module Algorithm
3
+
4
+ def self.create(name)
5
+ case name
6
+ when "null" then Null.new
7
+ when "hmac-sha1" then Hmac.new("sha1")
8
+ when "hmac-sha256" then Hmac.new("sha256")
9
+ else raise UnknownAlgorithm.new(name)
10
+ end
11
+ end
12
+
13
+ class UnknownAlgorithm < StandardError
14
+ def initialize(name)
15
+ super("Unknown algorithm name '#{name}'")
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module HttpSignatures
2
+ class Context
3
+
4
+ def initialize(keys: {}, algorithm: nil, headers: nil)
5
+ @key_store = KeyStore.new(keys)
6
+ @algorithm_name = algorithm
7
+ @headers = headers
8
+ end
9
+
10
+ def signer(key_id)
11
+ Signer.new(
12
+ key: @key_store.fetch(key_id),
13
+ algorithm: Algorithm.create(@algorithm_name),
14
+ header_list: HeaderList.new(@headers),
15
+ )
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,49 @@
1
+ module HttpSignatures
2
+ class HeaderList
3
+
4
+ # cannot sign the signature headers
5
+ ILLEGAL = ["authorization", "signature"]
6
+
7
+ def self.from_string(string)
8
+ new(string.split(" "))
9
+ end
10
+
11
+ def initialize(names)
12
+ @names = names.map(&:downcase)
13
+ validate_names!
14
+ end
15
+
16
+ def to_a
17
+ @names.dup
18
+ end
19
+
20
+ def to_s
21
+ @names.join(" ")
22
+ end
23
+
24
+ private
25
+
26
+ def validate_names!
27
+ if @names.empty?
28
+ raise EmptyHeaderList
29
+ end
30
+ if illegal_headers_present.any?
31
+ raise IllegalHeader, illegal_headers_present
32
+ end
33
+ end
34
+
35
+ def illegal_headers_present
36
+ ILLEGAL & @names
37
+ end
38
+
39
+ class IllegalHeader < StandardError
40
+ def initialize(names)
41
+ names_string = names.map { |n| "'#{n}'" }.join(", ")
42
+ super("Header #{names_string} not permitted")
43
+ end
44
+ end
45
+
46
+ class EmptyHeaderList < StandardError; end
47
+
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module HttpSignatures
2
+ class Key
3
+
4
+ def initialize(id:, secret:)
5
+ @id = id
6
+ @secret = secret
7
+ end
8
+
9
+ attr_reader :id
10
+ attr_reader :secret
11
+
12
+ def ==(other)
13
+ self.class == other.class &&
14
+ self.id == other.id &&
15
+ self.secret == other.secret
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module HttpSignatures
2
+ class KeyStore
3
+
4
+ def initialize(key_hash)
5
+ @keys = {}
6
+ key_hash.each { |id, secret| self[id] = secret }
7
+ end
8
+
9
+ def fetch(id)
10
+ @keys.fetch(id)
11
+ end
12
+
13
+ private
14
+
15
+ def []=(id, secret)
16
+ @keys[id] = Key.new(id: id, secret: secret)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require "base64"
2
+
3
+ module HttpSignatures
4
+ class SignatureParameters
5
+
6
+ def initialize(key:, algorithm:, header_list:, signature:)
7
+ @key = key
8
+ @algorithm = algorithm
9
+ @header_list = header_list
10
+ @signature = signature
11
+ end
12
+
13
+ def to_str
14
+ parameter_components.join(",")
15
+ end
16
+
17
+ private
18
+
19
+ def parameter_components
20
+ pc = []
21
+ pc << 'keyId="%s"' % @key.id
22
+ pc << 'algorithm="%s"' % @algorithm.name
23
+ pc << 'headers="%s"' % @header_list.to_s
24
+ pc << 'signature="%s"' % signature_base64
25
+ pc
26
+ end
27
+
28
+ def signature_base64
29
+ Base64.strict_encode64(@signature)
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ module HttpSignatures
2
+ class Signer
3
+
4
+ AUTHORIZATION_SCHEME = "Signature"
5
+
6
+ def initialize(key:, algorithm:, header_list:)
7
+ @key = key
8
+ @algorithm = algorithm
9
+ @header_list = header_list
10
+ end
11
+
12
+ def sign(message)
13
+ message.tap do |m|
14
+ signature = signature_parameters_for_message(message).to_str
15
+ m["Signature"] = [signature]
16
+ m["Authorization"] = [AUTHORIZATION_SCHEME + " " + signature]
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def signature_parameters_for_message(message)
23
+ SignatureParameters.new(
24
+ key: @key,
25
+ algorithm: @algorithm,
26
+ header_list: @header_list,
27
+ signature: signature_for_message(message),
28
+ )
29
+ end
30
+
31
+ def signature_for_message(message)
32
+ @algorithm.sign(@key.secret, signing_string_for_message(message))
33
+ end
34
+
35
+ def signing_string_for_message(message)
36
+ SigningString.new(
37
+ header_list: @header_list,
38
+ message: message,
39
+ ).to_s
40
+ end
41
+
42
+ class EmptyHeaderNames < StandardError; end
43
+
44
+ class MessageMissingHeader < StandardError
45
+ def initialize(name)
46
+ super("Message missing header '#{name}'")
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ module HttpSignatures
2
+ class SigningString
3
+
4
+ REQUEST_TARGET = "(request-target)"
5
+
6
+ def initialize(header_list:, message:)
7
+ @header_list = header_list
8
+ @message = message
9
+ end
10
+
11
+ def to_s
12
+ @header_list.to_a.map do |header|
13
+ "%s: %s" % [header, header_value(header)]
14
+ end.join("\n")
15
+ end
16
+
17
+ def header_value(header)
18
+ if header == REQUEST_TARGET
19
+ request_target
20
+ else
21
+ @message.fetch(header) { raise HeaderNotInMessage, header }
22
+ end
23
+ end
24
+
25
+ def request_target
26
+ "%s %s" % [@message.method.downcase, @message.path]
27
+ end
28
+
29
+ end
30
+
31
+ class HeaderNotInMessage < StandardError
32
+ def initialize(name)
33
+ super("Header '#{name}' not in message")
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,3 @@
1
+ module HttpSignatures
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,14 @@
1
+ require "http_signatures/algorithm"
2
+ require "http_signatures/algorithm/hmac"
3
+ require "http_signatures/algorithm/null"
4
+ require "http_signatures/context"
5
+ require "http_signatures/header_list"
6
+ require "http_signatures/key"
7
+ require "http_signatures/key_store"
8
+ require "http_signatures/signature_parameters"
9
+ require "http_signatures/signer"
10
+ require "http_signatures/signing_string"
11
+ require "http_signatures/version"
12
+
13
+ module HttpSignatures
14
+ end
@@ -0,0 +1,33 @@
1
+ require "base64"
2
+
3
+ RSpec.describe HttpSignatures::Algorithm do
4
+
5
+ let(:key) { "the-key" }
6
+ let(:input) { "the string\nto sign" }
7
+
8
+ {
9
+ "null" => "bnVsbA==", # "null"
10
+ "hmac-sha1" => "bXPeVc5ySIyeUapN7mpMsJRnxVg=",
11
+ "hmac-sha256" => "hRQ5zpbGudR1hokS4PqeAkveKmz2dd8SCgV8OHcramI=",
12
+ }.each do |name, base64_signature|
13
+
14
+ describe ".create('#{name}')" do
15
+ let(:algorithm) { HttpSignatures::Algorithm.create(name) }
16
+ it "has #name == '#{name}'" do
17
+ expect(algorithm.name).to eq(name)
18
+ end
19
+ it "produces known-good signature" do
20
+ signature = algorithm.sign(key, input)
21
+ expect(signature).to eq(Base64.strict_decode64(base64_signature))
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ it "raises error for unknown algorithm" do
28
+ expect {
29
+ HttpSignatures::Algorithm.create(name: "nope", key: nil)
30
+ }.to raise_error(HttpSignatures::Algorithm::UnknownAlgorithm)
31
+ end
32
+
33
+ end
@@ -0,0 +1,30 @@
1
+ require "net/http"
2
+
3
+ RSpec.describe HttpSignatures::Context do
4
+
5
+ subject(:context) do
6
+ HttpSignatures::Context.new(
7
+ keys: {"hello" => "world"},
8
+ algorithm: "null",
9
+ headers: %w{(request-target) date content-length},
10
+ )
11
+ end
12
+
13
+ let(:message) { Net::HTTP::Get.new("/", "date" => "x", "content-length" => "0") }
14
+
15
+ describe "#signer" do
16
+ it "instantiates Signer with key, algorithm, headers" do
17
+ expect(HttpSignatures::Signer).to receive(:new) do |args|
18
+ expect(args[:key]).to eq(HttpSignatures::Key.new(id: "hello", secret: "world"))
19
+ expect(args[:algorithm].name).to eq("null")
20
+ expect(args[:header_list].to_a).to eq(%w{(request-target) date content-length})
21
+ end
22
+ context.signer("hello")
23
+ end
24
+
25
+ it "signs without errors" do
26
+ context.signer("hello").sign(message)
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,36 @@
1
+ RSpec.describe HttpSignatures::HeaderList do
2
+
3
+ describe ".from_string" do
4
+ it "loads and normalizes header names" do
5
+ expect(HttpSignatures::HeaderList).to receive(:new).with(
6
+ ["(request-target)", "Date", "Content-Type"]
7
+ )
8
+ HttpSignatures::HeaderList.from_string(
9
+ "(request-target) Date Content-Type"
10
+ )
11
+ end
12
+ end
13
+
14
+ describe ".new" do
15
+ it "normalizes header names (downcase)" do
16
+ list = HttpSignatures::HeaderList.new(["(request-target)", "Date", "Content-Type"])
17
+ expect(list.to_a).to eq(["(request-target)", "date", "content-type"])
18
+ end
19
+
20
+ ["Authorization", "Signature"].each do |header|
21
+ it "raises IllegalHeader for #{header} header" do
22
+ expect {
23
+ HttpSignatures::HeaderList.new([header])
24
+ }.to raise_error(HttpSignatures::HeaderList::IllegalHeader)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#to_s" do
30
+ it "joins normalized header names with spaces" do
31
+ list = HttpSignatures::HeaderList.new(["(request-target)", "Date", "Content-Type"])
32
+ expect(list.to_s).to eq("(request-target) date content-type")
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe HttpSignatures::KeyStore do
2
+
3
+ subject(:store) do
4
+ HttpSignatures::KeyStore.new(
5
+ "hello" => "world",
6
+ "another" => "key",
7
+ )
8
+ end
9
+
10
+ describe "#fetch" do
11
+ it "retrieves keys" do
12
+ expect(store.fetch("hello")).to eq(
13
+ HttpSignatures::Key.new(id: "hello", secret: "world")
14
+ )
15
+ end
16
+ it "raises KeyError" do
17
+ expect {
18
+ store.fetch("nope")
19
+ }.to raise_error(KeyError)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,85 @@
1
+ require "net/http"
2
+
3
+ RSpec.describe HttpSignatures::Signer do
4
+
5
+ EXAMPLE_DATE = "Mon, 28 Jul 2014 15:39:13 -0700"
6
+
7
+ subject(:signer) do
8
+ HttpSignatures::Signer.new(key: key, algorithm: algorithm, header_list: header_list)
9
+ end
10
+ let(:key) { HttpSignatures::Key.new(id: "pda", secret: "sh") }
11
+ let(:algorithm) { HttpSignatures::Algorithm::Null.new }
12
+ let(:header_list) { HttpSignatures::HeaderList.new(["date", "content-type"]) }
13
+
14
+ let(:message) do
15
+ Net::HTTP::Get.new(
16
+ "/path?query=123",
17
+ "Date" => EXAMPLE_DATE,
18
+ "Content-Type" => "text/plain",
19
+ "Content-Length" => "123",
20
+ )
21
+ end
22
+
23
+ let(:authorization_structure_pattern) do
24
+ %r{
25
+ \A
26
+ Signature
27
+ \s
28
+ keyId="[\w-]+",
29
+ algorithm="[\w-]+",
30
+ (?:headers=".*",)?
31
+ signature="[a-zA-Z0-9/+=]+"
32
+ \z
33
+ }x
34
+ end
35
+
36
+ let(:signature_structure_pattern) do
37
+ %r{
38
+ \A
39
+ keyId="[\w-]+",
40
+ algorithm="[\w-]+",
41
+ (?:headers=".*",)?
42
+ signature="[a-zA-Z0-9/+=]+"
43
+ \z
44
+ }x
45
+ end
46
+
47
+ describe "#sign" do
48
+ it "passes correct signing string to algorithm" do
49
+ expect(algorithm).to receive(:sign).with(
50
+ "sh",
51
+ [
52
+ "date: #{EXAMPLE_DATE}",
53
+ "content-type: text/plain",
54
+ ].join("\n")
55
+ ).and_return("null")
56
+ signer.sign(message)
57
+ end
58
+ it "returns reference to the mutated input" do
59
+ expect(signer.sign(message)).to eq(message)
60
+ end
61
+ end
62
+
63
+ context "after signing" do
64
+ before { signer.sign(message) }
65
+ it "has valid Authorization header structure" do
66
+ expect(message["Authorization"]).to match(authorization_structure_pattern)
67
+ end
68
+ it "has valid Signature header structure" do
69
+ expect(message["Signature"]).to match(signature_structure_pattern)
70
+ end
71
+ it "matches expected Authorization header" do
72
+ expect(message["Authorization"]).to eq(
73
+ 'Signature keyId="pda",algorithm="null",' +
74
+ 'headers="date content-type",signature="bnVsbA=="'
75
+ )
76
+ end
77
+ it "matches expected Signature header" do
78
+ expect(message["Signature"]).to eq(
79
+ 'keyId="pda",algorithm="null",' +
80
+ 'headers="date content-type",signature="bnVsbA=="'
81
+ )
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,42 @@
1
+ require "net/http"
2
+
3
+ RSpec.describe HttpSignatures::SigningString do
4
+
5
+ DATE = "Tue, 29 Jul 2014 14:17:02 -0700"
6
+
7
+ subject(:signing_string) do
8
+ HttpSignatures::SigningString.new(
9
+ header_list: header_list,
10
+ message: message,
11
+ )
12
+ end
13
+
14
+ let(:header_list) do
15
+ HttpSignatures::HeaderList.from_string("(request-target) date")
16
+ end
17
+
18
+ let(:message) do
19
+ Net::HTTP::Get.new("/path?query=123", "date" => DATE, "x-herring" => "red")
20
+ end
21
+
22
+ describe "#to_s" do
23
+
24
+ it "returns correct signing string" do
25
+ expect(signing_string.to_s).to eq(
26
+ "(request-target): get /path?query=123\n" +
27
+ "date: #{DATE}"
28
+ )
29
+ end
30
+
31
+ context "for header not in message" do
32
+ let(:header_list) { HttpSignatures::HeaderList.from_string("nope") }
33
+ it "raises HeaderNotInMessage" do
34
+ expect {
35
+ signing_string.to_s
36
+ }.to raise_error(HttpSignatures::HeaderNotInMessage)
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,12 @@
1
+ require "http_signatures"
2
+
3
+ # http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
4
+ RSpec.configure do |c|
5
+
6
+ c.color = true
7
+
8
+ c.default_formatter = "documentation"
9
+
10
+ c.disable_monkey_patching!
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_signatures
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paul Annesley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-29 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: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
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: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - paul@annesley.cc
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - http_signatures.gemspec
69
+ - lib/http_signatures.rb
70
+ - lib/http_signatures/algorithm.rb
71
+ - lib/http_signatures/algorithm/hmac.rb
72
+ - lib/http_signatures/algorithm/null.rb
73
+ - lib/http_signatures/context.rb
74
+ - lib/http_signatures/header_list.rb
75
+ - lib/http_signatures/key.rb
76
+ - lib/http_signatures/key_store.rb
77
+ - lib/http_signatures/signature_parameters.rb
78
+ - lib/http_signatures/signer.rb
79
+ - lib/http_signatures/signing_string.rb
80
+ - lib/http_signatures/version.rb
81
+ - spec/algorithm_spec.rb
82
+ - spec/context_spec.rb
83
+ - spec/header_list_spec.rb
84
+ - spec/key_store_spec.rb
85
+ - spec/signer_spec.rb
86
+ - spec/signing_string_spec.rb
87
+ - spec/spec_helper.rb
88
+ homepage: https://github.com/99designs/http-signatures-ruby
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Sign and verify HTTP messages
112
+ test_files:
113
+ - spec/algorithm_spec.rb
114
+ - spec/context_spec.rb
115
+ - spec/header_list_spec.rb
116
+ - spec/key_store_spec.rb
117
+ - spec/signer_spec.rb
118
+ - spec/signing_string_spec.rb
119
+ - spec/spec_helper.rb