summary refs log tree commit
diff options
context:
space:
mode:
authorraggi <jftucker@gmail.com>2010-10-03 17:32:02 -0300
committerraggi <jftucker@gmail.com>2010-10-03 17:40:02 -0300
commitf69bd1a7fe76d51f324d0299fdb4b4c906602d2e (patch)
tree7cc9f008eeeb9ddcb11a7416aa309801295ab3ac
parentd3893c2709a9831f665245cf5da44e0019bead4f (diff)
downloadrack-f69bd1a7fe76d51f324d0299fdb4b4c906602d2e.tar.gz
Adding support for securerandom, will be in use by default. n.b. hacky test
-rw-r--r--lib/rack/session/abstract/id.rb19
-rw-r--r--test/spec_session_abstract_id.rb43
2 files changed, 59 insertions, 3 deletions
diff --git a/lib/rack/session/abstract/id.rb b/lib/rack/session/abstract/id.rb
index 6ff20fe3..1f85d616 100644
--- a/lib/rack/session/abstract/id.rb
+++ b/lib/rack/session/abstract/id.rb
@@ -4,6 +4,11 @@
 require 'time'
 require 'rack/request'
 require 'rack/response'
+begin
+  require 'securerandom'
+rescue LoadError
+  # We just won't get securerandom
+end
 
 module Rack
 
@@ -164,7 +169,8 @@ module Rack
           :defer =>         false,
           :renew =>         false,
           :sidbits =>       128,
-          :cookie_only =>   true
+          :cookie_only =>   true,
+          :secure_random => begin ::SecureRandom rescue false end
         }
 
         attr_reader :key, :default_options
@@ -174,6 +180,9 @@ module Rack
           @default_options = self.class::DEFAULT_OPTIONS.merge(options)
           @key = options[:key] || "rack.session"
           @cookie_only = @default_options.delete(:cookie_only)
+          @sid_secure = @default_options[:secure_random]
+          @sid_template = "%0#{@default_options[:sidbits] / 4}x"
+          @sid_rand_width = (2**@default_options[:sidbits] - 1)
         end
 
         def call(env)
@@ -193,8 +202,12 @@ module Rack
         # Monkey patch this to use custom methods for session id generation.
 
         def generate_sid
-          "%0#{@default_options[:sidbits] / 4}x" %
-            rand(2**@default_options[:sidbits] - 1)
+          r = if @sid_secure
+            SecureRandom.random_number(@sid_rand_width)
+          else
+            Kernel.rand(@sid_rand_width)
+          end
+          @sid_template % r
         end
 
         # Sets the lazy session at 'rack.session' and places options and session
diff --git a/test/spec_session_abstract_id.rb b/test/spec_session_abstract_id.rb
new file mode 100644
index 00000000..e1895243
--- /dev/null
+++ b/test/spec_session_abstract_id.rb
@@ -0,0 +1,43 @@
+### WARNING: there be hax in this file.
+
+require 'rack/session/abstract/id'
+
+describe Rack::Session::Abstract::ID do
+  id = Rack::Session::Abstract::ID
+
+  def silence_warning
+    o, $VERBOSE = $VERBOSE, nil
+    yield
+  ensure
+    $VERBOSE = o
+  end
+
+  def reload_id
+    $".delete $".find { |part| part =~ %r{session/abstract/id.rb} }
+    silence_warning { require 'rack/session/abstract/id' }
+  end
+
+  should "use securerandom when available" do
+    begin
+      fake = false
+      silence_warning do
+        ::SecureRandom = fake = true unless defined?(SecureRandom)
+      end
+      reload_id
+      id::DEFAULT_OPTIONS[:secure_random].should.eql(fake || SecureRandom)
+    ensure
+      Object.send(:remove_const, :SecureRandom) if fake
+    end
+  end
+
+  should "not use securerandom when unavailable" do
+    begin
+      sr = Object.send(:remove_const, :SecureRandom) if defined?(SecureRandom)
+      reload_id
+      id::DEFAULT_OPTIONS[:secure_random].should.eql false
+    ensure
+      ::SecureRandom = sr if defined?(sr)
+    end
+  end
+
+end \ No newline at end of file