mirror of
https://github.com/github/rails.git
synced 2026-01-12 08:08:31 -05:00
Compare commits
11 Commits
github24
...
reduce-obj
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d4d006cd6 | ||
|
|
1b0cb37cf0 | ||
|
|
8d8cef48cc | ||
|
|
37ed643ac7 | ||
|
|
685cb901fc | ||
|
|
e9f9d05a94 | ||
|
|
7b6670cc08 | ||
|
|
ed2d852bdc | ||
|
|
726ab5316d | ||
|
|
ecd6fb250a | ||
|
|
9f8ee9dd97 |
@@ -268,7 +268,7 @@ EOM
|
||||
|
||||
# Is this an SSL request?
|
||||
def ssl?
|
||||
@env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
||||
@env['HTTPS'f] == 'on'f || @env['HTTP_X_FORWARDED_PROTO'f] == 'https'f
|
||||
end
|
||||
|
||||
# Returns the \host for this request, such as "example.com".
|
||||
|
||||
@@ -209,7 +209,7 @@ module ActionController
|
||||
|
||||
def verifier_for(secret, digest)
|
||||
key = secret.respond_to?(:call) ? secret.call : secret
|
||||
ActiveSupport::MessageVerifier.new(key, digest)
|
||||
ActiveSupport::MessageVerifier.new(key, digest: digest)
|
||||
end
|
||||
|
||||
def generate_sid
|
||||
|
||||
@@ -137,6 +137,10 @@ module ActionView
|
||||
STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets"
|
||||
JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
|
||||
|
||||
class << self
|
||||
attr_accessor :rails_asset_id
|
||||
end
|
||||
|
||||
# Returns a link tag that browsers and news readers can use to auto-detect
|
||||
# an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or
|
||||
# <tt>:atom</tt>. Control the link options in url_for format using the
|
||||
@@ -182,7 +186,7 @@ module ActionView
|
||||
# javascript_path "http://www.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr.js
|
||||
# javascript_path "http://www.railsapplication.com/js/xmlhr.js" # => http://www.railsapplication.com/js/xmlhr.js
|
||||
def javascript_path(source)
|
||||
compute_public_path(source, 'javascripts', 'js')
|
||||
compute_public_path(source, 'javascripts'f, 'js'f)
|
||||
end
|
||||
alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
|
||||
|
||||
@@ -540,7 +544,7 @@ module ActionView
|
||||
source = rewrite_asset_path(source)
|
||||
|
||||
if has_request && include_host
|
||||
unless source =~ %r{^#{ActionController::Base.relative_url_root}/}
|
||||
unless source =~ %r{^#{ActionController::Base.relative_url_root}/}o
|
||||
source = "#{ActionController::Base.relative_url_root}#{source}"
|
||||
end
|
||||
end
|
||||
@@ -583,11 +587,10 @@ module ActionView
|
||||
@@asset_timestamps_cache = {}
|
||||
@@asset_timestamps_cache_guard = Mutex.new
|
||||
|
||||
# Use the RAILS_ASSET_ID environment variable or the source's
|
||||
# modification time as its cache-busting asset id.
|
||||
# Use modification time as its cache-busting asset id.
|
||||
def rails_asset_id(source)
|
||||
if asset_id = ENV["RAILS_ASSET_ID"]
|
||||
asset_id
|
||||
if ActionView::Helpers::AssetTagHelper.rails_asset_id
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id
|
||||
else
|
||||
if @@cache_asset_timestamps && (asset_id = @@asset_timestamps_cache[source])
|
||||
asset_id
|
||||
@@ -618,11 +621,11 @@ module ActionView
|
||||
end
|
||||
|
||||
def javascript_src_tag(source, options)
|
||||
content_tag("script", "", { "type" => Mime::JS, "src" => path_to_javascript(source) }.merge(options))
|
||||
content_tag("script"f, ""f, { "type"f => Mime::JS, "src"f => path_to_javascript(source) }.merge(options))
|
||||
end
|
||||
|
||||
def stylesheet_tag(source, options)
|
||||
tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false)
|
||||
tag("link"f, { "rel"f => "stylesheet"f, "type"f => Mime::CSS, "media"f => "screen"f, "href"f => html_escape(path_to_stylesheet(source)) }.merge(options), false, false)
|
||||
end
|
||||
|
||||
def compute_javascript_paths(*args)
|
||||
|
||||
@@ -130,19 +130,20 @@ module ActionView
|
||||
end
|
||||
|
||||
def tag_options(options, escape = true)
|
||||
attrs = ""
|
||||
unless options.blank?
|
||||
attrs = []
|
||||
options.each_pair do |key, value|
|
||||
attrs << " "
|
||||
if BOOLEAN_ATTRIBUTES.include?(key)
|
||||
attrs << %(#{key}="#{key}") if value
|
||||
attrs << key << '="'f << key << '"'f if value
|
||||
elsif !value.nil?
|
||||
final_value = value.is_a?(Array) ? value.join(" ") : value
|
||||
final_value = value.is_a?(Array) ? value.join(" "f) : value
|
||||
final_value = html_escape(final_value) if escape
|
||||
attrs << %(#{key}="#{final_value}")
|
||||
attrs << key << '="'f << final_value << '"'f
|
||||
end
|
||||
end
|
||||
" #{attrs.sort * ' '}".html_safe unless attrs.empty?
|
||||
end
|
||||
attrs.html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,14 @@ module RequestForgeryProtectionActions
|
||||
render :inline => "<% form_remote_tag(:url => '/') {} %>"
|
||||
end
|
||||
|
||||
def external_form_for
|
||||
render :inline => "<%= form_for(:some_resource, :authenticity_token => 'external_token') {} %>"
|
||||
end
|
||||
|
||||
def form_for_without_token
|
||||
render :inline => "<%= form_for(:some_resource, :authenticity_token => false ) {} %>"
|
||||
end
|
||||
|
||||
def unsafe
|
||||
render :text => 'pwn'
|
||||
end
|
||||
@@ -156,6 +164,20 @@ module RequestForgeryProtectionTests
|
||||
assert_nothing_raised { yield }
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
def test_should_render_form_with_token_tag_with_authenticity_token_requested
|
||||
assert_not_blocked do
|
||||
get :external_form_for
|
||||
end
|
||||
assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', 'external_token'
|
||||
end
|
||||
|
||||
def test_should_render_form_without_token_tag_with_authenticity_token_set_to_false
|
||||
assert_not_blocked do
|
||||
get :form_for_without_token
|
||||
end
|
||||
assert_select 'form>div>input[name=?]', 'authenticity_token', false
|
||||
end
|
||||
end
|
||||
|
||||
# OK let's get our test on
|
||||
|
||||
@@ -7,7 +7,7 @@ class CookieStoreTest < ActionController::IntegrationTest
|
||||
|
||||
DispatcherApp = ActionController::Dispatcher.new
|
||||
|
||||
Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
|
||||
Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, digest: 'SHA1')
|
||||
|
||||
SignedBar = "BAh7BjoIZm9vIghiYXI%3D--fef868465920f415f2c0652d6910d3af288a0367"
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
def teardown
|
||||
ActionController::Base.perform_caching = false
|
||||
ActionController::Base.asset_host = nil
|
||||
ENV.delete('RAILS_ASSET_ID')
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = nil
|
||||
end
|
||||
|
||||
AutoDiscoveryToTag = {
|
||||
@@ -154,12 +154,12 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_javascript_include_tag_with_blank_asset_id
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
|
||||
end
|
||||
|
||||
def test_javascript_include_tag_with_given_asset_id
|
||||
ENV["RAILS_ASSET_ID"] = "1"
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = "1"
|
||||
assert_dom_equal(%(<script src="/javascripts/prototype.js?1" type="text/javascript"></script>\n<script src="/javascripts/effects.js?1" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js?1" type="text/javascript"></script>\n<script src="/javascripts/controls.js?1" type="text/javascript"></script>\n<script src="/javascripts/application.js?1" type="text/javascript"></script>), javascript_include_tag(:defaults))
|
||||
end
|
||||
|
||||
@@ -169,13 +169,13 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_register_javascript_include_default
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'slider'
|
||||
assert_dom_equal %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/slider.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
|
||||
end
|
||||
|
||||
def test_register_javascript_include_default_mixed_defaults
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'slider'
|
||||
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'lib1', '/elsewhere/blub/lib2'
|
||||
assert_dom_equal %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/slider.js" type="text/javascript"></script>\n<script src="/javascripts/lib1.js" type="text/javascript"></script>\n<script src="/elsewhere/blub/lib2.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
|
||||
@@ -187,7 +187,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_custom_javascript_expansions_and_defaults_puts_application_js_at_the_end
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionView::Helpers::AssetTagHelper::register_javascript_expansion :monkey => ["head", "body", "tail"]
|
||||
assert_dom_equal %(<script src="/javascripts/first.js" type="text/javascript"></script>\n<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/head.js" type="text/javascript"></script>\n<script src="/javascripts/body.js" type="text/javascript"></script>\n<script src="/javascripts/tail.js" type="text/javascript"></script>\n<script src="/javascripts/last.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>), javascript_include_tag('first', :defaults, :monkey, 'last')
|
||||
end
|
||||
@@ -206,12 +206,12 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_stylesheet_link_tag
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
|
||||
end
|
||||
|
||||
def test_stylesheet_link_tag_is_html_safe
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
assert stylesheet_link_tag('dir/file').html_safe?
|
||||
assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe?
|
||||
assert stylesheet_tag('dir/file', {}).html_safe?
|
||||
@@ -242,7 +242,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_image_tag_windows_behaviour
|
||||
old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1"
|
||||
old_asset_id, ActionView::Helpers::AssetTagHelper.rails_asset_id = ActionView::Helpers::AssetTagHelper.rails_asset_id, "1"
|
||||
# This simulates the behaviour of File#exist? on windows when testing a file ending in "."
|
||||
# If the file "rails.png" exists, windows will return true when asked if "rails.png." exists (notice trailing ".")
|
||||
# OS X, linux etc will return false in this case.
|
||||
@@ -250,9 +250,9 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
assert_equal '<img alt="Rails" src="/images/rails.png?1" />', image_tag('rails.png')
|
||||
ensure
|
||||
if old_asset_id
|
||||
ENV["RAILS_ASSET_ID"] = old_asset_id
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = old_asset_id
|
||||
else
|
||||
ENV.delete("RAILS_ASSET_ID")
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -274,12 +274,12 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_should_use_preset_asset_id
|
||||
ENV["RAILS_ASSET_ID"] = "4500"
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = "4500"
|
||||
assert_equal %(<img alt="Rails" src="/images/rails.png?4500" />), image_tag("rails.png")
|
||||
end
|
||||
|
||||
def test_preset_empty_asset_id
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
assert_equal %(<img alt="Rails" src="/images/rails.png" />), image_tag("rails.png")
|
||||
end
|
||||
|
||||
@@ -291,7 +291,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_image_path_with_caching_and_proc_asset_host_using_request
|
||||
ENV['RAILS_ASSET_ID'] = ''
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ''
|
||||
ActionController::Base.asset_host = Proc.new do |source, request|
|
||||
if request.ssl?
|
||||
"#{request.protocol}#{request.host_with_port}"
|
||||
@@ -311,7 +311,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_on
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = 'http://a0.example.com'
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -343,7 +343,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host
|
||||
ENV['RAILS_ASSET_ID'] = ''
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ''
|
||||
ActionController::Base.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -360,7 +360,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_on_with_2_argument_proc_asset_host
|
||||
ENV['RAILS_ASSET_ID'] = ''
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ''
|
||||
ActionController::Base.asset_host = Proc.new { |source, request|
|
||||
if request.ssl?
|
||||
"#{request.protocol}#{request.host_with_port}"
|
||||
@@ -397,7 +397,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_on_with_2_argument_object_asset_host
|
||||
ENV['RAILS_ASSET_ID'] = ''
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ''
|
||||
ActionController::Base.asset_host = Class.new do
|
||||
def call(source, request)
|
||||
if request.ssl?
|
||||
@@ -437,7 +437,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_on_and_using_subdirectory
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = 'http://a%d.example.com'
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -453,7 +453,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_with_all_and_recursive_puts_defaults_at_the_start_of_the_file
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = 'http://a0.example.com'
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -474,7 +474,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_with_all_puts_defaults_at_the_start_of_the_file
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = 'http://a0.example.com'
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -495,7 +495,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_with_relative_url_root
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.relative_url_root = "/collaboration/hieraki"
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -520,7 +520,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_javascript_include_tag_when_caching_off
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.perform_caching = false
|
||||
|
||||
assert_dom_equal(
|
||||
@@ -549,7 +549,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_stylesheet_link_tag_when_caching_on
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = 'http://a0.example.com'
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -581,7 +581,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_concat_stylesheet_link_tag_when_caching_off
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
|
||||
assert_dom_equal(
|
||||
%(<link href="/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css" />),
|
||||
@@ -611,7 +611,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -628,7 +628,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_stylesheet_link_tag_with_relative_url_root
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.relative_url_root = "/collaboration/hieraki"
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@@ -653,7 +653,7 @@ class AssetTagHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_caching_stylesheet_include_tag_when_caching_off
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper.rails_asset_id = ""
|
||||
ActionController::Base.perform_caching = false
|
||||
|
||||
assert_dom_equal(
|
||||
|
||||
@@ -1,79 +1,74 @@
|
||||
require 'active_support/base64'
|
||||
require 'active_support/deprecation'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
|
||||
module ActiveSupport
|
||||
# MessageVerifier makes it easy to generate and verify messages which are signed
|
||||
# +MessageVerifier+ makes it easy to generate and verify messages which are signed
|
||||
# to prevent tampering.
|
||||
#
|
||||
#
|
||||
# This is useful for cases like remember-me tokens and auto-unsubscribe links where the
|
||||
# session store isn't suitable or available.
|
||||
#
|
||||
# Remember Me:
|
||||
# cookies[:remember_me] = @verifier.generate([@user.id, 2.weeks.from_now])
|
||||
#
|
||||
#
|
||||
# In the authentication filter:
|
||||
#
|
||||
# id, time = @verifier.verify(cookies[:remember_me])
|
||||
# if time < Time.now
|
||||
# self.current_user = User.find(id)
|
||||
# end
|
||||
#
|
||||
#
|
||||
# By default it uses Marshal to serialize the message. If you want to use another
|
||||
# serialization method, you can set the serializer attribute to something that responds
|
||||
# to dump and load, e.g.:
|
||||
#
|
||||
# @verifier.serializer = YAML
|
||||
class MessageVerifier
|
||||
class InvalidSignature < StandardError; end
|
||||
|
||||
def initialize(secret, digest = 'SHA1')
|
||||
|
||||
def initialize(secret, options = {})
|
||||
unless options.is_a?(Hash)
|
||||
ActiveSupport::Deprecation.warn "The second parameter should be an options hash. Use :digest => 'algorithm' to specify the digest algorithm."
|
||||
options = { :digest => options }
|
||||
end
|
||||
|
||||
@secret = secret
|
||||
@digest = digest
|
||||
@digest = options[:digest] || 'SHA1'
|
||||
@serializer = options[:serializer] || Marshal
|
||||
end
|
||||
|
||||
|
||||
def verify(signed_message)
|
||||
raise InvalidSignature if signed_message.blank?
|
||||
|
||||
data, digest = signed_message.split("--")
|
||||
if data.present? && digest.present? && secure_compare(digest, generate_digest(data))
|
||||
Marshal.load(ActiveSupport::Base64.decode64(data))
|
||||
@serializer.load(::Base64.decode64(data))
|
||||
else
|
||||
raise InvalidSignature
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def generate(value)
|
||||
data = ActiveSupport::Base64.encode64s(Marshal.dump(value))
|
||||
data = ::Base64.strict_encode64(@serializer.dump(value))
|
||||
"#{data}--#{generate_digest(data)}"
|
||||
end
|
||||
|
||||
private
|
||||
if "foo".respond_to?(:force_encoding)
|
||||
# constant-time comparison algorithm to prevent timing attacks
|
||||
def secure_compare(a, b)
|
||||
a = a.dup.force_encoding(Encoding::BINARY)
|
||||
b = b.dup.force_encoding(Encoding::BINARY)
|
||||
|
||||
if a.length == b.length
|
||||
result = 0
|
||||
for i in 0..(a.length - 1)
|
||||
result |= a[i].ord ^ b[i].ord
|
||||
end
|
||||
result == 0
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
else
|
||||
# For <= 1.8.6
|
||||
def secure_compare(a, b)
|
||||
if a.length == b.length
|
||||
result = 0
|
||||
for i in 0..(a.length - 1)
|
||||
result |= a[i] ^ b[i]
|
||||
end
|
||||
result == 0
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
private
|
||||
# constant-time comparison algorithm to prevent timing attacks
|
||||
def secure_compare(a, b)
|
||||
return false unless a.bytesize == b.bytesize
|
||||
|
||||
l = a.unpack "C#{a.bytesize}"
|
||||
|
||||
res = 0
|
||||
b.each_byte { |byte| res |= byte ^ l.shift }
|
||||
res == 0
|
||||
end
|
||||
|
||||
def generate_digest(data)
|
||||
require 'openssl' unless defined?(OpenSSL)
|
||||
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), @secret, data)
|
||||
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class MessageVerifierTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
|
||||
@data = {:some=>"data", :now=>Time.now}
|
||||
begin
|
||||
require 'openssl'
|
||||
OpenSSL::Digest::SHA1
|
||||
rescue LoadError, NameError
|
||||
$stderr.puts "Skipping MessageVerifier test: broken OpenSSL install"
|
||||
else
|
||||
|
||||
require 'active_support/json'
|
||||
|
||||
class MessageVerifierTest < ActiveSupport::TestCase
|
||||
|
||||
class JSONSerializer
|
||||
def dump(value)
|
||||
ActiveSupport::JSON.encode(value)
|
||||
end
|
||||
|
||||
def load(value)
|
||||
ActiveSupport::JSON.decode(value)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
|
||||
@data = { :some => "data", :now => Time.local(2010) }
|
||||
end
|
||||
|
||||
def test_simple_round_tripping
|
||||
message = @verifier.generate(@data)
|
||||
assert_equal @data, @verifier.verify(message)
|
||||
end
|
||||
|
||||
|
||||
def test_missing_signature_raises
|
||||
assert_not_verified(nil)
|
||||
assert_not_verified("")
|
||||
@@ -23,9 +43,23 @@ class MessageVerifierTest < Test::Unit::TestCase
|
||||
assert_not_verified("purejunk")
|
||||
end
|
||||
|
||||
def test_alternative_serialization_method
|
||||
verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", :serializer => JSONSerializer.new)
|
||||
message = verifier.generate({ :foo => 123, 'bar' => Time.utc(2010) })
|
||||
assert_equal verifier.verify(message), { "foo" => 123, "bar" => "2010/01/01 00:00:00 +0000" }
|
||||
end
|
||||
|
||||
def test_digest_algorithm_as_second_parameter_deprecation
|
||||
assert_deprecated(/options hash/) do
|
||||
ActiveSupport::MessageVerifier.new("secret", "SHA1")
|
||||
end
|
||||
end
|
||||
|
||||
def assert_not_verified(message)
|
||||
assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do
|
||||
@verifier.verify(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user