From e6ac57ac3ac4ac78135a99416d44e75d817816d0 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 21 Aug 2021 16:02:35 +0100 Subject: [PATCH 1/3] Migrate session cookies to new setup Currently sessions set on (www.openfoodnetwork.xxx) are not usable on the bare domain (openfoonetwork.xxx). When transitioning from one to the other, the user's session is completely lost. This change means sessions on subdomains (including www) will be transferable. --- config/initializers/session_store.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index d301b88739d..f5e1ed786f1 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,10 +1,11 @@ # Be sure to restart your server when you modify this file. -# The cookie_store can be too small for very long URLs stored by Devise. -# The maximum size of cookies is 4096 bytes. -#Openfoodnetwork::Application.config.session_store :cookie_store, key: '_openfoodnetwork_session' - # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") -Openfoodnetwork::Application.config.session_store :active_record_store +Openfoodnetwork::Application.config.session_store( + :active_record_store, + key: "_ofn_session_id", + domain: :all, + tld_length: 2 +) From 1d472d0dec6f3ac1cec1b4e016534cba99536314 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 22 Aug 2021 15:42:37 +0100 Subject: [PATCH 2/3] Add Rack Middleware for transitioning existing sessions This checks if the current request has been submitted using the old session key (_session_id) and transparently migrates the session id to a new session cookie with the new settings and the new key (_ofn_session_id). --- config/application.rb | 11 ++++++++++- lib/session_cookie_upgrader.rb | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 lib/session_cookie_upgrader.rb diff --git a/config/application.rb b/config/application.rb index f54fca0e4f6..c835223d4e2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -21,9 +21,9 @@ end require_relative "../lib/open_food_network/i18n_config" - require_relative '../lib/spree/core/environment' require_relative '../lib/spree/core/mail_interceptor' +require_relative "../lib/session_cookie_upgrader" if defined?(Bundler) # If you precompile assets before deploying to production, use this line @@ -34,6 +34,15 @@ module Openfoodnetwork class Application < Rails::Application + config.middleware.insert_before( + ActionDispatch::Cookies, + SessionCookieUpgrader, { + old_key: "_session_id", + new_key: "_ofn_session_id", + domain: "." + ENV["SITE_URL"].delete_prefix("www.") + } + ) if Rails.env.staging? || Rails.env.production? + config.after_initialize do # We need this here because the test env file loads before the Spree engine is loaded Spree::Core::Engine.routes.default_url_options[:host] = 'test.host' if Rails.env == 'test' diff --git a/lib/session_cookie_upgrader.rb b/lib/session_cookie_upgrader.rb new file mode 100644 index 00000000000..feb24807601 --- /dev/null +++ b/lib/session_cookie_upgrader.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class SessionCookieUpgrader + def initialize(app, options = {}) + @app = app + @options = options + end + + def call(env) + request = ::Rack::Request.new(env) + cookies = request.cookies + old_key = @options[:old_key] + new_key = @options[:new_key] + + # Set the session id for this request from the old session cookie (if present) + # This must be done before @app.call(env) or a new session will be initialized + cookies[new_key] = cookies[old_key] if cookies[old_key] + + status, headers, body = @app.call(env) + + if cookies[old_key] + # Create new session cookie with pre-existing session id + Rack::Utils.set_cookie_header!( + headers, + new_key, + { value: cookies[old_key], path: "/", domain: @options[:domain] } + ) + + # Delete old session cookie + Rack::Utils.delete_cookie_header!(headers, old_key) + end + + [status, headers, body] + end +end From 39372f7bd7ca309a42cdd6b605961c0e05262041 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 22 Aug 2021 15:43:30 +0100 Subject: [PATCH 3/3] Update cookies policy notes and related spec The session cookie is now named `_ofn_session_id` instead of `_session_id`. --- .../app/views/web/angular_templates/cookies_policy.html.haml | 2 +- engines/web/spec/features/consumer/cookies_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/web/app/views/web/angular_templates/cookies_policy.html.haml b/engines/web/app/views/web/angular_templates/cookies_policy.html.haml index 4b00ac32f12..385262ae746 100644 --- a/engines/web/app/views/web/angular_templates/cookies_policy.html.haml +++ b/engines/web/app/views/web/angular_templates/cookies_policy.html.haml @@ -13,7 +13,7 @@ = t 'legal.cookies_policy.essential_cookies_desc' %table{ng: { controller:"CookiesPolicyModalCtrl"}} - = render_cookie_entry( "_session_id", t( "legal.cookies_policy.cookie_session_desc" ) ) + = render_cookie_entry( "_ofn_session_id", t( "legal.cookies_policy.cookie_session_desc" ) ) = render_cookie_entry( "cookies_consent", t( "legal.cookies_policy.cookie_consent_desc" ) ) = render_cookie_entry( "remember_spree_user_token", t( "legal.cookies_policy.cookie_remember_me_desc" ) ) = render_cookie_entry( "qos_token", t( "legal.cookies_policy.cookie_openstreemap_desc" ), "openstreetmap.org" ) diff --git a/engines/web/spec/features/consumer/cookies_spec.rb b/engines/web/spec/features/consumer/cookies_spec.rb index e447364fe20..48c1845b840 100644 --- a/engines/web/spec/features/consumer/cookies_spec.rb +++ b/engines/web/spec/features/consumer/cookies_spec.rb @@ -79,7 +79,7 @@ scenario "shows session_id cookies description with correct instance domain" do visit '/#/policies/cookies' - expect(page).to have_content('_session_id') + expect(page).to have_content('_ofn_session_id') .and have_content('127.0.0.1') end