From 5f37e16ab5fb36555175379ad96b2da3c3b31a0b Mon Sep 17 00:00:00 2001 From: Assain Date: Mon, 14 Aug 2017 19:16:58 +0530 Subject: freshen :expires option with duration support and add expiry metadata to cookies --- .../lib/action_dispatch/middleware/cookies.rb | 18 ++++++++++-- actionpack/test/dispatch/cookies_test.rb | 32 ++++++++++++++++++++++ .../test/dispatch/session/cookie_store_test.rb | 9 ++++-- 3 files changed, 54 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 5a55ee13ee..c0913715ac 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -360,7 +360,11 @@ module ActionDispatch @cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; " end - def handle_options(options) #:nodoc: + def handle_options(options) # :nodoc: + if options[:expires].respond_to?(:from_now) + options[:expires] = options[:expires].from_now + end + options[:path] ||= "/" if options[:domain] == :all || options[:domain] == "all" @@ -488,6 +492,14 @@ module ActionDispatch def request; @parent_jar.request; end private + def expiry_options(options) + if options[:expires].respond_to?(:from_now) + { expires_in: options[:expires] } + else + { expires_at: options[:expires] } + end + end + def parse(name, data); data; end def commit(options); end end @@ -569,7 +581,7 @@ module ActionDispatch end def commit(options) - options[:value] = @verifier.generate(serialize(options[:value])) + options[:value] = @verifier.generate(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end @@ -609,7 +621,7 @@ module ActionDispatch end def commit(options) - options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value])) + options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index a551fb00a8..cb225c0f62 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -278,6 +278,11 @@ class CookiesTest < ActionController::TestCase def encrypted_cookie cookies.encrypted["foo"] end + + def cookie_expires_in_two_hours + cookies[:user_name] = { value: "assain", expires: 2.hours } + head :ok + end end tests TestController @@ -1235,6 +1240,33 @@ class CookiesTest < ActionController::TestCase assert_equal "bar", @controller.encrypted_cookie end + def test_signed_cookie_with_expires_set_relatively + cookies.signed[:user_name] = { value: "assain", expires: 2.hours } + + travel 1.hour + assert_equal "assain", cookies.signed[:user_name] + + travel 2.hours + assert_nil cookies.signed[:user_name] + end + + def test_encrypted_cookie_with_expires_set_relatively + cookies.encrypted[:user_name] = { value: "assain", expires: 2.hours } + + travel 1.hour + assert_equal "assain", cookies.encrypted[:user_name] + + travel 2.hours + assert_nil cookies.encrypted[:user_name] + end + + def test_vanilla_cookie_with_expires_set_relatively + travel_to Time.utc(2017, 8, 15) do + get :cookie_expires_in_two_hours + assert_cookie_header "user_name=assain; path=/; expires=Tue, 15 Aug 2017 02:00:00 -0000" + end + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 26a63c9f7d..6517cf4c99 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -26,6 +26,11 @@ class CookieStoreTest < ActionDispatch::IntegrationTest render plain: Rack::Utils.escape(Verifier.generate(session.to_hash)) end + def set_session_value_expires_in_five_hours + session[:foo] = "bar" + render plain: Rack::Utils.escape(Verifier.generate(session.to_hash, expires_in: 5.hours)) + end + def get_session_value render plain: "foo: #{session[:foo].inspect}" end @@ -283,7 +288,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest cookies[SessionKey] = SignedBar - get "/set_session_value" + get "/set_session_value_expires_in_five_hours" assert_response :success cookie_body = response.body @@ -299,7 +304,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest get "/no_session_access" assert_response :success - assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", + assert_equal "_myapp_session=#{cookies[SessionKey]}; path=/; expires=#{expected_expiry}; HttpOnly", headers["Set-Cookie"] end end -- cgit v1.2.3