diff options
Diffstat (limited to 'lib/cgi/session.rb')
| -rw-r--r-- | lib/cgi/session.rb | 97 |
1 files changed, 64 insertions, 33 deletions
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb index 63c5003526..70c7ebca42 100644 --- a/lib/cgi/session.rb +++ b/lib/cgi/session.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # cgi/session.rb - session support for cgi scripts # @@ -163,29 +164,72 @@ class CGI # Create a new session id. # - # The session id is an MD5 hash based upon the time, - # a random number, and a constant string. This routine - # is used internally for automatically generated - # session ids. + # The session id is a secure random number by SecureRandom + # if possible, otherwise an SHA512 hash based upon the time, + # a random number, and a constant string. This routine is + # used internally for automatically generated session ids. def create_new_id require 'securerandom' begin + # by OpenSSL, or system provided entropy pool session_id = SecureRandom.hex(16) rescue NotImplementedError - require 'digest/md5' - md5 = Digest::MD5::new + # never happens on modern systems + require 'digest' + d = Digest('SHA512').new now = Time::now - md5.update(now.to_s) - md5.update(String(now.usec)) - md5.update(String(rand(0))) - md5.update(String($$)) - md5.update('foobar') - session_id = md5.hexdigest + d.update(now.to_s) + d.update(String(now.usec)) + d.update(String(rand(0))) + d.update(String($$)) + d.update('foobar') + session_id = d.hexdigest[0, 32] end session_id end private :create_new_id + + # Create a new file to store the session data. + # + # This file will be created if it does not exist, or opened if it + # does. + # + # This path is generated under _tmpdir_ from _prefix_, the + # digested session id, and _suffix_. + # + # +option+ is a hash of options for the initializer. The + # following options are recognised: + # + # tmpdir:: the directory to use for storing the FileStore + # file. Defaults to Dir::tmpdir (generally "/tmp" + # on Unix systems). + # prefix:: the prefix to add to the session id when generating + # the filename for this session's FileStore file. + # Defaults to "cgi_sid_". + # suffix:: the prefix to add to the session id when generating + # the filename for this session's FileStore file. + # Defaults to the empty string. + def new_store_file(option={}) # :nodoc: + dir = option['tmpdir'] || Dir::tmpdir + prefix = option['prefix'] + suffix = option['suffix'] + require 'digest/md5' + md5 = Digest::MD5.hexdigest(session_id)[0,16] + path = dir+"/" + path << prefix if prefix + path << md5 + path << suffix if suffix + if File::exist? path + hash = nil + elsif new_session + hash = {} + else + raise NoSession, "uninitialized session" + end + return path, hash + end + # Create a new CGI::Session object for +request+. # # +request+ is an instance of the +CGI+ class (see cgi.rb). @@ -370,21 +414,8 @@ class CGI # This session's FileStore file will be created if it does # not exist, or opened if it does. def initialize(session, option={}) - dir = option['tmpdir'] || Dir::tmpdir - prefix = option['prefix'] || 'cgi_sid_' - suffix = option['suffix'] || '' - id = session.session_id - require 'digest/md5' - md5 = Digest::MD5.hexdigest(id)[0,16] - @path = dir+"/"+prefix+md5+suffix - if File::exist? @path - @hash = nil - else - unless session.new_session - raise CGI::Session::NoSession, "uninitialized session" - end - @hash = {} - end + option = {'prefix' => 'cgi_sid_'}.update(option) + @path, @hash = session.new_store_file(option) end # Restore session state from the session's FileStore file. @@ -400,11 +431,11 @@ class CGI for line in f line.chomp! k, v = line.split('=',2) - @hash[CGI::unescape(k)] = Marshal.restore(CGI::unescape(v)) + @hash[CGI.unescape(k)] = Marshal.restore(CGI.unescape(v)) end ensure - f.close unless f.nil? - lockf.close if lockf + f&.close + lockf&.close end end @hash @@ -418,13 +449,13 @@ class CGI lockf.flock File::LOCK_EX f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600) for k,v in @hash - f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(Marshal.dump(v))) + f.printf "%s=%s\n", CGI.escape(k), CGI.escape(String(Marshal.dump(v))) end f.close File.rename @path+".new", @path ensure - f.close if f and !f.closed? - lockf.close if lockf + f&.close + lockf&.close end end |
