diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b241dede09..e19c9bb26b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -55,17 +55,32 @@ class ApplicationController < ActionController::Base end def enable_embedded_shopfront - whitelist = Spree::Config[:embedded_shopfronts_whitelist] - return unless Spree::Config[:enable_embedded_shopfronts] && whitelist.present? - return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development? + return unless embeddable? + return if embedding_without_https? response.headers.delete 'X-Frame-Options' - response.headers['Content-Security-Policy'] = "frame-ancestors #{whitelist}" + response.headers['Content-Security-Policy'] = "frame-ancestors #{embedded_shopfront_referer}" check_embedded_request set_embedded_layout end + def embedded_shopfront_referer + return if request.referer.blank? + domain = URI(request.referer).host.downcase + domain.start_with?('www.') ? domain[4..-1] : domain + end + + def embeddable? + whitelist = Spree::Config[:embedded_shopfronts_whitelist] + domain = embedded_shopfront_referer + Spree::Config[:enable_embedded_shopfronts] && whitelist.present? && domain.present? && whitelist.include?(domain) + end + + def embedding_without_https? + request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development? + end + def check_embedded_request return unless params[:embedded_shopfront] diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 12770fc070..deb79a5ad2 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -22,9 +22,10 @@ feature "Using embedded shopfront functionality", js: true do add_variant_to_order_cycle(exchange, variant) Spree::Config[:enable_embedded_shopfronts] = true - Spree::Config[:embedded_shopfronts_whitelist] = 'localhost' + Spree::Config[:embedded_shopfronts_whitelist] = 'test.com' page.driver.browser.js_errors = false + allow_any_instance_of(ActionDispatch::Request).to receive(:referer).and_return('https://www.test.com') Capybara.current_session.driver.visit('spec/support/views/iframe_test.html') end diff --git a/spec/requests/embedded_shopfronts_headers_spec.rb b/spec/requests/embedded_shopfronts_headers_spec.rb index a991d7362c..8056946f23 100644 --- a/spec/requests/embedded_shopfronts_headers_spec.rb +++ b/spec/requests/embedded_shopfronts_headers_spec.rb @@ -43,16 +43,19 @@ describe "setting response headers for embedded shopfronts", type: :request do context "with a valid whitelist" do before do - Spree::Config[:embedded_shopfronts_whitelist] = "test.com" + Spree::Config[:embedded_shopfronts_whitelist] = "example.com external-site.com" + allow_any_instance_of(ActionDispatch::Request).to receive(:referer).and_return('http://www.external-site.com/shop?embedded_shopfront=true') end it "allows iframes on certain pages when enabled in configuration" do get shops_path + expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to be_nil - expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors test.com" + expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors external-site.com" get spree.admin_path + expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to eq 'DENY' expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors 'none'"