summaryrefslogtreecommitdiff
path: root/app/controllers/concerns
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r--app/controllers/concerns/floc_opt_out.rb2
-rw-r--r--app/controllers/concerns/issuable_actions.rb14
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb2
-rw-r--r--app/controllers/concerns/membership_actions.rb15
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb27
-rw-r--r--app/controllers/concerns/search_rate_limitable.rb15
-rw-r--r--app/controllers/concerns/sessionless_authentication.rb3
-rw-r--r--app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb11
-rw-r--r--app/controllers/concerns/spammable_actions/attributes.rb13
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/common.rb32
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb5
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb11
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb39
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
14 files changed, 130 insertions, 61 deletions
diff --git a/app/controllers/concerns/floc_opt_out.rb b/app/controllers/concerns/floc_opt_out.rb
index 3039af02bbb..50a52cecda9 100644
--- a/app/controllers/concerns/floc_opt_out.rb
+++ b/app/controllers/concerns/floc_opt_out.rb
@@ -4,7 +4,7 @@ module FlocOptOut
extend ActiveSupport::Concern
included do
- after_action :set_floc_opt_out_header, unless: :floc_enabled?
+ before_action :set_floc_opt_out_header, unless: :floc_enabled?
end
def floc_enabled?
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index eae087bca4d..ae90bd59d01 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -17,10 +17,6 @@ module IssuableActions
def show
respond_to do |format|
format.html do
- @show_crm_contacts = issuable.is_a?(Issue) && # rubocop:disable Gitlab/ModuleWithInstanceVariables
- can?(current_user, :read_crm_contact, issuable.project.group) &&
- CustomerRelations::Contact.exists_for_group?(issuable.project.group)
-
@issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables
render 'show'
end
@@ -43,18 +39,18 @@ module IssuableActions
if updated_issuable.is_a?(Spammable)
respond_to do |format|
format.html do
- # NOTE: This redirect is intentionally only performed in the case where the updated
- # issuable is a spammable, and intentionally is not performed in the non-spammable case.
- # This preserves the legacy behavior of this action.
if updated_issuable.valid?
+ # NOTE: This redirect is intentionally only performed in the case where the valid updated
+ # issuable is a spammable, and intentionally is not performed below in the
+ # valid non-spammable case. This preserves the legacy behavior of this action.
redirect_to spammable_path
else
- with_captcha_check_html_format { render :edit }
+ with_captcha_check_html_format(spammable: spammable) { render :edit }
end
end
format.json do
- with_captcha_check_json_format { render_entity_json }
+ with_captcha_check_json_format(spammable: spammable) { render_entity_json }
end
end
else
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index b68db0e3f9f..96cf6021ea9 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -17,7 +17,7 @@ module IssuableCollectionsAction
respond_to do |format|
format.html
- format.atom { render layout: 'xml.atom' }
+ format.atom { render layout: 'xml' }
end
end
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index f716c1f6c2f..0b9024dc3db 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -4,17 +4,6 @@ module MembershipActions
include MembersPresentation
extend ActiveSupport::Concern
- def create
- create_params = params.permit(:user_ids, :access_level, :expires_at)
- result = Members::CreateService.new(current_user, create_params.merge({ source: membershipable, invite_source: "#{plain_source_type}-members-page" })).execute
-
- if result[:status] == :success
- redirect_to members_page_url, notice: _('Users were successfully added.')
- else
- redirect_to members_page_url, alert: result[:message]
- end
- end
-
def update
update_params = params.require(root_params_key).permit(:access_level, :expires_at)
member = membershipable.members_and_requesters.find(params[:id])
@@ -79,8 +68,8 @@ module MembershipActions
notice: _('Your request for access has been queued for review.')
else
redirect_to polymorphic_path(membershipable),
- alert: _("Your request for access could not be processed: %{error_meesage}") %
- { error_meesage: access_requester.errors.full_messages.to_sentence }
+ alert: _("Your request for access could not be processed: %{error_message}") %
+ { error_message: access_requester.errors.full_messages.to_sentence }
end
end
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
new file mode 100644
index 00000000000..03296d6b233
--- /dev/null
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ProductAnalyticsTracking
+ include Gitlab::Tracking::Helpers
+ include RedisTracking
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def track_event(*controller_actions, name:, conditions: nil, destinations: [:redis_hll], &block)
+ custom_conditions = [:trackable_html_request?, *conditions]
+
+ after_action only: controller_actions, if: custom_conditions do
+ route_events_to(destinations, name, &block)
+ end
+ end
+ end
+
+ private
+
+ def route_events_to(destinations, name, &block)
+ track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll)
+
+ if destinations.include?(:snowplow) && Feature.enabled?(:route_hll_to_snowplow, tracking_namespace_source, default_enabled: :yaml)
+ Gitlab::Tracking.event(self.class.to_s, name, namespace: tracking_namespace_source, user: current_user)
+ end
+ end
+end
diff --git a/app/controllers/concerns/search_rate_limitable.rb b/app/controllers/concerns/search_rate_limitable.rb
new file mode 100644
index 00000000000..a77ebd276b6
--- /dev/null
+++ b/app/controllers/concerns/search_rate_limitable.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module SearchRateLimitable
+ extend ActiveSupport::Concern
+
+ private
+
+ def check_search_rate_limit!
+ if current_user
+ check_rate_limit!(:search_rate_limit, scope: [current_user])
+ else
+ check_rate_limit!(:search_rate_limit_unauthenticated, scope: [request.ip])
+ end
+ end
+end
diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb
index 1f17f9f4e1b..48daacc09c2 100644
--- a/app/controllers/concerns/sessionless_authentication.rb
+++ b/app/controllers/concerns/sessionless_authentication.rb
@@ -26,6 +26,9 @@ module SessionlessAuthentication
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in(user, store: false, message: :sessionless_sign_in)
+ elsif request_authenticator.can_sign_in_bot?(user)
+ # we suppress callbacks to avoid redirecting the bot
+ sign_in(user, store: false, message: :sessionless_sign_in, run_callbacks: false)
end
end
diff --git a/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb b/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
index 234c591ffb7..044519004b2 100644
--- a/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
+++ b/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
@@ -2,7 +2,6 @@
module SpammableActions::AkismetMarkAsSpamAction
extend ActiveSupport::Concern
- include SpammableActions::Attributes
included do
before_action :authorize_submit_spammable!, only: :mark_as_spam
@@ -22,7 +21,15 @@ module SpammableActions::AkismetMarkAsSpamAction
access_denied! unless current_user.can_admin_all_resources?
end
+ def spammable
+ # The class extending this module should define the #spammable method to return
+ # the Spammable model instance via: `alias_method :spammable , <:model_name>`
+ raise NotImplementedError, "#{self.class} should implement #{__method__}"
+ end
+
def spammable_path
- raise NotImplementedError, "#{self.class} does not implement #{__method__}"
+ # The class extending this module should define the #spammable_path method to return
+ # the route helper pointing to the action to show the Spammable instance
+ raise NotImplementedError, "#{self.class} should implement #{__method__}"
end
end
diff --git a/app/controllers/concerns/spammable_actions/attributes.rb b/app/controllers/concerns/spammable_actions/attributes.rb
deleted file mode 100644
index d7060e47c07..00000000000
--- a/app/controllers/concerns/spammable_actions/attributes.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module SpammableActions
- module Attributes
- extend ActiveSupport::Concern
-
- private
-
- def spammable
- raise NotImplementedError, "#{self.class} does not implement #{__method__}"
- end
- end
-end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/common.rb b/app/controllers/concerns/spammable_actions/captcha_check/common.rb
index 7c047e02a1d..aaeb6b3ba83 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/common.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/common.rb
@@ -1,23 +1,25 @@
# frozen_string_literal: true
-module SpammableActions::CaptchaCheck
- module Common
- extend ActiveSupport::Concern
+module SpammableActions
+ module CaptchaCheck
+ module Common
+ extend ActiveSupport::Concern
- private
+ private
- def with_captcha_check_common(captcha_render_lambda:, &block)
- # If the Spammable indicates that CAPTCHA is not necessary (either due to it not being flagged
- # as spam, or if spam/captcha is disabled for some reason), then we will go ahead and
- # yield to the block containing the action's original behavior, then return.
- return yield unless spammable.render_recaptcha?
+ def with_captcha_check_common(spammable:, captcha_render_lambda:, &block)
+ # If the Spammable indicates that CAPTCHA is not necessary (either due to it not being flagged
+ # as spam, or if spam/captcha is disabled for some reason), then we will go ahead and
+ # yield to the block containing the action's original behavior, then return.
+ return yield unless spammable.render_recaptcha?
- # If we got here, we need to render the CAPTCHA instead of yielding to action's original
- # behavior. We will present a CAPTCHA to be solved by executing the lambda which was passed
- # as the `captcha_render_lambda:` argument. This lambda contains either the HTML-specific or
- # JSON-specific behavior to cause the CAPTCHA modal to be rendered.
- Gitlab::Recaptcha.load_configurations!
- captcha_render_lambda.call
+ # If we got here, we need to render the CAPTCHA instead of yielding to action's original
+ # behavior. We will present a CAPTCHA to be solved by executing the lambda which was passed
+ # as the `captcha_render_lambda:` argument. This lambda contains either the HTML-specific or
+ # JSON-specific behavior to cause the CAPTCHA modal to be rendered.
+ Gitlab::Recaptcha.load_configurations!
+ captcha_render_lambda.call
+ end
end
end
end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
index f687c0fcf2d..b254916cdd6 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
@@ -8,7 +8,6 @@
# which supports JSON format should be used instead.
module SpammableActions::CaptchaCheck::HtmlFormatActionsSupport
extend ActiveSupport::Concern
- include SpammableActions::Attributes
include SpammableActions::CaptchaCheck::Common
included do
@@ -17,9 +16,9 @@ module SpammableActions::CaptchaCheck::HtmlFormatActionsSupport
private
- def with_captcha_check_html_format(&block)
+ def with_captcha_check_html_format(spammable:, &block)
captcha_render_lambda = -> { render :captcha_check }
- with_captcha_check_common(captcha_render_lambda: captcha_render_lambda, &block)
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
end
# Convert spam/CAPTCHA values from form field params to headers, because all spam-related services
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
index 0bfea05abc7..4a278a7b233 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
@@ -4,22 +4,27 @@
# In other words, forms handled by actions which use a `respond_to` of `format.js` or `format.json`.
#
# For example, for all Javascript based form submissions and Vue components which use Apollo and Axios
+# which are directly handled by a controller other than `GraphqlController`. For example, issue
+# update currently uses this module.
+#
+# However, requests which directly hit `GraphqlController` will not use this module - the
+# `Mutations::SpamProtection` module handles those requests (for example, snippet create/update
+# requests)
#
# If the request is handled by actions via `format.html`, then the corresponding module which
# supports HTML format should be used instead.
module SpammableActions::CaptchaCheck::JsonFormatActionsSupport
extend ActiveSupport::Concern
- include SpammableActions::Attributes
include SpammableActions::CaptchaCheck::Common
include Spam::Concerns::HasSpamActionResponseFields
private
- def with_captcha_check_json_format(&block)
+ def with_captcha_check_json_format(spammable:, &block)
# NOTE: "409 - Conflict" seems to be the most appropriate HTTP status code for a response
# which requires a CAPTCHA to be solved in order for the request to be resubmitted.
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
captcha_render_lambda = -> { render json: spam_action_response_fields(spammable), status: :conflict }
- with_captcha_check_common(captcha_render_lambda: captcha_render_lambda, &block)
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
end
end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb
new file mode 100644
index 00000000000..2ebfa90e6da
--- /dev/null
+++ b/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# This module should be included to support CAPTCHA check for REST API actions via Grape.
+#
+# If the request is directly handled by a controller action, then the corresponding module which
+# supports HTML or JSON formats should be used instead.
+module SpammableActions::CaptchaCheck::RestApiActionsSupport
+ extend ActiveSupport::Concern
+ include SpammableActions::CaptchaCheck::Common
+ include Spam::Concerns::HasSpamActionResponseFields
+
+ private
+
+ def with_captcha_check_rest_api(spammable:, &block)
+ # In the case of the REST API, the request is handled by Grape, so if there is a spam-related
+ # error, we don't render directly, instead we will pass the error message and other necessary
+ # fields to the Grape api error helper for it to handle.
+ captcha_render_lambda = -> do
+ fields = spam_action_response_fields(spammable)
+
+ fields.delete :spam
+ # NOTE: "409 - Conflict" seems to be the most appropriate HTTP status code for a response
+ # which requires a CAPTCHA to be solved in order for the request to be resubmitted.
+ # https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
+ status = 409
+
+ # NOTE: This nested 'error' key may not be consistent with all other API error responses,
+ # because they are not currently consistent across different API endpoints
+ # and models. Some (snippets) will nest errors in an errors key like this,
+ # while others (issues) will return the model's errors hash without an errors key,
+ # while still others just return a plain string error.
+ # See https://gitlab.com/groups/gitlab-org/-/epics/5527#revisit-inconsistent-shape-of-error-responses-in-rest-api
+ fields[:message] = { error: spammable.errors.full_messages.to_sentence }
+ render_structured_api_error!(fields, status)
+ end
+
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
+ end
+end
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index e1bfe92f61b..c9b6e8923fe 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -143,7 +143,7 @@ module UploadsActions
end
def bypass_auth_checks_on_uploads?
- if ::Feature.enabled?(:enforce_auth_checks_on_uploads, default_enabled: :yaml)
+ if ::Feature.enabled?(:enforce_auth_checks_on_uploads, project, default_enabled: :yaml)
false
else
action_name == 'show' && embeddable?