rack-session-file 0.4.0 → 0.5.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.
data/README.md CHANGED
@@ -17,6 +17,12 @@ use Rack::Session::File, :storage => ENV['TEMP'],
17
17
  :expire_after => 1800
18
18
  ```
19
19
 
20
+ **NOTICE**: Never use this module in conjunction with other session middlewares (especially `Rack::Session::Cookie`). That would brake session handling.
21
+
22
+ ### For Sinatra and Padrino
23
+
24
+ Do not enable session mechanism by `enable :session`. Built-in session of Sinatra (and Padrino) utilizes `Rack::Session::Cookie`, so it will interfere this module's behavior. Using this middleware makes `session[]` available in your application without `enable :session`.
25
+
20
26
  ## Usage in Rails 3 Applications
21
27
 
22
28
  On Gemfile:
data/Rakefile CHANGED
@@ -1,2 +1,7 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new :test
6
+
7
+ task :default => :test
@@ -3,7 +3,7 @@
3
3
  module Rack
4
4
  module Session
5
5
  module File
6
- VERSION = '0.4.0'
6
+ VERSION = '0.5.0'
7
7
 
8
8
  autoload :Marshal, 'rack/session/file/marshal'
9
9
  autoload :PStore, 'rack/session/file/pstore'
@@ -5,6 +5,8 @@ require 'rack/session/abstract/id'
5
5
  module Rack
6
6
  module Session
7
7
  module File
8
+ class InvalidSessionIDError < SecurityError; end
9
+
8
10
  class Abstract < Rack::Session::Abstract::ID
9
11
  DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS.merge({
10
12
  :storage => Dir.tmpdir,
@@ -161,6 +163,14 @@ module Rack
161
163
  def want_thread_safe?
162
164
  @env['rack.multithread']
163
165
  end
166
+
167
+ def ensure_sid_is_valid(sid)
168
+ unless /^[0-9A-Fa-f]+$/ =~ sid
169
+ raise InvalidSessionIDError.new("'#{sid}' is not suitable for session ID")
170
+ end
171
+
172
+ true
173
+ end
164
174
  end
165
175
  end
166
176
  end
@@ -23,6 +23,8 @@ module Rack
23
23
  open_session_file(sid, 'r') do |file|
24
24
  return ::Marshal.load(file)
25
25
  end
26
+ rescue InvalidSessionIDError
27
+ return nil
26
28
  rescue Errno::ENOENT
27
29
  return nil
28
30
  rescue TypeError
@@ -31,9 +33,12 @@ module Rack
31
33
  end
32
34
 
33
35
  def delete_session(sid)
34
- filename = session_file_name(sid)
35
- if ::File.exists?(filename)
36
- ::File.unlink(filename)
36
+ begin
37
+ filename = session_file_name(sid)
38
+ if ::File.exists?(filename)
39
+ ::File.unlink(filename)
40
+ end
41
+ rescue InvalidSessionIDError
37
42
  end
38
43
  end
39
44
 
@@ -55,6 +60,7 @@ module Rack
55
60
  end
56
61
 
57
62
  def session_file_name(sid)
63
+ ensure_sid_is_valid(sid)
58
64
  return ::File.join(@storage, sid)
59
65
  end
60
66
 
@@ -33,6 +33,8 @@ module Rack
33
33
  data[key] = db[key]
34
34
  end
35
35
  end
36
+ rescue InvalidSessionIDError
37
+ return nil
36
38
  rescue TypeError
37
39
  return nil
38
40
  end
@@ -40,9 +42,12 @@ module Rack
40
42
  end
41
43
 
42
44
  def delete_session(sid)
43
- filename = store_for_sid(sid).path
44
- if ::File.exists?(filename)
45
- ::File.unlink(filename)
45
+ begin
46
+ filename = store_for_sid(sid).path
47
+ if ::File.exists?(filename)
48
+ ::File.unlink(filename)
49
+ end
50
+ rescue InvalidSessionIDError
46
51
  end
47
52
  end
48
53
 
@@ -61,6 +66,7 @@ module Rack
61
66
  end
62
67
 
63
68
  def session_file_name(sid)
69
+ ensure_sid_is_valid(sid)
64
70
  return ::File.join(@storage, sid)
65
71
  end
66
72
 
@@ -8,6 +8,7 @@ module Rack
8
8
  module Session
9
9
  module File
10
10
  class YAML < Abstract
11
+
11
12
  def initialize(app, options = {})
12
13
  super
13
14
  @transaction_options['yaml'] = @default_options.delete(:yaml) || {}
@@ -43,16 +44,21 @@ module Rack
43
44
  data[key] = db[key]
44
45
  end
45
46
  end
46
- rescue Psych::SyntaxError, Syck::Error, Syck::TypeError
47
+ rescue InvalidSessionIDError
48
+ return nil
49
+ rescue (::Psych::SyntaxError rescue nil), (::Syck::Error rescue nil), (::Syck::TypeError rescue nil)
47
50
  return nil
48
51
  end
49
52
  return data
50
53
  end
51
54
 
52
55
  def delete_session(sid)
53
- filename = store_for_sid(sid).path
54
- if ::File.exists?(filename)
55
- ::File.unlink(filename)
56
+ begin
57
+ filename = store_for_sid(sid).path
58
+ if ::File.exists?(filename)
59
+ ::File.unlink(filename)
60
+ end
61
+ rescue InvalidSessionIDError
56
62
  end
57
63
  end
58
64
 
@@ -67,6 +73,7 @@ module Rack
67
73
  end
68
74
 
69
75
  def session_file_name(sid)
76
+ ensure_sid_is_valid(sid)
70
77
  return ::File.join(@storage, sid)
71
78
  end
72
79
 
@@ -32,7 +32,7 @@ Gem::Specification.new do |gem|
32
32
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
33
33
  gem.name = "rack-session-file"
34
34
  gem.require_paths = ["lib"]
35
- gem.version = '0.4.0'
35
+ gem.version = '0.5.0'
36
36
 
37
37
  if gem.respond_to? :specification_version then
38
38
  gem.specification_version = 3
@@ -65,26 +65,26 @@ shared_examples_for Rack::Session::File do
65
65
  end
66
66
 
67
67
  it 'survives nonexistent cookies' do
68
- bad_cookie = 'rack.session=blarghfasel'
68
+ bad_cookie = 'rack.session=00000001'
69
69
  res = Rack::MockRequest.new(pool) \
70
70
  .get('/', 'HTTP_COOKIE' => bad_cookie)
71
71
 
72
72
  res.body.should == '{"counter"=>1}'
73
73
  cookie = res['Set-Cookie'][@session_match]
74
- cookie.should_not match(/#{bad_cookie}/)
74
+ cookie.should_not match(/#{bad_cookie}(?:;|$)/)
75
75
  end
76
76
 
77
77
  it 'survives broken session data' do
78
- open(::File.join(@storage, 'broken'), 'w') do |f|
79
- f.write "\x1\x1o" # broken data for Marshal, YAML
78
+ open(::File.join(@storage, '00000002'), 'w') do |f|
79
+ f.write "\x1\x1o" # broken data for Marshal and YAML
80
80
  end
81
- cookie = 'rack.session=broken'
81
+ bad_cookie = 'rack.session=00000002'
82
82
  res = Rack::MockRequest.new(pool) \
83
- .get('/', 'HTTP_COOKIE' => cookie)
83
+ .get('/', 'HTTP_COOKIE' => bad_cookie)
84
84
 
85
85
  res.body.should == '{"counter"=>1}'
86
86
  cookie = res['Set-Cookie'][@session_match]
87
- cookie.should_not match(/broken/)
87
+ cookie.should_not match(/#{bad_cookie}(?:;|$)/)
88
88
  end
89
89
 
90
90
  it 'should maintain freshness' do
@@ -173,5 +173,15 @@ shared_examples_for Rack::Session::File do
173
173
  # res3['Set-Cookie'][@session_match].should == session
174
174
  res3.body.should == '{"counter"=>4}'
175
175
  end
176
+
177
+ it 'omit cookie with bad session id' do
178
+ bad_cookie = 'rack.session=/etc/passwd'
179
+ res = Rack::MockRequest.new(pool) \
180
+ .get('/', 'HTTP_COOKIE' => bad_cookie)
181
+
182
+ res.body.should == '{"counter"=>1}'
183
+ cookie = res['Set-Cookie'][@session_match]
184
+ cookie.should_not match(/#{bad_cookie}(?:;|$)/)
185
+ end
176
186
  end
177
187
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-session-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-05 00:00:00.000000000 Z
12
+ date: 2012-11-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -82,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
82
  version: '0'
83
83
  segments:
84
84
  - 0
85
- hash: -4049294331236196458
85
+ hash: 3379845102946176394
86
86
  required_rubygems_version: !ruby/object:Gem::Requirement
87
87
  none: false
88
88
  requirements:
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
91
  version: '0'
92
92
  segments:
93
93
  - 0
94
- hash: -4049294331236196458
94
+ hash: 3379845102946176394
95
95
  requirements: []
96
96
  rubyforge_project:
97
97
  rubygems_version: 1.8.23