rack-session-file 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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