json_web_token 0.1.2 → 0.2.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/CHANGELOG.md +5 -0
- data/README.md +12 -12
- data/json_web_token.gemspec +1 -1
- data/lib/json_web_token.rb +24 -3
- data/lib/json_web_token/format/asn1.rb +6 -8
- data/lib/json_web_token/jwt.rb +6 -5
- data/lib/json_web_token/util.rb +17 -5
- data/lib/json_web_token/version.rb +1 -1
- data/spec/json_web_token/jwt_spec.rb +2 -2
- data/spec/json_web_token_spec.rb +25 -16
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1bab6670404e2a3185dabc1944f130891cb6de6
|
4
|
+
data.tar.gz: 142fb6257f61b6c906e29519af046289ba085508
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 263eb8d5f5855937117026134f7dce4f76c37c48a3c0ef955d4c21d47e41395793cc3c55bea20de613f56c1808cc6ae55af919d16bfae214a81b1a8ec9f1d840
|
7
|
+
data.tar.gz: 29073ba554234ce1581d0608e29e17e12885c962ecbda6f402564c7bc85aa18669c9a47039bd817ce09e42e6def463623fd97f554bccff2b76049f610af85bd5
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# JSON Web Token [![travis][ci_img]][travis] [![yard docs][yd_img]][yard_docs] [![code climate][cc_img]][code_climate]
|
2
2
|
|
3
|
-
## A JSON Web Token implementation for Ruby
|
3
|
+
## A JSON Web Token (JWT) implementation for Ruby
|
4
4
|
|
5
5
|
### Description
|
6
|
-
A Ruby implementation of the JSON Web Token
|
6
|
+
A Ruby implementation of the JSON Web Token standard [RFC 7519][rfc7519]
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
gem install json_web_token
|
@@ -30,7 +30,7 @@ Secure Cross-Origin Resource Sharing ([CORS][cors]) using the [rack-cors][rack-c
|
|
30
30
|
|
31
31
|
## Usage
|
32
32
|
|
33
|
-
### JsonWebToken.
|
33
|
+
### JsonWebToken.sign(claims, options)
|
34
34
|
|
35
35
|
Returns a JSON Web Token string
|
36
36
|
|
@@ -47,7 +47,7 @@ Example
|
|
47
47
|
require 'json_web_token'
|
48
48
|
|
49
49
|
# sign with default algorithm, HMAC SHA256
|
50
|
-
jwt = JsonWebToken.
|
50
|
+
jwt = JsonWebToken.sign({foo: 'bar'}, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
|
51
51
|
|
52
52
|
# sign with RSA SHA256 algorithm
|
53
53
|
opts = {
|
@@ -55,14 +55,14 @@ opts = {
|
|
55
55
|
key: < RSA private key >
|
56
56
|
}
|
57
57
|
|
58
|
-
jwt = JsonWebToken.
|
58
|
+
jwt = JsonWebToken.sign({foo: 'bar'}, opts)
|
59
59
|
|
60
60
|
# unsecured token (algorithm is 'none')
|
61
|
-
jwt = JsonWebToken.
|
61
|
+
jwt = JsonWebToken.sign({foo: 'bar'}, alg: 'none')
|
62
62
|
|
63
63
|
```
|
64
64
|
|
65
|
-
### JsonWebToken.
|
65
|
+
### JsonWebToken.verify(jwt, options)
|
66
66
|
|
67
67
|
Returns either:
|
68
68
|
* a JWT claims set string or hash, if the Message Authentication Code (MAC), or signature, is verified
|
@@ -83,7 +83,7 @@ require 'json_web_token'
|
|
83
83
|
secure_jwt_example = 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt.cGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
|
84
84
|
|
85
85
|
# verify with default algorithm, HMAC SHA256
|
86
|
-
claims = JsonWebToken.
|
86
|
+
claims = JsonWebToken.verify(secure_jwt_example, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')
|
87
87
|
|
88
88
|
# verify with RSA SHA256 algorithm
|
89
89
|
opts = {
|
@@ -91,12 +91,12 @@ opts = {
|
|
91
91
|
key: < RSA public key >
|
92
92
|
}
|
93
93
|
|
94
|
-
claims = JsonWebToken.
|
94
|
+
claims = JsonWebToken.verify(jwt, opts)
|
95
95
|
|
96
96
|
# unsecured token (algorithm is 'none')
|
97
97
|
unsecured_jwt_example = 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt.'
|
98
98
|
|
99
|
-
claims = JsonWebToken.
|
99
|
+
claims = JsonWebToken.verify(unsecured_jwt_example, alg: 'none')
|
100
100
|
|
101
101
|
```
|
102
102
|
### Supported encryption algorithms
|
@@ -115,7 +115,7 @@ ES512 | ECDSA using P-521 and SHA-512
|
|
115
115
|
none | No digital signature or MAC performed (unsecured)
|
116
116
|
|
117
117
|
### Supported Ruby Versions
|
118
|
-
Ruby 2.0 and up
|
118
|
+
Ruby 2.0.0 and up
|
119
119
|
|
120
120
|
### Limitations
|
121
121
|
Future implementation may include these features:
|
@@ -141,7 +141,7 @@ Future implementation may include these features:
|
|
141
141
|
|
142
142
|
[travis]: https://travis-ci.org/garyf/json_web_token
|
143
143
|
[ci_img]: https://travis-ci.org/garyf/json_web_token.svg?branch=master
|
144
|
-
[yard_docs]: http://www.rubydoc.info/
|
144
|
+
[yard_docs]: http://www.rubydoc.info/github/garyf/json_web_token
|
145
145
|
[yd_img]: http://img.shields.io/badge/yard-docs-blue.svg
|
146
146
|
[code_climate]: https://codeclimate.com/github/garyf/json_web_token
|
147
147
|
[cc_img]: https://codeclimate.com/github/garyf/json_web_token/badges/gpa.svg
|
data/json_web_token.gemspec
CHANGED
@@ -16,6 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
# optional
|
17
17
|
s.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
|
18
18
|
s.add_development_dependency 'rspec', '~> 3.3'
|
19
|
-
s.description = 'Ruby implementation of the JSON Web Token standard, RFC 7519'
|
19
|
+
s.description = 'Ruby implementation of the JSON Web Token (JWT) standard, RFC 7519'
|
20
20
|
s.required_ruby_version = '>= 2.0.0'
|
21
21
|
end
|
data/lib/json_web_token.rb
CHANGED
@@ -1,14 +1,35 @@
|
|
1
1
|
require 'json_web_token/jwt'
|
2
2
|
|
3
|
+
# Top level interface, or API, to sign and verify a JSON Web Token (JWT)
|
4
|
+
# @see http://tools.ietf.org/html/rfc7519
|
3
5
|
module JsonWebToken
|
4
6
|
|
5
7
|
module_function
|
6
8
|
|
7
|
-
|
9
|
+
# @param claims [Hash] a collection of name/value pairs asserting information about a subject
|
10
|
+
# @param options [Hash] specify the desired signing algorithm and signing key
|
11
|
+
# @return [String] a JSON Web Token, representing digitally signed claims
|
12
|
+
# @example
|
13
|
+
# claims = {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
|
14
|
+
# options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
|
15
|
+
# JsonWebToken.sign(claims, options)
|
16
|
+
# # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
17
|
+
def sign(claims, options)
|
8
18
|
Jwt.sign(claims, options)
|
9
19
|
end
|
10
|
-
|
11
|
-
|
20
|
+
|
21
|
+
# @param jwt [String] a JSON Web Token
|
22
|
+
# @param options [Hash] specify the desired verifying algorithm and verifying key
|
23
|
+
# @return [Hash] a JWT claims set if the jwt verifies, or +error: 'Invalid'+ otherwise
|
24
|
+
# @example
|
25
|
+
# jwt = 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
26
|
+
# options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
|
27
|
+
# JsonWebToken.verify(jwt, options)
|
28
|
+
# # => {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
|
29
|
+
def verify(jwt, options)
|
12
30
|
Jwt.verify(jwt, options)
|
13
31
|
end
|
14
32
|
end
|
33
|
+
|
34
|
+
# alias
|
35
|
+
JWT = JsonWebToken
|
@@ -2,6 +2,12 @@ require 'openssl'
|
|
2
2
|
|
3
3
|
module JsonWebToken
|
4
4
|
module Format
|
5
|
+
# ASN1 data structures are usually encoded using the Distinguished Encoding Rules (DER).
|
6
|
+
# The ASN1 module provides the necessary classes that allow generation of ASN1 data
|
7
|
+
# structures and the methods to encode them using a DER encoding. The decode method allows
|
8
|
+
# parsing arbitrary DER-encoded data to a Ruby object that can then be modified and
|
9
|
+
# re-encoded at will.
|
10
|
+
# @see http://docs.ruby-lang.org/en/2.1.0/OpenSSL/ASN1.html
|
5
11
|
module Asn1
|
6
12
|
|
7
13
|
KEY_BITS = {
|
@@ -12,12 +18,6 @@ module JsonWebToken
|
|
12
18
|
|
13
19
|
module_function
|
14
20
|
|
15
|
-
# ASN1 data structures are usually encoded using the Distinguished Encoding Rules (DER).
|
16
|
-
# The ASN1 module provides the necessary classes that allow generation of ASN1 data
|
17
|
-
# structures and the methods to encode them using a DER encoding. The decode method allows
|
18
|
-
# parsing arbitrary DER-encoded data to a Ruby object that can then be modified and
|
19
|
-
# re-encoded at will. (see http://docs.ruby-lang.org/en/2.1.0/OpenSSL/ASN1.html)
|
20
|
-
|
21
21
|
def der_to_signature(der, sha_bits)
|
22
22
|
signature_pair = OpenSSL::ASN1.decode(der).value
|
23
23
|
width = per_part_byte_count(sha_bits)
|
@@ -33,8 +33,6 @@ module JsonWebToken
|
|
33
33
|
asn1_seq.to_der
|
34
34
|
end
|
35
35
|
|
36
|
-
# private
|
37
|
-
|
38
36
|
def per_part_byte_count(sha_bits)
|
39
37
|
bits = KEY_BITS[sha_bits]
|
40
38
|
bits ? (bits + 7) / 8 : fail('Invalid sha_bits')
|
data/lib/json_web_token/jwt.rb
CHANGED
@@ -4,6 +4,7 @@ module JsonWebToken
|
|
4
4
|
# Encode claims for transmission as a JSON object that is used as the payload of a JSON Web
|
5
5
|
# Signature (JWS) structure, enabling the claims to be integrity protected with a Message
|
6
6
|
# Authentication Code (MAC), to be later verified
|
7
|
+
# @see http://tools.ietf.org/html/rfc7519
|
7
8
|
module Jwt
|
8
9
|
|
9
10
|
ALG_DEFAULT = 'HS256'
|
@@ -19,12 +20,12 @@ module JsonWebToken
|
|
19
20
|
# (e.g String for Hmac | OpenSSL::PKey::RSA | OpenSSL::PKey::EC)
|
20
21
|
# @return [String] a JSON Web Token, representing digitally signed claims
|
21
22
|
# @example
|
22
|
-
# claims = {iss: 'joe', exp: 1300819380, 'http://example.com/is_root' => true}
|
23
|
+
# claims = {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
|
23
24
|
# options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
|
24
25
|
# Jwt.sign(claims, options)
|
25
26
|
# # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
26
27
|
# @see http://tools.ietf.org/html/rfc7519#section-7.1
|
27
|
-
def sign(claims, options
|
28
|
+
def sign(claims, options)
|
28
29
|
message = validated_message(claims)
|
29
30
|
header = config_header(options)
|
30
31
|
return Jws.unsecured_message(header, message) if header[:alg] == 'none'
|
@@ -33,14 +34,14 @@ module JsonWebToken
|
|
33
34
|
|
34
35
|
# @param jwt [String] a JSON Web Token
|
35
36
|
# @param options [Hash] specify the desired verifying algorithm and verifying key
|
36
|
-
# @return [Hash] a JWT claims set if the jwt verifies, or +
|
37
|
+
# @return [Hash] a JWT claims set if the jwt verifies, or +error: 'Invalid'+ otherwise
|
37
38
|
# @example
|
38
39
|
# jwt = 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
39
40
|
# options = {alg: 'HS256', key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'}
|
40
41
|
# Jwt.verify(jwt, options)
|
41
|
-
# # => {iss: 'joe', exp: 1300819380, 'http://example.com/is_root' => true}
|
42
|
+
# # => {iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true}
|
42
43
|
# @see see http://tools.ietf.org/html/rfc7519#section-7.2
|
43
|
-
def verify(jwt, options
|
44
|
+
def verify(jwt, options)
|
44
45
|
alg = options[:alg] || ALG_DEFAULT
|
45
46
|
jws = Jws.verify(jwt, alg, options[:key])
|
46
47
|
jws ? Util.symbolize_keys(decoded_message_json_to_hash jws) : {error: 'invalid'}
|
data/lib/json_web_token/util.rb
CHANGED
@@ -1,22 +1,34 @@
|
|
1
1
|
module JsonWebToken
|
2
|
+
# Utility methods
|
2
3
|
module Util
|
3
4
|
|
4
5
|
module_function
|
5
6
|
|
6
|
-
#
|
7
|
+
# @param a [String]
|
8
|
+
# @param b [String]
|
9
|
+
# @return [Boolean] a predicate that compares two strings for equality in constant-time
|
10
|
+
# to avoid timing attacks
|
11
|
+
# @example
|
12
|
+
# Util.constant_time_compare?("a", "A")
|
13
|
+
# # => false
|
14
|
+
# @see https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-3.2
|
15
|
+
# @see cf. rails activesupport/lib/active_support/security_utils.rb
|
7
16
|
def constant_time_compare?(a, b)
|
8
17
|
return false if a.nil? || b.nil? || a.empty? || b.empty?
|
9
18
|
secure_compare(a, b)
|
10
19
|
end
|
11
20
|
|
12
|
-
#
|
21
|
+
# @param hsh [Hash]
|
22
|
+
# @return [Hash] a new hash with all keys converted to symbols,
|
23
|
+
# as long as they respond to to_sym
|
24
|
+
# @example
|
25
|
+
# Util.symbolize_keys({'a' => 0, 'b' => '2', c: '3'})
|
26
|
+
# # => {a: 0, b: '2', c: '3'}
|
27
|
+
# @see cf. rails activesupport/lib/active_support/core_ext/hash/keys.rb
|
13
28
|
def symbolize_keys(hsh)
|
14
29
|
transform_keys(hsh) { |key| key.to_sym rescue key }
|
15
30
|
end
|
16
31
|
|
17
|
-
# private
|
18
|
-
|
19
|
-
# cf. rails activesupport/lib/active_support/security_utils.rb
|
20
32
|
def secure_compare(a, b)
|
21
33
|
return false unless a.bytesize == b.bytesize
|
22
34
|
l = a.unpack "C#{a.bytesize}"
|
@@ -20,7 +20,7 @@ module JsonWebToken
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'w claims' do
|
23
|
-
let(:claims) { { iss: 'joe', exp: 1300819380, 'http://example.com/is_root'
|
23
|
+
let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
|
24
24
|
context 'w HS256 keys' do
|
25
25
|
let(:signing_key) { 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C' }
|
26
26
|
let(:verifying_key) { signing_key }
|
@@ -118,7 +118,7 @@ module JsonWebToken
|
|
118
118
|
describe 'w default verify alg' do
|
119
119
|
it 'raises' do
|
120
120
|
jwt = Jwt.sign(claims, sign_options)
|
121
|
-
expect { Jwt.verify(jwt) }
|
121
|
+
expect { Jwt.verify(jwt, {alg: nil}) }
|
122
122
|
.to raise_error(RuntimeError, "Algorithm not matching 'alg' header parameter")
|
123
123
|
end
|
124
124
|
end
|
data/spec/json_web_token_spec.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'json_web_token'
|
2
2
|
|
3
3
|
describe JsonWebToken do
|
4
|
-
context '#
|
5
|
-
let(:claims) { {exp: '
|
6
|
-
shared_examples_for 'w #
|
7
|
-
it '
|
8
|
-
jwt = JsonWebToken.
|
9
|
-
expect(JsonWebToken.
|
4
|
+
context '#sign' do
|
5
|
+
let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
|
6
|
+
shared_examples_for 'w #verify' do
|
7
|
+
it 'w a claims set' do
|
8
|
+
jwt = JsonWebToken.sign(claims, sign_options)
|
9
|
+
expect(JsonWebToken.verify jwt, verify_options).to include(claims)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -15,29 +15,38 @@ describe JsonWebToken do
|
|
15
15
|
let(:verifying_key) { signing_key }
|
16
16
|
|
17
17
|
describe 'default alg' do
|
18
|
-
let(:
|
19
|
-
let(:
|
20
|
-
it_behaves_like 'w #
|
18
|
+
let(:sign_options) { {key: signing_key} }
|
19
|
+
let(:verify_options) { {key: verifying_key} }
|
20
|
+
it_behaves_like 'w #verify'
|
21
21
|
end
|
22
22
|
|
23
23
|
context "w 'alg' option" do
|
24
24
|
describe 'HS256' do
|
25
|
-
let(:
|
26
|
-
let(:
|
27
|
-
it_behaves_like 'w #
|
25
|
+
let(:sign_options) { {alg: 'HS256', key: signing_key} }
|
26
|
+
let(:verify_options) { {alg: 'HS256', key: verifying_key} }
|
27
|
+
it_behaves_like 'w #verify'
|
28
28
|
end
|
29
29
|
|
30
30
|
describe "w alg 'none'" do
|
31
|
-
let(:
|
32
|
-
let(:
|
33
|
-
it_behaves_like 'w #
|
31
|
+
let(:sign_options) { {alg: 'none', key: signing_key} }
|
32
|
+
let(:verify_options) { {alg: 'none', key: verifying_key} }
|
33
|
+
it_behaves_like 'w #verify'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe 'w/o key w default header alg' do
|
39
39
|
it 'raises' do
|
40
|
-
expect { JsonWebToken.
|
40
|
+
expect { JsonWebToken.sign(claims, {}) }.to raise_error(RuntimeError, 'Invalid shared key')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'module alias JWT' do
|
46
|
+
describe '#sign' do
|
47
|
+
let(:claims) { { iss: 'joe', exp: 1300819380, :'http://example.com/is_root' => true} }
|
48
|
+
it 'recognized' do
|
49
|
+
expect(JsonWebToken.sign(claims, key: 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C')).to be
|
41
50
|
end
|
42
51
|
end
|
43
52
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_web_token
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gary Fleshman
|
@@ -14,45 +14,45 @@ dependencies:
|
|
14
14
|
name: json
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.8'
|
20
|
-
- -
|
20
|
+
- - '>='
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 1.8.3
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '1.8'
|
30
|
-
- -
|
30
|
+
- - '>='
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.8.3
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rspec
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- -
|
37
|
+
- - ~>
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '3.3'
|
40
40
|
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- -
|
44
|
+
- - ~>
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '3.3'
|
47
|
-
description: Ruby implementation of the JSON Web Token standard, RFC 7519
|
47
|
+
description: Ruby implementation of the JSON Web Token (JWT) standard, RFC 7519
|
48
48
|
email: gfleshman@newforge-tech.com
|
49
49
|
executables: []
|
50
50
|
extensions: []
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
|
-
-
|
54
|
-
-
|
55
|
-
-
|
53
|
+
- .gitignore
|
54
|
+
- .rspec
|
55
|
+
- .travis.yml
|
56
56
|
- CHANGELOG.md
|
57
57
|
- Gemfile
|
58
58
|
- LICENSE
|
@@ -93,12 +93,12 @@ require_paths:
|
|
93
93
|
- lib
|
94
94
|
required_ruby_version: !ruby/object:Gem::Requirement
|
95
95
|
requirements:
|
96
|
-
- -
|
96
|
+
- - '>='
|
97
97
|
- !ruby/object:Gem::Version
|
98
98
|
version: 2.0.0
|
99
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - '>='
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
requirements: []
|