rack-session-smart_cookie 0.1.0

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: 4610e81040f4a6f234cc5365aca0fd89660e7985
4
+ data.tar.gz: 2d64b237c171b63c1b5791e9f1bf0e904c319e75
5
+ SHA512:
6
+ metadata.gz: 5209a33d1cc7b7dbf542b0f3a0f016912877118208a4cc610533308521c62c572660490bee9d535e9e803c12935541dabe55b1be6b05dc23dc644741a3beef60
7
+ data.tar.gz: a80d1588a48494bef580385a852df4636b88377b3e9ee1d3ba11e40bc50b3922fe510741cb603f058b1d84270baf2c22816eb50237acc1cb1bd83d556a158de3
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - ruby-head
5
+ - 2.4.2
6
+ - 2.3.5
7
+ - 2.2.8
8
+ - jruby-head
9
+ - jruby-9.1.13.0
10
+ - jruby-9.0.5.0
11
+ env:
12
+ - RACK_VERSION='~> 2.0.0'
13
+ before_install: gem install bundler -v 1.15.4
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: ruby-head
17
+ - rvm: jruby-head
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gemspec
6
+
7
+ #gem 'openssl', '>= 2.0.3'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Mike Pastore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Rack::Session::SmartCookie
2
+
3
+ The version of Rack::Session::Cookie that ships with Rack 2 has the following
4
+ limitations:
5
+
6
+ * Insecure SHA1 (HMAC-SHA1) by default
7
+ * Slow and/or bloated JSON, ZipJSON, or Marshal encoding out of the box
8
+ * JSON encodings do not preserve Symbols
9
+ * Digest is double-encoded and bloated (hexdigest of a base64)
10
+ * Base64-encoded strings contain unecessary padding and characters that need to
11
+ be escaped (e.g. `/` becomes `%2F`), wasting precious cookie bytes
12
+ * It has some bugs in the size check that may lead to truncated cookies, token
13
+ leakage, and/or cross-site request forgery
14
+
15
+ Of course, none of these are true show-stoppers, and the worst can be worked
16
+ around by passing e.g. `:hmac` and `:coder` to the initializer. But we are nice
17
+ people and we deserve nice things. This gem provides a minor derivative of
18
+ Rack::Session::Cookie with the following improvements:
19
+
20
+ * Secure SHA2 (HMAC-SHA-256) by default
21
+ * Compact binary serialization format (currently [MessagePack][3] but will
22
+ likely change to [CBOR][4] in the future) out of the box
23
+ * Symbols are preserved with the default `:coder`
24
+ * Digest is single-encoded and compact (base64 of a digest)
25
+ * Base64-encoded strings are not padded and conform to URL-encoded form data
26
+ (e.g. `/` becomes `_`)
27
+ * It does not perform a size check (use [Rack::Protection::MaximumCookie][2]
28
+ if you care about cookie limits)
29
+
30
+ The resultant cookies values with a small-to-medium sized session can be up to
31
+ 30% smaller in an apples-to-apples comparison (see below for examples).
32
+
33
+ ### Strategy
34
+
35
+ The main distinguishing feature of this cf. the stock implementation is that
36
+ the encoding (and decoding) step has been separated into two stages: 1. binary
37
+ serialization and 2. stringification, instead of being combined into a single
38
+ "coder" class. This allows the various cookie components to be either both
39
+ serialized and stringified (in the case of the session payload) or merely
40
+ stringified (in the case of the digest).
41
+
42
+ The other key realization is that the method Rack uses to escape cookie data
43
+ ([URI.encode_www_form_component][5]) will only ever allow URL-safe Base64 plus
44
+ period (`.`) and asterisk (`*`), so there's no sense in using any
45
+ stringification scheme other than URL-safe Base64! It doesn't need to be
46
+ configurable. The serializer remains configurable as the `:coder`.
47
+
48
+ The remaining differences are mostly just better defaults: MessagePack and
49
+ SHA2.
50
+
51
+ ## Installation
52
+
53
+ Add this line to your application's Gemfile:
54
+
55
+ ```ruby
56
+ gem 'rack-session-smart_cookie'
57
+ ```
58
+
59
+ And then execute:
60
+
61
+ ```console
62
+ $ bundle
63
+ ```
64
+
65
+ Or install it yourself as:
66
+
67
+ ```console
68
+ $ gem install rack-session-smart_cookie
69
+ ```
70
+
71
+ ## Usage
72
+
73
+ ```ruby
74
+ use Rack::Session::SmartCookie
75
+ ```
76
+
77
+ Rack::Session::SmartCookie accepts the same options as
78
+ [Rack::Session::Cookie][6]. If you choose to override the default `:coder`, it
79
+ should *not* perform the Base64 steps.
80
+
81
+ You can easily register additional custom types on the default coder's factory:
82
+
83
+ ```ruby
84
+ my_coder = Rack::Session::SmartCookie::MessagePack.new
85
+ my_coder.factory.register_type(0x00, MyCustomType) # 0x60..0xFF are reserved
86
+
87
+ use Rack::Session::SmartCookie, :coder=>my_coder
88
+ ```
89
+
90
+ ## Comparisons
91
+
92
+ For general size and performance benchmarks of the encoding schemes, see
93
+ [here][1]. Unfortunately, the post is slightly out-of-date and doesn't include
94
+ ZipJSON (Zlib+JSON) results. However, I was able to run the benchmarks locally
95
+ and add ZipJSON. Although it comes in second-most compact at 289 bytes (cf.
96
+ protocol buffers and MessagePack at 204 and 373 bytes, respectively), it was
97
+ 97% slower to encode and 91% slower to decode cf. MessagePack.
98
+
99
+ I put this mock session payload through the following configurations with SHA2
100
+ and 128 sidbits and here are the results:
101
+
102
+ ```ruby
103
+ {
104
+ :user_id=>514,
105
+ :roles=>[:user, :moderator, :mailbox],
106
+ :data=>'{"foo":"bar","qux":21}',
107
+ :issued_at=>Time.now.to_f,
108
+ :valid_for=>30*24*3_600
109
+ }
110
+ ```
111
+
112
+ ### Rack::Session::Cookie w/ Base64::Marshal
113
+
114
+ ```
115
+ BAh7C0kiD3Nlc3Npb25faWQGOgZFVEkiRTg3MzJkMTEzNDQyZjQyM2FlZGUy%0AMTdmNDY0OWEyOTk5
116
+ MjkyYzg2M2JkNTFlY2VjYjY2ZDAzMTg0MTYzZWE3YTcG%0AOwBGSSIMdXNlcl9pZAY7AEZpAgICSSIK
117
+ cm9sZXMGOwBGWwg6CXVzZXI6Dm1v%0AZGVyYXRvcjoMbWFpbGJveEkiCWRhdGEGOwBGSSIbeyJmb28i
118
+ OiJiYXIiLCJx%0AdXgiOjIxfQY7AFRJIg5pc3N1ZWRfYXQGOwBGZhYxNTA5MjAzMDIzLjI3MzE2%0AN
119
+ UkiDnZhbGlkX2ZvcgY7AEZpAwCNJw%3D%3D%0A--15aebb42ba0ff0a28436556c64eb2ef6d4dc7c6
120
+ a39e164eac0889052cec4f83f
121
+ ```
122
+
123
+ Size: 420 bytes (100%)
124
+
125
+ Note the percent-encoded characters and hex-encoded digest here and in the
126
+ other Rack::Session::Cookie results.
127
+
128
+ ### Rack::Session::Cookie w/ Base64::JSON
129
+
130
+ ```
131
+ eyJzZXNzaW9uX2lkIjoiMTA4YzM1ZGIxMTFkNWZlMjk5NzUwMTc1Mzc2MzVm%0AMDJlZTIxMjM4ZmIx
132
+ OTg2NDQ0ZTc4MTliY2RjZGQyYjc2YSIsInVzZXJfaWQi%0AOjUxNCwicm9sZXMiOlsidXNlciIsIm1v
133
+ ZGVyYXRvciIsIm1haWxib3giXSwi%0AZGF0YSI6IntcImZvb1wiOlwiYmFyXCIsXCJxdXhcIjoyMX0i
134
+ LCJpc3N1ZWRf%0AYXQiOjE1MDkyMDI5NzEuODk3MzUyLCJ2YWxpZF9mb3IiOjI1OTIwMDB9%0A--7a6
135
+ 000bdece71118e768ccffedc645ace865b829536e335c304c00bb9050c625
136
+ ```
137
+
138
+ Size: 377 bytes (90%)
139
+
140
+ ### Rack::Session::Cookie w/ Base64::ZipJSON
141
+
142
+ ```
143
+ eJwdjeGKwyAQhN9lf8uxGrcaX%2BU8wqa7gpCeXEyOQum7V%2FJvZj5m5gVde6%2Ft%0Ad6kCCcok1h
144
+ bvwnqfJLpJ2VkpIXrxSmQZ76uzBb0qzYokSPY2E8aAXDQSg4Gz%0A636NkfUG9rZph%2FR9xYM%2Bmu
145
+ jOR7s0121tT%2FgxIHzwuH9lKK1lSBlW3jOYDH%2Fn%0Ac3hn36NQez9VFj4gWcLZoZsxfN1ioCkY%2
146
+ BOetylLGdHI0IOL7A%2BnjQaI%3D%0A--fc193337b2900b6ce893143b5a52d36b55fafebc21cbde
147
+ 83712dce56bbf836f4
148
+ ```
149
+
150
+ Size: 334 bytes (80%)
151
+
152
+ ### Rack::Session::SmartCookie w/ MessagePack
153
+
154
+ ```
155
+ hqpzZXNzaW9uX2lk2UBiMGEzYzhlZTE4NzY3YjcwOTNmNThhN2E4MTI4NTNmNTlmNDYwOTgwMDA5NGY
156
+ 1Y2E4MTg5MjFjMjA4ZWQ1ZDY3p3VzZXJfaWTNAgKlcm9sZXOT1gB1c2VyxwkAbW9kZXJhdG9yxwcAbW
157
+ FpbGJveKRkYXRhtnsiZm9vIjoiYmFyIiwicXV4IjoyMX2paXNzdWVkX2F0y0HWfSbUfbp0qXZhbGlkX
158
+ 2Zvcs4AJ40A.CRGTAgpN19Iz1plyX14kHmQYWTe0OtFbetqKZmCvSfg
159
+ ```
160
+
161
+ Size: 292 bytes (70%)
162
+
163
+ ## Development
164
+
165
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
166
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
167
+ prompt that will allow you to experiment.
168
+
169
+ To install this gem onto your local machine, run `bundle exec rake install`. To
170
+ release a new version, update the version number in `version.rb`, and then run
171
+ `bundle exec rake release`, which will create a git tag for the version, push
172
+ git commits and tags, and push the `.gem` file to
173
+ [rubygems.org](https://rubygems.org).
174
+
175
+ ## Contributing
176
+
177
+ Bug reports and pull requests are welcome on GitHub at
178
+ https://github.com/mwpastore/rack-session-smart_cookie.
179
+
180
+ ## License
181
+
182
+ The gem is available as open source under the terms of the [MIT
183
+ License](http://opensource.org/licenses/MIT).
184
+
185
+ [1]: https://gist.github.com/eirc/1300627
186
+ [2]: https://github.com/mwpastore/rack-protection-maximum_cookie
187
+ [3]: https://msgpack.org
188
+ [4]: http://cbor.io
189
+ [5]: https://ruby-doc.org/stdlib-2.4.2/libdoc/uri/rdoc/URI.html#method-c-encode_www_form_component
190
+ [6]: http://www.rubydoc.info/gems/rack/Rack/Session/Cookie
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default=>:test
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'irb'
5
+ require 'rack/session/smart_cookie'
6
+
7
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require 'rack/session/smart_cookie'
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+ require 'rack/session/smart_cookie/version'
3
+
4
+ require 'base64'
5
+ require 'msgpack'
6
+ require 'openssl'
7
+ require 'rack/session/cookie'
8
+
9
+ module Rack
10
+ module Session
11
+ class SmartCookie < Cookie
12
+ BAD_DIGESTS = %w[MD2 MD4 MD5 SHA SHA1].freeze
13
+ DEFAULT_DIGEST = 'SHA256'
14
+ SECRET_MIN_BYTESIZE = 16
15
+
16
+ class Base64
17
+ if ::Base64.respond_to?(:urlsafe_encode64) && ::Base64.method(:urlsafe_encode64).arity.abs >= 2
18
+ def self.encode(data)
19
+ ::Base64.urlsafe_encode64(data, :padding=>false)
20
+ end
21
+
22
+ def self.decode(str)
23
+ return unless str
24
+
25
+ ::Base64.urlsafe_decode64(str)
26
+ rescue
27
+ end
28
+ else
29
+ def self.encode(data)
30
+ ::Base64.urlsafe_encode64(data).tap { |str| str.sub!(/=*\z/, '') }
31
+ end
32
+
33
+ def self.decode(str)
34
+ return unless str
35
+
36
+ num_pad_chars =
37
+ case str.bytesize % 4
38
+ when 0 then 0
39
+ when 2 then 2
40
+ when 3 then 1
41
+ else
42
+ fail 'Invalid Base64-encoded string!'
43
+ end
44
+
45
+ ::Base64.urlsafe_decode64(str + '=' * num_pad_chars)
46
+ rescue
47
+ end
48
+ end
49
+ end
50
+
51
+ class MessagePack
52
+ attr_reader :factory
53
+
54
+ def initialize
55
+ # Create our own factory so we don't pollute the global namespace
56
+ # with our custom type.
57
+ @factory = ::MessagePack::Factory.new
58
+ # user gets 0x00...0x60
59
+ # we get 0x60...0x80
60
+ # MessagePack gets 0x80..0xFF
61
+ @factory.register_type(0x60, Symbol)
62
+ end
63
+
64
+ def encode(data)
65
+ # https://github.com/msgpack/msgpack-ruby/issues/141
66
+ factory.packer.write(data).to_str
67
+ end
68
+
69
+ def decode(bin)
70
+ return unless bin
71
+
72
+ # https://github.com/msgpack/msgpack-ruby/issues/141
73
+ factory.unpacker.feed(bin).read
74
+ rescue
75
+ end
76
+ end
77
+
78
+ def initialize(app, options={})
79
+ options[:coder] ||= MessagePack.new
80
+ options[:hmac] = OpenSSL::Digest.const_get(DEFAULT_DIGEST) unless options.key?(:hmac)
81
+
82
+ super
83
+
84
+ if @secrets.any?
85
+ hmac = options[:hmac].new
86
+
87
+ warn <<-MSG if BAD_DIGESTS.include?(hmac.name)
88
+ SECURITY WARNING: You have elected to use an old and insecure message
89
+ digest algorithm (#{hmac.class}).
90
+
91
+ Such algorithms are generally considered to be effectively broken. It
92
+ is strongly recommended that you elect to use a message digest algorithm
93
+ from the SHA2 family: SHA224, SHA256, SHA384, or SHA512, or one of the
94
+ derivatives such as SHA512/256. This will help prevent exploits that
95
+ may be possible from crafted cookies.
96
+
97
+ Called from: #{caller[0]}.
98
+ MSG
99
+
100
+ unless (SECRET_MIN_BYTESIZE..hmac.block_length).cover?(@secrets.first.bytesize)
101
+ show_caveat = hmac.digest_length > SECRET_MIN_BYTESIZE
102
+
103
+ message = String.new(<<-MSG)
104
+ SECURITY WARNING: You have provided a session secret with a sub-optimal
105
+ byte size.
106
+
107
+ It is strongly recommended that you select a secret at least #{SECRET_MIN_BYTESIZE} bytes
108
+ long#{'*' if show_caveat}, but not longer than the block size (#{hmac.block_length} bytes) of the selected
109
+ message digest algorithm (#{hmac.class}). This will help
110
+ prevent exploits that may be possible from crafted cookies.
111
+ MSG
112
+
113
+ message << "\n " \
114
+ "* - Ideally, at least #{hmac.digest_length} bytes long.\n" if show_caveat
115
+
116
+ message << "\n " \
117
+ "Called from: #{caller[0]}."
118
+
119
+ warn message
120
+ end
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def unpacked_cookie_data(request)
127
+ request.fetch_header(RACK_SESSION_UNPACKED_COOKIE_DATA) do |k|
128
+ bin_session_data = nil
129
+
130
+ if (session_data = request.cookies[@key])
131
+ if @secrets.any?
132
+ if session_data =~ /\A([^.*]+)\.([^.*]+)\z/
133
+ session_data, digest = Regexp.last_match.captures
134
+ bin_session_data = Base64.decode(session_data)
135
+ bin_session_data = nil unless digest_match?(bin_session_data, digest)
136
+ end
137
+ else
138
+ bin_session_data = Base64.decode(session_data)
139
+ end
140
+ end
141
+
142
+ request.set_header(k, coder.decode(bin_session_data) || {})
143
+ end
144
+ end
145
+
146
+ def write_session(req, session_id, session, options)
147
+ session = session.merge('session_id'=>session_id)
148
+ bin_session_data = coder.encode(session)
149
+ session_data = Base64.encode(bin_session_data)
150
+
151
+ if @secrets.any?
152
+ session_data << '.' << generate_hmac(bin_session_data, @secrets.first)
153
+ end
154
+
155
+ session_data
156
+ end
157
+
158
+ def generate_hmac(data, secret)
159
+ Base64.encode(OpenSSL::HMAC.digest(@hmac.new, secret, data))
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: false
2
+ begin
3
+ require 'rack/session/cookie'
4
+ rescue LoadError
5
+ end
6
+
7
+ module Rack
8
+ module Session
9
+ # Stub out a parent class so gemspec can get the version from this file.
10
+ Cookie = Class.new unless defined?(Cookie)
11
+
12
+ class SmartCookie < Cookie
13
+ VERSION = '0.1.0'.freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rack/session/smart_cookie/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rack-session-smart_cookie'
8
+ spec.version = Rack::Session::SmartCookie::VERSION
9
+ spec.authors = ['Mike Pastore']
10
+ spec.email = ['mike@oobak.org']
11
+
12
+ spec.summary = %q{Slighty smarter session cookies for Rack apps}
13
+ spec.homepage = 'https://github.com/mwpastore/rack-session-smart_cookie#readme'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = %x{git ls-files -z}.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = %w[lib]
22
+
23
+ spec.required_ruby_version = '>= 2.2.8'
24
+
25
+ spec.add_dependency 'msgpack', '~> 1.1'
26
+ spec.add_dependency 'rack', ENV.fetch('RACK_VERSION', '~> 2.0.0')
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.15'
29
+ spec.add_development_dependency 'hobby', '~> 0.1.0'
30
+ spec.add_development_dependency 'minitest', '~> 5.0'
31
+ spec.add_development_dependency 'rack-test', '~> 0.7.0'
32
+ spec.add_development_dependency 'rake', '~> 12.0'
33
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-session-smart_cookie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mike Pastore
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: msgpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.15'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hobby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.7.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.7.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: '12.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '12.0'
111
+ description:
112
+ email:
113
+ - mike@oobak.org
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - bin/console
125
+ - bin/setup
126
+ - lib/rack-session-smart_cookie.rb
127
+ - lib/rack/session/smart_cookie.rb
128
+ - lib/rack/session/smart_cookie/version.rb
129
+ - rack-session-smart_cookie.gemspec
130
+ homepage: https://github.com/mwpastore/rack-session-smart_cookie#readme
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 2.2.8
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.6.13
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Slighty smarter session cookies for Rack apps
154
+ test_files: []