http_signatures 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: 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