sandal 0.5.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ea79b1b4960ee68f883439155f86e455f840297
4
- data.tar.gz: 88fe766c7e0dd6f42ffe8cc9e362bd4f9d4dcf1c
3
+ metadata.gz: e87dc3dc16b78944fbce50e48565012d79f087f6
4
+ data.tar.gz: 59b76ed79701856db73f2967da1818063fa58400
5
5
  SHA512:
6
- metadata.gz: 8caf814bd10d413690942fde42d319a9b1d65afcef90c3ebf19f27f35b731e2d48c4d4225fb0700a60c9841c98ea46a6e34c610b40d93cf5584c605b6144621a
7
- data.tar.gz: 978832491980e5e85b83bdac17e4c615cddc01594600785db0e7b7a621d459b7955003ab0352dac65ba803ded8890780cb609895528a6f35f60e107938dc8be6
6
+ metadata.gz: 2ebe5600b88a9026de7b5056b0d26832f259adb47556a5cbe7eb51d07e6ec9eddc08ae289769ce260bf053d424521cb21c4cd394c273bf11d084fab7c2122b3d
7
+ data.tar.gz: 78a7d2f1a4a13330719adb344534882ee8652dcf26ad3966c3f9532a61682daaddcc409fee36d7e5f008d1c0f5f4b2a9defc2ec9fff44a4f685b65d3c3633c8c
@@ -13,7 +13,6 @@ require "sandal/util"
13
13
  #
14
14
  # Currently supports draft-07 of the JWT spec, and draft-10 of the JWS and JWE specs.
15
15
  module Sandal
16
- extend Sandal::Util
17
16
 
18
17
  # The base error for all errors raised by this library.
19
18
  class Error < StandardError; end
@@ -112,9 +111,9 @@ module Sandal
112
111
 
113
112
  payload = MultiJson.dump(payload) unless payload.is_a?(String)
114
113
 
115
- sec_input = [header, payload].map { |p| jwt_base64_encode(p) }.join(".")
114
+ sec_input = [header, payload].map { |p| Sandal::Util.jwt_base64_encode(p) }.join(".")
116
115
  signature = signer.sign(sec_input)
117
- [sec_input, jwt_base64_encode(signature)].join(".")
116
+ [sec_input, Sandal::Util.jwt_base64_encode(signature)].join(".")
118
117
  end
119
118
 
120
119
  # Creates an encrypted JSON Web Token.
@@ -206,7 +205,7 @@ module Sandal
206
205
 
207
206
  # Decodes the parts of a token.
208
207
  def self.decode_token_parts(parts)
209
- parts = parts.map { |part| jwt_base64_decode(part) }
208
+ parts = parts.map { |part| Sandal::Util.jwt_base64_decode(part) }
210
209
  parts[0] = MultiJson.load(parts[0])
211
210
  parts
212
211
  rescue
@@ -12,7 +12,7 @@ module Sandal
12
12
  def self.token_parts(token)
13
13
  parts = token.is_a?(Array) ? token : token.split(".")
14
14
  raise ArgumentError unless parts.length == 5
15
- decoded_parts = parts.map { |part| jwt_base64_decode(part) }
15
+ decoded_parts = parts.map { |part| Sandal::Util.jwt_base64_decode(part) }
16
16
  return parts, decoded_parts
17
17
  rescue ArgumentError
18
18
  raise Sandal::InvalidTokenError, "Invalid token encoding."
@@ -6,7 +6,6 @@ module Sandal
6
6
 
7
7
  # Base implementation of the A*CBC-HS* family of encryption methods.
8
8
  class ACBC_HS
9
- include Sandal::Util
10
9
 
11
10
  # The JWA name of the encryption method.
12
11
  attr_reader :name
@@ -44,13 +43,13 @@ module Sandal
44
43
  cipher.iv = iv = SecureRandom.random_bytes(16)
45
44
  ciphertext = cipher.update(payload) + cipher.final
46
45
 
47
- auth_data = jwt_base64_encode(header)
46
+ auth_data = Sandal::Util.jwt_base64_encode(header)
48
47
  auth_data_length = [auth_data.length * 8].pack("Q>")
49
48
  mac_input = [auth_data, iv, ciphertext, auth_data_length].join
50
49
  mac = OpenSSL::HMAC.digest(@digest, mac_key, mac_input)
51
50
  auth_tag = mac[0...(mac.length / 2)]
52
51
 
53
- remainder = [encrypted_key, iv, ciphertext, auth_tag].map { |part| jwt_base64_encode(part) }
52
+ remainder = [encrypted_key, iv, ciphertext, auth_tag].map { |part| Sandal::Util.jwt_base64_encode(part) }
54
53
  [auth_data, *remainder].join(".")
55
54
  end
56
55
 
@@ -6,7 +6,6 @@ module Sandal
6
6
 
7
7
  # Base implementation of the A*GCM family of encryption methods.
8
8
  class AGCM
9
- include Sandal::Util
10
9
 
11
10
  @@iv_size = 96
12
11
  @@auth_tag_size = 128
@@ -41,12 +40,12 @@ module Sandal
41
40
  cipher.key = key
42
41
  cipher.iv = iv = SecureRandom.random_bytes(@@iv_size / 8)
43
42
 
44
- auth_data = jwt_base64_encode(header)
43
+ auth_data = Sandal::Util.jwt_base64_encode(header)
45
44
  cipher.auth_data = auth_data
46
45
 
47
46
  ciphertext = cipher.update(payload) + cipher.final
48
47
  remaining_parts = [encrypted_key, iv, ciphertext, cipher.auth_tag(@@auth_tag_size / 8)]
49
- remaining_parts.map! { |part| jwt_base64_encode(part) }
48
+ remaining_parts.map! { |part| Sandal::Util.jwt_base64_encode(part) }
50
49
  [auth_data, *remaining_parts].join(".")
51
50
  end
52
51
 
@@ -5,7 +5,6 @@ module Sandal
5
5
 
6
6
  # Base implementation of the HMAC-SHA family of signature algorithms.
7
7
  class HS
8
- include Sandal::Util
9
8
 
10
9
  # The JWA name of the algorithm.
11
10
  attr_reader :name
@@ -36,7 +35,7 @@ module Sandal
36
35
  # @param payload [String] The payload of the token.
37
36
  # @return [Boolean] true if the signature is correct; otherwise false.
38
37
  def valid?(signature, payload)
39
- jwt_strings_equal?(sign(payload), signature)
38
+ Sandal::Util.jwt_strings_equal?(sign(payload), signature)
40
39
  end
41
40
 
42
41
  end
@@ -5,8 +5,6 @@ module Sandal
5
5
  # Implements some JWT utility functions. Shouldn't be needed by most people
6
6
  # but may be useful if you're developing an extension to the library.
7
7
  module Util
8
-
9
- private
10
8
 
11
9
  # A string equality function that compares Unicode codepoints, and also
12
10
  # doesn't short-circuit the equality check to help protect against timing
@@ -19,7 +17,7 @@ module Sandal
19
17
  # @param a [String] The first string.
20
18
  # @param b [String] The second string.
21
19
  # @return [Boolean] true if the strings are equal; otherwise false.
22
- def jwt_strings_equal?(a, b)
20
+ def self.jwt_strings_equal?(a, b)
23
21
  return true if a.object_id == b.object_id
24
22
  return false if a.nil? || b.nil? || a.length != b.length
25
23
  a.codepoints.zip(b.codepoints).reduce(0) { |r, (x, y)| r |= x ^ y } == 0
@@ -29,7 +27,7 @@ module Sandal
29
27
  #
30
28
  # @param s [String] The string to encode.
31
29
  # @return [String] The encoded base64 string.
32
- def jwt_base64_encode(s)
30
+ def self.jwt_base64_encode(s)
33
31
  Base64.urlsafe_encode64(s).gsub(/=+$/, "")
34
32
  end
35
33
 
@@ -38,7 +36,7 @@ module Sandal
38
36
  # @param s [String] The base64 string to decode.
39
37
  # @return [String] The decoded string.
40
38
  # @raise [ArgumentError] The base64 string is invalid or contains padding.
41
- def jwt_base64_decode(s)
39
+ def self.jwt_base64_decode(s)
42
40
  if s.end_with?("=")
43
41
  raise ArgumentError, "Base64 strings must not contain padding."
44
42
  end
@@ -1,4 +1,4 @@
1
1
  module Sandal
2
2
  # The semantic version of the library.
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
4
4
  end
@@ -1,33 +1,33 @@
1
1
  ($LOAD_PATH << File.expand_path("../lib", __FILE__)).uniq!
2
- require 'sandal/version'
2
+ require "sandal/version"
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = 'sandal'
5
+ s.name = "sandal"
6
6
  s.version = Sandal::VERSION
7
- s.summary = 'A JSON Web Token (JWT) library.'
8
- s.description = 'A ruby library for creating and reading JSON Web Tokens (JWT), supporting JSON Web Signatures (JWS) and JSON Web Encryption (JWE).'
9
- s.author = 'Greg Beech'
10
- s.email = 'greg@gregbeech.com'
11
- s.homepage = 'http://rubygems.org/gems/sandal'
12
- s.license = 'MIT'
7
+ s.summary = "A JSON Web Token (JWT) library."
8
+ s.description = "A ruby library for creating and reading JSON Web Tokens (JWT), supporting JSON Web Signatures (JWS) and JSON Web Encryption (JWE)."
9
+ s.author = "Greg Beech"
10
+ s.email = "greg@gregbeech.com"
11
+ s.homepage = "http://rubygems.org/gems/sandal"
12
+ s.license = "MIT"
13
13
 
14
14
  s.files = `git ls-files`.split($/)
15
15
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
16
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
- s.require_paths = ['lib']
18
- s.extra_rdoc_files = ['README.md', 'LICENSE.md']
17
+ s.require_paths = ["lib"]
18
+ s.extra_rdoc_files = ["README.md", "LICENSE.md", "CHANGELOG.md"]
19
19
 
20
- s.add_runtime_dependency 'multi_json', '~> 1.7'
21
- s.add_runtime_dependency 'jruby-openssl', '~> 0.7', '>= 0.7.3' if RUBY_PLATFORM == 'java'
20
+ s.add_runtime_dependency "multi_json", "~> 1.7"
21
+ s.add_runtime_dependency "jruby-openssl", "~> 0.7", ">= 0.7.3" if RUBY_PLATFORM == "java"
22
22
 
23
- s.add_development_dependency 'bundler', '>= 1.3'
24
- s.add_development_dependency 'rake', '>= 10.0'
25
- s.add_development_dependency 'rspec', '>= 2.13'
26
- s.add_development_dependency 'simplecov', '>= 0.7'
27
- s.add_development_dependency 'coveralls', '>= 0.6'
28
- s.add_development_dependency 'yard', '>= 0.8'
29
- s.add_development_dependency 'redcarpet', '>= 2.2' unless RUBY_PLATFORM == 'java' # for yard
30
- s.add_development_dependency 'kramdown', '>= 1.0' if RUBY_PLATFORM == 'java' # for yard
23
+ s.add_development_dependency "bundler", ">= 1.3"
24
+ s.add_development_dependency "rake", ">= 10.0"
25
+ s.add_development_dependency "rspec", ">= 2.13"
26
+ s.add_development_dependency "simplecov", ">= 0.7"
27
+ s.add_development_dependency "coveralls", ">= 0.6"
28
+ s.add_development_dependency "yard", ">= 0.8"
29
+ s.add_development_dependency "redcarpet", ">= 2.2" unless RUBY_PLATFORM == "java" # for yard
30
+ s.add_development_dependency "kramdown", ">= 1.0" if RUBY_PLATFORM == "java" # for yard
31
31
 
32
- s.requirements << 'openssl 1.0.1c for EC signature methods'
32
+ s.requirements << "openssl 1.0.1c for EC signature methods"
33
33
  end
@@ -1,8 +1,6 @@
1
1
  require "helper"
2
2
  require "openssl"
3
3
 
4
- include Sandal::Util
5
-
6
4
  shared_examples "encryption and decryption" do |enc_class|
7
5
 
8
6
  it "can encrypt and decrypt a content master key" do
@@ -1,8 +1,6 @@
1
1
  require "helper"
2
2
  require "openssl"
3
3
 
4
- include Sandal::Util
5
-
6
4
  # EC isn't implemented in jruby-openssl at the moment
7
5
  if defined? Sandal::Sig::ES
8
6
 
@@ -111,7 +109,7 @@ describe Sandal::Sig::ES do
111
109
  r = make_bn([14, 209, 33, 83, 121, 99, 108, 72, 60, 47, 127, 21, 88, 7, 212, 2, 163, 178, 40, 3, 58, 249, 124, 126, 23, 129, 154, 195, 22, 158, 166, 101])
112
110
  s = make_bn([197, 10, 7, 211, 140, 60, 112, 229, 216, 241, 45, 175, 8, 74, 84, 128, 166, 101, 144, 197, 242, 147, 80, 154, 143, 63, 127, 138, 131, 163, 84, 213])
113
111
  signature = Sandal::Sig::ES.encode_jws_signature(r, s, 256)
114
- base64_signature = jwt_base64_encode(signature)
112
+ base64_signature = Sandal::Util.jwt_base64_encode(signature)
115
113
  base64_signature.should == "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
116
114
  end
117
115
 
@@ -119,7 +117,7 @@ describe Sandal::Sig::ES do
119
117
  r = make_bn([1, 220, 12, 129, 231, 171, 194, 209, 232, 135, 233, 117, 247, 105, 122, 210, 26, 125, 192, 1, 217, 21, 82, 91, 45, 240, 255, 83, 19, 34, 239, 71, 48, 157, 147, 152, 105, 18, 53, 108, 163, 214, 68, 231, 62, 153, 150, 106, 194, 164, 246, 72, 143, 138, 24, 50, 129, 223, 133, 206, 209, 172, 63, 237, 119, 109])
120
118
  s = make_bn([0, 111, 6, 105, 44, 5, 41, 208, 128, 61, 152, 40, 92, 61, 152, 4, 150, 66, 60, 69, 247, 196, 170, 81, 193, 199, 78, 59, 194, 169, 16, 124, 9, 143, 42, 142, 131, 48, 206, 238, 34, 175, 83, 203, 220, 159, 3, 107, 155, 22, 27, 73, 111, 68, 68, 21, 238, 144, 229, 232, 148, 188, 222, 59, 242, 103])
121
119
  signature = Sandal::Sig::ES.encode_jws_signature(r, s, 521)
122
- base64_signature = jwt_base64_encode(signature)
120
+ base64_signature = Sandal::Util.jwt_base64_encode(signature)
123
121
  base64_signature.should == "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn"
124
122
  end
125
123
 
@@ -144,7 +142,7 @@ describe Sandal::Sig::ES256 do
144
142
  y = make_bn([199, 241, 68, 205, 27, 189, 155, 126, 135, 44, 223, 237, 185, 238, 185, 244, 179, 105, 93, 110, 169, 11, 36, 173, 138, 70, 35, 40, 133, 136, 229, 173])
145
143
  d = make_bn([142, 155, 16, 158, 113, 144, 152, 191, 152, 4, 135, 223, 31, 93, 119, 233, 203, 41, 96, 110, 190, 210, 38, 59, 95, 87, 194, 19, 223, 132, 244, 178])
146
144
  data = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
147
- signature = jwt_base64_decode("DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q")
145
+ signature = Sandal::Util.jwt_base64_decode("DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q")
148
146
 
149
147
  group = OpenSSL::PKey::EC::Group.new("prime256v1")
150
148
  public_key = OpenSSL::PKey::EC.new(group)
@@ -186,7 +184,7 @@ describe Sandal::Sig::ES512 do
186
184
  y = make_bn([0, 52, 166, 68, 14, 55, 103, 80, 210, 55, 31, 209, 189, 194, 200, 243, 183, 29, 47, 78, 229, 234, 52, 50, 200, 21, 204, 163, 21, 96, 254, 93, 147, 135, 236, 119, 75, 85, 131, 134, 48, 229, 203, 191, 90, 140, 190, 10, 145, 221, 0, 100, 198, 153, 154, 31, 110, 110, 103, 250, 221, 237, 228, 200, 200, 246])
187
185
  d = make_bn([1, 142, 105, 111, 176, 52, 80, 88, 129, 221, 17, 11, 72, 62, 184, 125, 50, 206, 73, 95, 227, 107, 55, 69, 237, 242, 216, 202, 228, 240, 242, 83, 159, 70, 21, 160, 233, 142, 171, 82, 179, 192, 197, 234, 196, 206, 7, 81, 133, 168, 231, 187, 71, 222, 172, 29, 29, 231, 123, 204, 246, 97, 53, 230, 61, 130] )
188
186
  data = "eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA"
189
- signature = jwt_base64_decode("AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn")
187
+ signature = Sandal::Util.jwt_base64_decode("AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn")
190
188
 
191
189
  group = OpenSSL::PKey::EC::Group.new("secp521r1")
192
190
  public_key = OpenSSL::PKey::EC.new(group)
@@ -2,24 +2,22 @@ require 'helper'
2
2
  require 'openssl'
3
3
  require 'benchmark'
4
4
 
5
- include Sandal::Util
6
-
7
5
  describe Sandal::Util do
8
6
 
9
7
  context '#jwt_base64_decode' do
10
8
 
11
9
  it 'decodes base64 as per JWT example 6.1' do
12
10
  encoded = 'eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ'
13
- val = jwt_base64_decode(encoded)
11
+ val = Sandal::Util.jwt_base64_decode(encoded)
14
12
  val.should == %!{"iss":"joe",\r\n "exp":1300819380,\r\n "http://example.com/is_root":true}!
15
13
  end
16
14
 
17
15
  it 'raises an ArgumentError if base64 strings contain padding' do
18
- expect { jwt_base64_decode('eyJpc3MiOiJq=') }.to raise_error ArgumentError
16
+ expect { Sandal::Util.jwt_base64_decode('eyJpc3MiOiJq=') }.to raise_error ArgumentError
19
17
  end
20
18
 
21
19
  it 'raises an ArgumentError if base64 strings are invalid' do
22
- expect { jwt_base64_decode('not valid base64') }.to raise_error ArgumentError
20
+ expect { Sandal::Util.jwt_base64_decode('not valid base64') }.to raise_error ArgumentError
23
21
  end
24
22
 
25
23
  end
@@ -28,7 +26,7 @@ describe Sandal::Util do
28
26
 
29
27
  it 'encodes base64 as per JWT example 6.1' do
30
28
  src = %!{"iss":"joe",\r\n "exp":1300819380,\r\n "http://example.com/is_root":true}!
31
- encoded = jwt_base64_encode(src)
29
+ encoded = Sandal::Util.jwt_base64_encode(src)
32
30
  encoded.should == 'eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ'
33
31
  end
34
32
 
@@ -37,31 +35,31 @@ describe Sandal::Util do
37
35
  context '#jwt_strings_equal?' do
38
36
 
39
37
  it 'compares nil strings as equal' do
40
- jwt_strings_equal?(nil, nil).should == true
38
+ Sandal::Util.jwt_strings_equal?(nil, nil).should == true
41
39
  end
42
40
 
43
41
  it 'compares empty strings as equal' do
44
- jwt_strings_equal?('', '').should == true
42
+ Sandal::Util.jwt_strings_equal?('', '').should == true
45
43
  end
46
44
 
47
45
  it 'compares nil strings as unequal to empty strings' do
48
- jwt_strings_equal?(nil, '').should == false
49
- jwt_strings_equal?('', nil).should == false
46
+ Sandal::Util.jwt_strings_equal?(nil, '').should == false
47
+ Sandal::Util.jwt_strings_equal?('', nil).should == false
50
48
  end
51
49
 
52
50
  it 'compares equal strings as equal' do
53
- jwt_strings_equal?('hello', 'hello').should == true
54
- jwt_strings_equal?('a longer string', 'a longer string').should == true
51
+ Sandal::Util.jwt_strings_equal?('hello', 'hello').should == true
52
+ Sandal::Util.jwt_strings_equal?('a longer string', 'a longer string').should == true
55
53
  end
56
54
 
57
55
  it 'compares unequal strings as unequal' do
58
- jwt_strings_equal?('hello', 'world').should == false
59
- jwt_strings_equal?('a longer string', 'a different longer string').should == false
56
+ Sandal::Util.jwt_strings_equal?('hello', 'world').should == false
57
+ Sandal::Util.jwt_strings_equal?('a longer string', 'a different longer string').should == false
60
58
  end
61
59
 
62
60
  it 'compares strings without short-circuiting', :timing_dependent do
63
61
  measure_equals = -> a, b do
64
- Benchmark.realtime { 100.times { jwt_strings_equal?(a, b) } }
62
+ Benchmark.realtime { 100.times { Sandal::Util.jwt_strings_equal?(a, b) } }
65
63
  end
66
64
  ref = 'a' * 10000
67
65
  cmp1 = ('a' * 9999) + 'b'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sandal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Beech
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-07 00:00:00.000000000 Z
11
+ date: 2013-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -130,6 +130,7 @@ extensions: []
130
130
  extra_rdoc_files:
131
131
  - README.md
132
132
  - LICENSE.md
133
+ - CHANGELOG.md
133
134
  files:
134
135
  - .coveralls.yml
135
136
  - .gitignore