bollard 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 +7 -0
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +79 -0
- data/LICENCE.md +22 -0
- data/README.md +24 -0
- data/Rakefile +8 -0
- data/bollard.gemspec +28 -0
- data/lib/bollard/post.rb +33 -0
- data/lib/bollard/signature.rb +72 -0
- data/lib/bollard/version.rb +3 -0
- data/lib/bollard.rb +14 -0
- data/spec/lib/bollard/post_spec.rb +33 -0
- data/spec/lib/bollard/signature_spec.rb +75 -0
- data/spec/lib/bollard_spec.rb +45 -0
- data/spec/spec_helper.rb +16 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 902e221383e933affc9e6e06aad20ad103e3844c
|
4
|
+
data.tar.gz: 266c40c3987a7395d7505e18b9b30a4c1abed5ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7fa85f9688e7009f7ba8758162a7bf0acf04fc5a8edb728617cbf5a5003f47060276407052bdf213457aed99e0ed94eb8ec2f4e4abd56bbadc3be135cd40f8c1
|
7
|
+
data.tar.gz: b69f6bc526192d625370f9552e9ebe8793cc3dbccc6b0f7180abcc1d0da09ff88a558f4ef72a121dc8484dd97fb16f912300f0b0271a129290e42b241e54b101
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bollard (1.0.0)
|
5
|
+
jwt
|
6
|
+
rest-client
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activesupport (5.2.1)
|
12
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
|
+
i18n (>= 0.7, < 2)
|
14
|
+
minitest (~> 5.1)
|
15
|
+
tzinfo (~> 1.1)
|
16
|
+
addressable (2.5.2)
|
17
|
+
public_suffix (>= 2.0.2, < 4.0)
|
18
|
+
byebug (10.0.2)
|
19
|
+
concurrent-ruby (1.0.5)
|
20
|
+
crack (0.4.3)
|
21
|
+
safe_yaml (~> 1.0.0)
|
22
|
+
diff-lcs (1.3)
|
23
|
+
domain_name (0.5.20180417)
|
24
|
+
unf (>= 0.0.5, < 1.0.0)
|
25
|
+
hashdiff (0.3.7)
|
26
|
+
http-cookie (1.0.3)
|
27
|
+
domain_name (~> 0.5)
|
28
|
+
i18n (1.1.0)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
jwt (2.1.0)
|
31
|
+
mime-types (3.2.2)
|
32
|
+
mime-types-data (~> 3.2015)
|
33
|
+
mime-types-data (3.2018.0812)
|
34
|
+
minitest (5.11.3)
|
35
|
+
netrc (0.11.0)
|
36
|
+
public_suffix (3.0.3)
|
37
|
+
rake (12.3.1)
|
38
|
+
rest-client (2.0.2)
|
39
|
+
http-cookie (>= 1.0.2, < 2.0)
|
40
|
+
mime-types (>= 1.16, < 4.0)
|
41
|
+
netrc (~> 0.8)
|
42
|
+
rspec (3.8.0)
|
43
|
+
rspec-core (~> 3.8.0)
|
44
|
+
rspec-expectations (~> 3.8.0)
|
45
|
+
rspec-mocks (~> 3.8.0)
|
46
|
+
rspec-core (3.8.0)
|
47
|
+
rspec-support (~> 3.8.0)
|
48
|
+
rspec-expectations (3.8.1)
|
49
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
+
rspec-support (~> 3.8.0)
|
51
|
+
rspec-mocks (3.8.0)
|
52
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
+
rspec-support (~> 3.8.0)
|
54
|
+
rspec-support (3.8.0)
|
55
|
+
safe_yaml (1.0.4)
|
56
|
+
thread_safe (0.3.6)
|
57
|
+
tzinfo (1.2.5)
|
58
|
+
thread_safe (~> 0.1)
|
59
|
+
unf (0.1.4)
|
60
|
+
unf_ext
|
61
|
+
unf_ext (0.0.7.5)
|
62
|
+
webmock (2.3.2)
|
63
|
+
addressable (>= 2.3.6)
|
64
|
+
crack (>= 0.3.2)
|
65
|
+
hashdiff
|
66
|
+
|
67
|
+
PLATFORMS
|
68
|
+
ruby
|
69
|
+
|
70
|
+
DEPENDENCIES
|
71
|
+
activesupport (>= 3.1)
|
72
|
+
bollard!
|
73
|
+
byebug
|
74
|
+
rake
|
75
|
+
rspec (~> 3.7)
|
76
|
+
webmock (~> 2.3)
|
77
|
+
|
78
|
+
BUNDLED WITH
|
79
|
+
1.16.1
|
data/LICENCE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright 2018 Vinomofo
|
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,24 @@
|
|
1
|
+
# Bollard
|
2
|
+
|
3
|
+
A way of securing API communications with a JWT header that verifies a payload given a known secret
|
4
|
+
|
5
|
+
## Use
|
6
|
+
Install Bollard
|
7
|
+
|
8
|
+
```
|
9
|
+
gem install bollard
|
10
|
+
```
|
11
|
+
|
12
|
+
Use Bollard to :post messages
|
13
|
+
```
|
14
|
+
require "bollard"
|
15
|
+
|
16
|
+
Bollard.secure_post("https://my.endpoint/api", '{ "key_1": "val_1" }', "shared_secret_key")
|
17
|
+
```
|
18
|
+
|
19
|
+
Use Bollard to verify received messages
|
20
|
+
```
|
21
|
+
require "bollard"
|
22
|
+
|
23
|
+
Bollard.verify_post('{ "key_1": "val_1" }', "", "shared_secret_key")
|
24
|
+
```
|
data/Rakefile
ADDED
data/bollard.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
# Maintain your gem's version:
|
4
|
+
require "bollard/version"
|
5
|
+
|
6
|
+
# Describe your gem and declare its dependencies:
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "bollard"
|
9
|
+
s.version = Bollard::VERSION
|
10
|
+
s.license = "MIT"
|
11
|
+
s.authors = ["Michael Dilley"]
|
12
|
+
s.email = "mick@vinomofo.com"
|
13
|
+
s.homepage = "https://github.com/vinomofo/bollard"
|
14
|
+
s.summary = "Send a secure post somewhere"
|
15
|
+
s.description = "Send a secure post somewhere"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {spec,gemfiles}/*`.split("\n")
|
19
|
+
|
20
|
+
s.add_dependency "jwt"
|
21
|
+
s.add_dependency "rest-client"
|
22
|
+
|
23
|
+
s.add_development_dependency "activesupport", ">= 3.1"
|
24
|
+
s.add_development_dependency "rspec", "~> 3.7"
|
25
|
+
s.add_development_dependency "webmock", "~> 2.3"
|
26
|
+
s.add_development_dependency "byebug"
|
27
|
+
s.add_development_dependency "rake"
|
28
|
+
end
|
data/lib/bollard/post.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
module Bollard
|
4
|
+
PostError = Class.new(RuntimeError)
|
5
|
+
|
6
|
+
class Post
|
7
|
+
def initialize(url, payload, signing_secret, extra_headers, auth_header)
|
8
|
+
@url = url
|
9
|
+
@payload = payload
|
10
|
+
@signing_secret = signing_secret
|
11
|
+
@auth_header = auth_header
|
12
|
+
@extra_headers = extra_headers
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform
|
16
|
+
RestClient.post(@url, @payload, headers)
|
17
|
+
rescue RestClient::ExceptionWithResponse => e
|
18
|
+
raise PostError.new(e.response.body)
|
19
|
+
rescue RestClient::Exception => e
|
20
|
+
raise PostError.new(e.message)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def headers
|
26
|
+
@extra_headers.merge({ @auth_header => signature })
|
27
|
+
end
|
28
|
+
|
29
|
+
def signature
|
30
|
+
Signature.generate(@payload, @signing_secret)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'jwt'
|
3
|
+
|
4
|
+
module Bollard
|
5
|
+
class SignatureVerificationError < RuntimeError
|
6
|
+
attr_reader :message, :sig_header, :http_body
|
7
|
+
|
8
|
+
def initialize(message, sig_header, http_body: nil)
|
9
|
+
@message = message
|
10
|
+
@sig_header = sig_header
|
11
|
+
@http_body = http_body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Signature
|
16
|
+
EXPECTED_ALGORITHM = "sig_v1".freeze
|
17
|
+
|
18
|
+
|
19
|
+
def self.generate(data, secret, ttl: 600)
|
20
|
+
iat = Time.now.to_i
|
21
|
+
payload = { iat: iat, exp: iat + ttl, sig_v1: Digest::SHA256.hexdigest(data) }
|
22
|
+
JWT.encode(payload, secret, 'HS256')
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Verifies the signature header for a given payload.
|
27
|
+
#
|
28
|
+
# Raises a SignatureVerificationError in the following cases:
|
29
|
+
# - the header does not match the expected format
|
30
|
+
# - no hash found with the expected algorithm
|
31
|
+
# - hash doesn't match the expected hash
|
32
|
+
#
|
33
|
+
# Returns true otherwise
|
34
|
+
def self.verify(payload, header, secret, tolerance: nil)
|
35
|
+
begin
|
36
|
+
decoded_token = JWT.decode(header, secret, true, { exp_leeway: tolerance })
|
37
|
+
rescue JWT::DecodeError => e
|
38
|
+
raise SignatureVerificationError.new(e.message, header, http_body: payload)
|
39
|
+
end
|
40
|
+
|
41
|
+
provided_hash = decoded_token[0][EXPECTED_ALGORITHM]
|
42
|
+
if provided_hash.blank?
|
43
|
+
raise SignatureVerificationError.new(
|
44
|
+
"No hash found with expected algorithm #{EXPECTED_ALGORITHM}",
|
45
|
+
header, http_body: payload
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
expected_hash = Digest::SHA256.hexdigest(payload)
|
50
|
+
unless secure_compare(provided_hash, expected_hash)
|
51
|
+
raise SignatureVerificationError.new("Hash mismatch for payload", header, http_body: payload)
|
52
|
+
end
|
53
|
+
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Constant time string comparison to prevent timing attacks
|
59
|
+
|
60
|
+
# Code borrowed from ActiveSupport
|
61
|
+
def self.secure_compare(a, b)
|
62
|
+
return false unless a.bytesize == b.bytesize
|
63
|
+
|
64
|
+
l = a.unpack "C#{a.bytesize}"
|
65
|
+
|
66
|
+
res = 0
|
67
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
68
|
+
res.zero?
|
69
|
+
end
|
70
|
+
private_class_method :secure_compare
|
71
|
+
end
|
72
|
+
end
|
data/lib/bollard.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bollard/signature'
|
2
|
+
require 'bollard/post'
|
3
|
+
|
4
|
+
module Bollard
|
5
|
+
def self.secure_post(url, payload, signing_secret, extra_headers: {}, auth_header: 'Bollard-Signature')
|
6
|
+
post = Post.new(url, payload, signing_secret, extra_headers: extra_headers, auth_header: auth_header)
|
7
|
+
post.perform
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def self.verify_post(payload, header, signing_secret, tolerance: nil)
|
12
|
+
Signature.verify_header(payload, header, signing_secret, tolerance: tolerance)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Bollard::Post do
|
4
|
+
it "posts the payload to the given URL" do
|
5
|
+
stub_request(:post, "https://test.localhost/")
|
6
|
+
|
7
|
+
post = Bollard::Post.new("https://test.localhost/", "{}", "secret", {}, "Bollard-Signature")
|
8
|
+
post.perform
|
9
|
+
|
10
|
+
expect(WebMock).to have_requested(:post, "https://test.localhost").with(body: "{}")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds the correct signature header to the request" do
|
14
|
+
allow(Bollard::Signature).to receive(:generate).and_return("valid_signature")
|
15
|
+
stub_request(:post, "https://test.localhost/")
|
16
|
+
|
17
|
+
post = Bollard::Post.new("https://test.localhost/", "{}", "secret", {}, "Bollard-Signature")
|
18
|
+
post.perform
|
19
|
+
|
20
|
+
expect(WebMock).to have_requested(:post, "https://test.localhost")
|
21
|
+
.with(headers: { "Bollard-Signature" => "valid_signature" })
|
22
|
+
end
|
23
|
+
|
24
|
+
it "adds extra headers to the request" do
|
25
|
+
stub_request(:post, "https://test.localhost/")
|
26
|
+
|
27
|
+
post = Bollard::Post.new("https://test.localhost/", "{}", "secret", { content_type: :json, accept: :json }, "Bollard-Signature")
|
28
|
+
post.perform
|
29
|
+
|
30
|
+
expect(WebMock).to have_requested(:post, "https://test.localhost")
|
31
|
+
.with(headers: { content_type: 'application/json', accept: 'application/json' })
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
RSpec.describe Bollard::Signature do
|
5
|
+
describe ".generate" do
|
6
|
+
let(:jwt) { Bollard::Signature.generate("Some data", "super-secret") }
|
7
|
+
let(:jwt_payload) { JWT.decode(jwt, "super-secret", true)[0] }
|
8
|
+
|
9
|
+
it "generates a valid JWT for the given payload" do
|
10
|
+
expect { JWT.decode(jwt, "super-secret", true) }.not_to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds an issued-at field" do
|
14
|
+
travel_to(Time.now) do
|
15
|
+
expect(jwt_payload["iat"]).to eq Time.now.to_i
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "adds an expires-at field" do
|
20
|
+
travel_to(Time.now) do
|
21
|
+
expect(jwt_payload["exp"]).to eq(Time.now.to_i + 600)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when given a ttl" do
|
26
|
+
let(:jwt) { Bollard::Signature.generate("Some data", "super-secret", ttl: 100) }
|
27
|
+
|
28
|
+
it "sets the expires-at field using the configurable ttl" do
|
29
|
+
travel_to(Time.now) do
|
30
|
+
expect(jwt_payload["exp"]).to eq(Time.now.to_i + 100)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "adds a hash of the data" do
|
36
|
+
expect(jwt_payload["sig_v1"]).to eq(Digest::SHA256.hexdigest("Some data"))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "signs the jwt with the secret so it can be verified" do
|
40
|
+
expect { JWT.decode(jwt, "not-the-same-secret", true) }.to raise_error(JWT::VerificationError, "Signature verification raised")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".verify" do
|
45
|
+
it "verifies the signing secret matches the given secret" do
|
46
|
+
jwt = Bollard::Signature.generate("Some data", "super-secret")
|
47
|
+
expect { Bollard::Signature.verify("Some data", jwt, "different-super-secret") }.to raise_error(Bollard::SignatureVerificationError, "Signature verification raised")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "verifies the payload matches the given hash" do
|
51
|
+
jwt = Bollard::Signature.generate("Some data", "super-secret")
|
52
|
+
expect { Bollard::Signature.verify("Some different data", jwt, "super-secret") }.to raise_error(Bollard::SignatureVerificationError, "Hash mismatch for payload")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "verifies the format of the token" do
|
56
|
+
jwt = JWT.encode({ sig_v2: Digest::SHA256.hexdigest("Some data") }, "super-secret", 'HS256')
|
57
|
+
|
58
|
+
expect { Bollard::Signature.verify("Some data", jwt, "super-secret") }.to raise_error(Bollard::SignatureVerificationError, "No hash found with expected algorithm #{Bollard::Signature::EXPECTED_ALGORITHM}")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "ensures that the jwt hasn't expired" do
|
62
|
+
jwt = Bollard::Signature.generate("Some data", "super-secret")
|
63
|
+
travel_to(Time.now + 1200) do
|
64
|
+
expect { Bollard::Signature.verify("Some data", jwt, "super-secret") }.to raise_error(Bollard::SignatureVerificationError, "Signature has expired")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "allows leeway for the expiry if set" do
|
69
|
+
jwt = Bollard::Signature.generate("Some data", "super-secret")
|
70
|
+
travel_to(Time.now + 1200) do
|
71
|
+
expect { Bollard::Signature.verify("Some data", jwt, "super-secret", tolerance: 1200) }.not_to raise_error
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Bollard do
|
4
|
+
describe ".secure_post" do
|
5
|
+
let(:post) { instance_double(Bollard::Post, perform: true) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Bollard::Post).to receive(:new).and_return(post)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "delegates everything to Post" do
|
12
|
+
Bollard.secure_post("https://url.com", "{}", "secrets", extra_headers: { header_1: "1" }, auth_header: "Authorization")
|
13
|
+
expect(Bollard::Post).to have_received(:new).with("https://url.com", "{}", "secrets", extra_headers: { header_1: "1" }, auth_header: "Authorization")
|
14
|
+
expect(post).to have_received(:perform)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "provides defaults for extra_headers" do
|
18
|
+
Bollard.secure_post("https://url.com", "{}", "secrets", auth_header: "Authorization")
|
19
|
+
expect(Bollard::Post).to have_received(:new).with("https://url.com", "{}", "secrets", extra_headers: {}, auth_header: "Authorization")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "provides defaults for auth_header" do
|
23
|
+
Bollard.secure_post("https://url.com", "{}", "secrets", extra_headers: { header_1: "1" })
|
24
|
+
expect(Bollard::Post).to have_received(:new).with("https://url.com", "{}", "secrets", extra_headers: { header_1: "1" }, auth_header: "Bollard-Signature")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".verify_post" do
|
29
|
+
before do
|
30
|
+
allow(Bollard::Signature).to receive(:verify_header)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "delegates everything to Signature" do
|
34
|
+
Bollard.verify_post("{}", "abc123", "secrets", tolerance: 100)
|
35
|
+
|
36
|
+
expect(Bollard::Signature).to have_received(:verify_header).with("{}", "abc123", "secrets", tolerance: 100)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "provides a default for tolerance" do
|
40
|
+
Bollard.verify_post("{}", "abc123", "secrets")
|
41
|
+
|
42
|
+
expect(Bollard::Signature).to have_received(:verify_header).with("{}", "abc123", "secrets", tolerance: nil)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'byebug'
|
2
|
+
require 'active_support/testing/time_helpers'
|
3
|
+
|
4
|
+
require 'webmock/rspec'
|
5
|
+
require File.expand_path('../../lib/bollard', __FILE__)
|
6
|
+
Dir[File.expand_path('../spec/support/**/*.rb', __FILE__)].each { |f| require f }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.order = 'random'
|
10
|
+
|
11
|
+
config.expect_with :rspec do |c|
|
12
|
+
c.syntax = :expect
|
13
|
+
end
|
14
|
+
|
15
|
+
config.include ActiveSupport::Testing::TimeHelpers
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bollard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Dilley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jwt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
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: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: byebug
|
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
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Send a secure post somewhere
|
112
|
+
email: mick@vinomofo.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- ".gitignore"
|
118
|
+
- Gemfile
|
119
|
+
- Gemfile.lock
|
120
|
+
- LICENCE.md
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- bollard.gemspec
|
124
|
+
- lib/bollard.rb
|
125
|
+
- lib/bollard/post.rb
|
126
|
+
- lib/bollard/signature.rb
|
127
|
+
- lib/bollard/version.rb
|
128
|
+
- spec/lib/bollard/post_spec.rb
|
129
|
+
- spec/lib/bollard/signature_spec.rb
|
130
|
+
- spec/lib/bollard_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
homepage: https://github.com/vinomofo/bollard
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.6.8
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Send a secure post somewhere
|
156
|
+
test_files:
|
157
|
+
- spec/lib/bollard/post_spec.rb
|
158
|
+
- spec/lib/bollard/signature_spec.rb
|
159
|
+
- spec/lib/bollard_spec.rb
|
160
|
+
- spec/spec_helper.rb
|