Compare commits

..

22 Commits

Author SHA1 Message Date
Greg Ose
730e6a273c Merge pull request #64 from github/json-sessions
Support custom serialization for Session::CookieStore
2014-05-16 00:06:44 -05:00
Greg Ose
aa1b6d1284 bump rails version 2014-05-15 22:49:19 -05:00
Greg Ose
5f6c95e29e Merge branch '2-3-github' into json-sessions 2014-05-13 15:29:47 -05:00
Charlie Somerville
7403667b89 Merge pull request #67 from github/2-3-github+cve-2014-0130
CVE-2014-0130 protection
2014-05-10 00:52:08 +10:00
Charlie Somerville
1a45ec57bf CVE-2014-0130 protection 2014-05-09 23:55:20 +10:00
Greg Ose
9070fbcffe Revert nested hash indifference, swap delete order
Upstream doesnt support nested hashes having indifferent access, we
should stay consistent. Swap order for returned value in session hash.
2014-05-07 14:27:52 -05:00
Greg Ose
364b534815 support indifferent access for hashes stored within FlashHash 2014-04-30 13:18:28 -05:00
Greg Ose
14da203564 indifferent delete 2014-04-29 10:37:53 -05:00
Greg Ose
f46a4bab08 indifferent access to flash hash 2014-04-29 10:21:16 -05:00
Greg Ose
198aa6ef99 Update tests to load flash from session value 2014-04-28 15:07:52 -05:00
Greg Ose
b3ae51c9fc Add serializer option to cookie store and use Rails 4 Hash flash
Backport for Rails 4 flash hash based on https://github.com/envato/rails_4_session_flash_backport
2014-04-28 14:42:24 -05:00
Patrick Toomey
1e6e438f6e Update RAILS_VERSION 2014-04-24 10:45:25 -05:00
Patrick Toomey
2b01f832a3 Merge pull request #63 from github/memoize-nil-check
make sure nil isn't memoized and frozen
2014-04-24 10:44:47 -05:00
Patrick Toomey
1e5fda763e backport memoiziation from 3.0 2014-04-24 10:24:04 -05:00
Dirkjan Bussink
7c3d4ec43c Bump version 2014-03-31 13:43:08 +02:00
Dirkjan Bussink
7343ed7b05 Merge pull request #53 from github/dbussink/no-toplevel-exception-rescue
We shouldn't try to rescue every type of exception here
2014-03-31 11:42:02 +00:00
Dirkjan Bussink
2a70c9691d We shouldn't try to rescue every type of exception here 2014-03-31 13:35:28 +02:00
Dirkjan Bussink
a141d9de0d bump 2.3.14.github41 2014-03-27 13:55:26 +01:00
Dirkjan Bussink
74492f43a8 Merge pull request #51 from github/dbussink/fix-logging-frozen-string-query
Dup string before changing encoding because it might be frozen
2014-03-27 12:53:25 +00:00
Dirkjan Bussink
c2894170bf Dup string before changing encoding because it might be frozen
Calling String#force_encoding! on a frozen string throws an exception.
By dupping the string we prevent this from happening.
2014-03-27 13:47:08 +01:00
Charlie Somerville
057aed6e18 Merge pull request #48 from github/2-3-kill-backtick-monkey-patch
[2.3] Kill Object#` monkey patch
2014-02-23 23:20:47 +11:00
Charlie Somerville
02fc012b42 kill Object#` monkey patch 2014-02-23 23:17:44 +11:00
12 changed files with 112 additions and 66 deletions

View File

@@ -1 +1 @@
2.3.14.github40
2.3.14.github45

View File

@@ -1320,7 +1320,14 @@ module ActionController #:nodoc:
render
end
CVE_2014_0310 = Class.new(StandardError)
def perform_action
# CVE-2014-0130 protection
if action_name.include? "/"
raise CVE_2014_0310
end
if action_methods.include?(action_name)
send(action_name)
default_render unless performed?

View File

@@ -45,37 +45,74 @@ module ActionController #:nodoc:
end
def []=(k, v)
k = k.to_s
@flash[k] = v
@flash.discard(k)
v
end
def [](k)
@flash[k]
@flash[k.to_s]
end
end
class FlashHash < Hash
def self.from_session_value(value)
flash = case value
when FlashHash # Rails 2.3
value
when Hash # Rails 4.0
flashes = value['flashes'] || {}
flashes.stringify_keys!
discard = value['discard'] || []
discard = discard.map do |item|
item.kind_of?(Symbol) ? item.to_s : item
end
used = Hash[flashes.keys.map{|k| [k, discard.include?(k)] }]
new_from_values(flashes, used)
else
new
end
flash
end
def initialize #:nodoc:
super
@used = {}
end
def to_session_value
return nil if empty?
rails_3_discard_list = @used.map{|k,v| k if v}.compact
{'discard' => rails_3_discard_list, 'flashes' => Hash[to_a]}
end
def []=(k, v) #:nodoc:
k = k.to_s
keep(k)
super
super(k, v)
end
def [](k)
super(k.to_s)
end
def delete(k)
super(k.to_s)
end
def update(h) #:nodoc:
h.stringify_keys!
h.keys.each { |k| keep(k) }
super
super(h)
end
alias :merge! :update
def replace(h) #:nodoc:
@used = {}
super
super(h.stringify_keys)
end
# Sets a flash that will not be available to the next action, only to the current.
@@ -126,8 +163,7 @@ module ActionController #:nodoc:
end
def store(session, key = "flash")
return if self.empty?
session[key] = self
session[key] = to_session_value
end
private
@@ -138,11 +174,20 @@ module ActionController #:nodoc:
# use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action)
def use(k=nil, v=true)
unless k.nil?
@used[k] = v
@used[k.to_s] = v
else
keys.each{ |key| use(key, v) }
end
end
def self.new_from_values(flashes, used)
new.tap do |flash_hash|
flashes.each do |k, v|
flash_hash[k] = v
end
flash_hash.instance_variable_set("@used", used)
end
end
end
module InstanceMethods #:nodoc:
@@ -168,11 +213,11 @@ module ActionController #:nodoc:
if notice = response_status_and_flash.delete(:notice)
flash[:notice] = notice
end
if other_flashes = response_status_and_flash.delete(:flash)
flash.update(other_flashes)
end
redirect_to_without_flash(options, response_status_and_flash)
end
@@ -181,19 +226,19 @@ module ActionController #:nodoc:
# to put a new one.
def flash #:doc:
if !defined?(@_flash)
@_flash = session["flash"] || FlashHash.new
@_flash = Flash::FlashHash.from_session_value(session["flash"])
@_flash.sweep
end
@_flash
end
# Convenience accessor for flash[:alert]
def alert
flash[:alert]
end
# Convenience accessor for flash[:alert]=
def alert=(message)
flash[:alert] = message
@@ -203,7 +248,7 @@ module ActionController #:nodoc:
def notice
flash[:notice]
end
# Convenience accessor for flash[:notice]=
def notice=(message)
flash[:notice] = message

View File

@@ -2,7 +2,7 @@ require 'rack/utils'
module ActionController
module Session
class AbstractStore
class AbstractStore
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
@@ -55,17 +55,17 @@ module ActionController
def [](key)
load_for_read!
super
super(key.to_s) || super(key)
end
def has_key?(key)
load_for_read!
super
super(key.to_s) || super(key)
end
def []=(key, value)
load_for_write!
super
super(key.to_s, value)
end
def clear
@@ -87,7 +87,9 @@ module ActionController
def delete(key)
load_for_write!
super
value = super(key)
string_value = super(key.to_s)
string_value || value
end
def data
@@ -119,7 +121,7 @@ module ActionController
end
private
def load_for_read!
load! if !loaded? && exists?
end
@@ -183,7 +185,7 @@ module ActionController
request = ActionController::Request.new(env)
return response if (options[:secure] && !request.ssl?)
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
sid = options[:id] || generate_sid
@@ -205,12 +207,12 @@ module ActionController
end
private
def prepare!(env)
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
end
def generate_sid
ActiveSupport::SecureRandom.hex(16)
end
@@ -222,7 +224,7 @@ module ActionController
[sid, session]
end
end
def extract_session_id(env)
stale_session_check! do
request = Rack::Request.new(env)
@@ -235,7 +237,7 @@ module ActionController
def current_session_id(env)
env[ENV_SESSION_OPTIONS_KEY][:id]
end
def exists?(env)
current_session_id(env).present?
end
@@ -247,11 +249,11 @@ module ActionController
def set_session(env, sid, session_data)
raise '#set_session needs to be implemented.'
end
def destroy(env)
raise '#destroy needs to be implemented.'
end
module SessionUtils
private
def stale_session_check!

View File

@@ -86,7 +86,8 @@ module ActionController
@secret = options.delete(:secret).freeze
@digest = options.delete(:digest) || 'SHA1'
@verifier = verifier_for(@secret, @digest)
@serializer = options.delete(:serializer) || Marshal
@verifier = verifier_for(@secret, @digest, @serializer)
@default_options = DEFAULT_OPTIONS.merge(options).freeze
@@ -138,13 +139,13 @@ module ActionController
def load_session(env)
data = unpacked_cookie_data(env)
data = persistent_session_id!(data)
[data[:session_id], data]
[data["session_id"] || data[:session_id], data]
end
def extract_session_id(env)
if data = unpacked_cookie_data(env)
persistent_session_id!(data) unless data.empty?
data[:session_id]
data["session_id"] || data[:session_id]
else
nil
end
@@ -214,9 +215,9 @@ module ActionController
end
end
def verifier_for(secret, digest)
def verifier_for(secret, digest, serializer)
key = secret.respond_to?(:call) ? secret.call : secret
ActiveSupport::MessageVerifier.new(key, digest: digest)
ActiveSupport::MessageVerifier.new(key, digest: digest, serializer: serializer)
end
def generate_sid
@@ -232,12 +233,12 @@ module ActionController
end
def inject_persistent_session_id(data)
requires_session_id?(data) ? { :session_id => generate_sid } : {}
requires_session_id?(data) ? { "session_id" => generate_sid } : {}
end
def requires_session_id?(data)
if data
data.respond_to?(:key?) && !data.key?(:session_id)
data.respond_to?(:key?) && !(data.key?("session_id") || data.key?(:session_id))
else
true
end

View File

@@ -219,7 +219,7 @@ module ActionController #:nodoc:
# A shortcut to the flash. Returns an empty hash if no session flash exists.
def flash
session['flash'] || {}
ActionController::Flash::FlashHash.from_session_value(session["flash"]) || {}
end
# Do we have a flash?

View File

@@ -195,7 +195,9 @@ module ActiveRecord
def log_info(sql, name, ms)
if @logger && @logger.debug?
name = '%s (%.1fms)' % [name || 'SQL', ms]
sql.force_encoding 'binary' if sql.respond_to?(:force_encoding)
if sql.respond_to?(:force_encoding)
sql = sql.dup.force_encoding 'binary'
end
@logger.debug(format_log_entry(name, sql.squeeze(' ')))
end
end
@@ -212,13 +214,7 @@ module ActiveRecord
log_info(sql, name, 0)
nil
end
rescue SystemExit, SignalException, NoMemoryError => e
# Don't re-wrap these exceptions. They are probably not being caused by invalid
# sql, but rather some external stimulus beyond the responsibilty of this code.
# Additionaly, wrapping these exceptions with StatementInvalid would lead to
# meaningful loss of data, such as losing SystemExit#status.
raise e
rescue Exception => e
rescue => e
# Log message and raise exception.
# Set last_verification to 0, so that connection gets verified
# upon reentering the request loop

View File

@@ -1,5 +1,4 @@
require 'active_support/core_ext/kernel/daemonizing'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/agnostics'
require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/kernel/debugger'

View File

@@ -1,11 +0,0 @@
class Object
# Makes backticks behave (somewhat more) similarly on all platforms.
# On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the
# spawned shell prints a message to stderr and sets $?. We emulate
# Unix on the former but not the latter.
def `(command) #:nodoc:
super
rescue Errno::ENOENT => e
STDERR.puts "#$0: #{e}"
end
end

View File

@@ -1,3 +1,6 @@
require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/module/aliasing'
module ActiveSupport
module Memoizable
def self.memoized_ivar_for(symbol)
@@ -41,10 +44,10 @@ module ActiveSupport
end
end
def flush_cache(*syms, &block)
def flush_cache(*syms)
syms.each do |sym|
(methods + private_methods + protected_methods).each do |m|
if m.to_s =~ /^_unmemoized_(#{sym})/
if m.to_s =~ /^_unmemoized_(#{sym.to_s.gsub(/\?\Z/, '\?')})/
ivar = ActiveSupport::Memoizable.memoized_ivar_for($1)
instance_variable_get(ivar).clear if instance_variable_defined?(ivar)
end
@@ -69,7 +72,7 @@ module ActiveSupport
if instance_method(:#{symbol}).arity == 0 # if instance_method(:mime_type).arity == 0
def #{symbol}(reload = false) # def mime_type(reload = false)
if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? # if reload || !defined?(@_memoized_mime_type) || @_memoized_mime_type.empty?
#{memoized_ivar} = [#{original_method}.freeze] # @_memoized_mime_type = [_unmemoized_mime_type.freeze]
#{memoized_ivar} = [#{original_method}] # @_memoized_mime_type = [_unmemoized_mime_type]
end # end
#{memoized_ivar}[0] # @_memoized_mime_type[0]
end # end
@@ -82,7 +85,7 @@ module ActiveSupport
if !reload && #{memoized_ivar}.has_key?(args) # if !reload && @_memoized_mime_type.has_key?(args)
#{memoized_ivar}[args] # @_memoized_mime_type[args]
elsif #{memoized_ivar} # elsif @_memoized_mime_type
#{memoized_ivar}[args] = #{original_method}(*args).freeze # @_memoized_mime_type[args] = _unmemoized_mime_type(*args).freeze
#{memoized_ivar}[args] = #{original_method}(*args) # @_memoized_mime_type[args] = _unmemoized_mime_type(*args)
end # end
else # else
#{original_method}(*args) # _unmemoized_mime_type(*args)

View File

@@ -1,3 +1,4 @@
require 'abstract_unit'
require 'active_support'
require 'test/unit'

View File

@@ -4,12 +4,13 @@ class MemoizableTest < Test::Unit::TestCase
class Person
extend ActiveSupport::Memoizable
attr_reader :name_calls, :age_calls, :is_developer_calls
attr_reader :name_calls, :age_calls, :is_developer_calls, :name_query_calls
def initialize
@name_calls = 0
@age_calls = 0
@is_developer_calls = 0
@name_query_calls = 0
end
def name
@@ -18,6 +19,7 @@ class MemoizableTest < Test::Unit::TestCase
end
def name?
@name_query_calls += 1
true
end
memoize :name?
@@ -123,6 +125,13 @@ class MemoizableTest < Test::Unit::TestCase
end
end
def test_memoization_flush_with_punctuation
assert_equal true, @person.name?
@person.flush_cache(:name?)
3.times { assert_equal true, @person.name? }
assert_equal 2, @person.name_query_calls
end
def test_memoization_with_nil_value
assert_equal nil, @person.age
assert_equal 1, @person.age_calls
@@ -131,13 +140,7 @@ class MemoizableTest < Test::Unit::TestCase
assert_equal 1, @person.age_calls
end
def test_memorized_results_are_immutable
assert_equal "Josh", @person.name
assert_raise(ActiveSupport::FrozenObjectError) { @person.name.gsub!("Josh", "Gosh") }
end
def test_reloadable
counter = @calculator.counter
assert_equal 1, @calculator.counter
assert_equal 2, @calculator.counter(:reload)
assert_equal 2, @calculator.counter