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] 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 f54fca0e4f..c835223d4e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -21,9 +21,9 @@ require "rails" 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 @@ end 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 0000000000..feb2480760 --- /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