diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 85602aa72deb31eb32e58462010e51ad4816b259..13b226a6a7106ac4766e4aeafb2b7fbd6aaf120f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -20,11 +20,11 @@ class ApplicationController < ActionController::Base before_action :authenticate_user!, except: [:route_not_found] before_action :enforce_terms!, if: :should_enforce_terms? before_action :validate_user_service_ticket! - before_action :check_password_expiration + before_action :check_password_expiration, if: :html_request? before_action :ldap_security_check before_action :sentry_context before_action :default_headers - before_action :add_gon_variables, unless: [:peek_request?, :json_request?] + before_action :add_gon_variables, if: :html_request? before_action :configure_permitted_parameters, if: :devise_controller? before_action :require_email, unless: :devise_controller? before_action :active_user_check, unless: :devise_controller? @@ -455,8 +455,8 @@ def set_page_title_header response.headers['Page-Title'] = URI.escape(page_title('GitLab')) end - def peek_request? - request.path.start_with?('/-/peek') + def html_request? + request.format.html? end def json_request? @@ -466,7 +466,7 @@ def json_request? def should_enforce_terms? return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms - !(peek_request? || devise_controller?) + html_request? && !devise_controller? end def set_usage_stats_consent_flag diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb index 86df0010665367e70f473ce63d48efd1bc4c82d7..32e1a46e580ffee8ea3364089620cf23ae1ab541 100644 --- a/app/controllers/concerns/confirm_email_warning.rb +++ b/app/controllers/concerns/confirm_email_warning.rb @@ -4,15 +4,18 @@ module ConfirmEmailWarning extend ActiveSupport::Concern included do - before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) } + before_action :set_confirm_warning, if: :show_confirm_warning? end protected + def show_confirm_warning? + html_request? && request.get? && Feature.enabled?(:soft_email_confirmation) + end + def set_confirm_warning return unless current_user return if current_user.confirmed? - return if peek_request? || json_request? || !request.get? email = current_user.unconfirmed_email || current_user.email diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index b87779c22d316da2f2f01f8573228a263fd59621..023c41821da1bf20d252d6c7cbcadd709e0aa662 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -1,11 +1,16 @@ # frozen_string_literal: true module UploadsActions + extend ActiveSupport::Concern include Gitlab::Utils::StrongMemoize include SendFileUpload UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze + included do + prepend_before_action :set_request_format_from_path_extension + end + def create uploader = UploadService.new(model, params[:file], uploader_class).execute @@ -64,6 +69,18 @@ def authorize private + # From ActionDispatch::Http::MimeNegotiation. We have an initializer that + # monkey-patches this method out (so that repository paths don't guess a + # format based on extension), but we do want this behaviour when serving + # uploads. + def set_request_format_from_path_extension + path = request.headers['action_dispatch.original_path'] || request.headers['PATH_INFO'] + + if match = path&.match(/\.(\w+)\z/) + request.format = match.captures.first + end + end + def uploader_class raise NotImplementedError end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index bb7f5ec2b28fa1b6f9d3ca2a97138eca6b2f3ad3..7893b0812c77f68c151935ce911fc609bda41853 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -90,14 +90,6 @@ def index let(:format) { :html } it_behaves_like 'setting gon variables' - - context 'for peek requests' do - before do - request.path = '/-/peek' - end - - it_behaves_like 'not setting gon variables' - end end context 'with json format' do @@ -105,6 +97,12 @@ def index it_behaves_like 'not setting gon variables' end + + context 'with atom format' do + let(:format) { :atom } + + it_behaves_like 'not setting gon variables' + end end describe 'session expiration' do diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 1bcf3bb106b86c342a4734cd17e5ba3c4cc08368..f35babc1b56361025552e4d1252cb2106ebff5f8 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -228,10 +228,10 @@ user.block end - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end @@ -320,10 +320,10 @@ end context "when not signed in" do - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end @@ -343,10 +343,10 @@ project.add_maintainer(user) end - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end @@ -439,10 +439,10 @@ user.block end - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end @@ -526,10 +526,10 @@ end context "when not signed in" do - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end @@ -549,10 +549,10 @@ project.add_maintainer(user) end - it "redirects to the sign in page" do + it "responds with status 401" do get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" } - expect(response).to redirect_to(new_user_session_path) + expect(response).to have_gitlab_http_status(401) end end diff --git a/spec/requests/user_avatar_spec.rb b/spec/requests/user_avatar_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9451674161c9dd376da7e5bcf90cb9caa2b3d76f --- /dev/null +++ b/spec/requests/user_avatar_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Loading a user avatar' do + let(:user) { create(:user, :with_avatar) } + + context 'when logged in' do + # The exact query count will vary depending on the 2FA settings of the + # instance, group, and user. Removing those extra 2FA queries in this case + # may not be a good idea, so we just set up the ideal case. + before do + stub_application_setting(require_two_factor_authentication: true) + + login_as(create(:user, :two_factor)) + end + + # One each for: current user, avatar user, and upload record + it 'only performs three SQL queries' do + get user.avatar_url # Skip queries on first application load + + expect(response).to have_gitlab_http_status(200) + expect { get user.avatar_url }.not_to exceed_query_limit(3) + end + end + + context 'when logged out' do + # One each for avatar user and upload record + it 'only performs two SQL queries' do + get user.avatar_url # Skip queries on first application load + + expect(response).to have_gitlab_http_status(200) + expect { get user.avatar_url }.not_to exceed_query_limit(2) + end + end +end