Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 18:40:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 18:40:28 +0300
commitb595cb0c1dec83de5bdee18284abe86614bed33b (patch)
tree8c3d4540f193c5ff98019352f554e921b3a41a72 /app/controllers/concerns
parent2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff)
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r--app/controllers/concerns/google_analytics_csp.rb24
-rw-r--r--app/controllers/concerns/harbor/access.rb27
-rw-r--r--app/controllers/concerns/harbor/artifact.rb41
-rw-r--r--app/controllers/concerns/harbor/repository.rb51
-rw-r--r--app/controllers/concerns/harbor/tag.rb41
-rw-r--r--app/controllers/concerns/integrations/hooks_execution.rb60
-rw-r--r--app/controllers/concerns/integrations/params.rb1
-rw-r--r--app/controllers/concerns/issuable_actions.rb1
-rw-r--r--app/controllers/concerns/issuable_collections.rb11
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb5
-rw-r--r--app/controllers/concerns/verifies_with_email.rb194
11 files changed, 444 insertions, 12 deletions
diff --git a/app/controllers/concerns/google_analytics_csp.rb b/app/controllers/concerns/google_analytics_csp.rb
new file mode 100644
index 00000000000..1a8e405928d
--- /dev/null
+++ b/app/controllers/concerns/google_analytics_csp.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module GoogleAnalyticsCSP
+ extend ActiveSupport::Concern
+
+ included do
+ content_security_policy do |policy|
+ next unless helpers.google_tag_manager_enabled? || policy.directives.present?
+
+ default_script_src = policy.directives['script-src'] || policy.directives['default-src']
+ script_src_values = Array.wrap(default_script_src) | ['*.googletagmanager.com']
+ policy.script_src(*script_src_values)
+
+ default_img_src = policy.directives['img-src'] || policy.directives['default-src']
+ img_src_values = Array.wrap(default_img_src) | ['*.google-analytics.com', '*.googletagmanager.com']
+ policy.img_src(*img_src_values)
+
+ default_connect_src = policy.directives['connect-src'] || policy.directives['default-src']
+ connect_src_values =
+ Array.wrap(default_connect_src) | ['*.google-analytics.com', '*.analytics.google.com', '*.googletagmanager.com']
+ policy.connect_src(*connect_src_values)
+ end
+ end
+end
diff --git a/app/controllers/concerns/harbor/access.rb b/app/controllers/concerns/harbor/access.rb
new file mode 100644
index 00000000000..70de72f15fc
--- /dev/null
+++ b/app/controllers/concerns/harbor/access.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Harbor
+ module Access
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :harbor_registry_enabled!
+ before_action :authorize_read_harbor_registry!
+ before_action do
+ push_frontend_feature_flag(:harbor_registry_integration)
+ end
+
+ feature_category :integrations
+ end
+
+ private
+
+ def harbor_registry_enabled!
+ render_404 unless Feature.enabled?(:harbor_registry_integration)
+ end
+
+ def authorize_read_harbor_registry!
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/app/controllers/concerns/harbor/artifact.rb b/app/controllers/concerns/harbor/artifact.rb
new file mode 100644
index 00000000000..c9d7d26fbb9
--- /dev/null
+++ b/app/controllers/concerns/harbor/artifact.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Harbor
+ module Artifact
+ def index
+ respond_to do |format|
+ format.json do
+ artifacts
+ end
+ end
+ end
+
+ private
+
+ def query_params
+ params.permit(:repository_id, :search, :sort, :page, :limit)
+ end
+
+ def query
+ Gitlab::Harbor::Query.new(container.harbor_integration, query_params)
+ end
+
+ def artifacts
+ unless query.valid?
+ return render(
+ json: { message: 'Invalid parameters', errors: query.errors },
+ status: :unprocessable_entity
+ )
+ end
+
+ artifacts_json = ::Integrations::HarborSerializers::ArtifactSerializer.new
+ .with_pagination(request, response)
+ .represent(query.artifacts)
+ render json: artifacts_json
+ end
+
+ def container
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/app/controllers/concerns/harbor/repository.rb b/app/controllers/concerns/harbor/repository.rb
new file mode 100644
index 00000000000..0e541e2172e
--- /dev/null
+++ b/app/controllers/concerns/harbor/repository.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Harbor
+ module Repository
+ def index
+ respond_to do |format|
+ format.html
+ format.json do
+ repositories
+ end
+ end
+ end
+
+ # The show action renders index to allow frontend routing to work on page refresh
+ def show
+ render :index
+ end
+
+ private
+
+ def query_params
+ params.permit(:search, :sort, :page, :limit)
+ end
+
+ def query
+ Gitlab::Harbor::Query.new(container.harbor_integration, query_params)
+ end
+
+ def repositories
+ unless query.valid?
+ return render(
+ json: { message: 'Invalid parameters', errors: query.errors },
+ status: :unprocessable_entity
+ )
+ end
+
+ repositories_json = ::Integrations::HarborSerializers::RepositorySerializer.new
+ .with_pagination(request, response)
+ .represent(
+ query.repositories,
+ url: container.harbor_integration.url,
+ project_name: container.harbor_integration.project_name
+ )
+ render json: repositories_json
+ end
+
+ def container
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/app/controllers/concerns/harbor/tag.rb b/app/controllers/concerns/harbor/tag.rb
new file mode 100644
index 00000000000..e0c00d1155a
--- /dev/null
+++ b/app/controllers/concerns/harbor/tag.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Harbor
+ module Tag
+ def index
+ respond_to do |format|
+ format.json do
+ tags
+ end
+ end
+ end
+
+ private
+
+ def query_params
+ params.permit(:repository_id, :artifact_id, :sort, :page, :limit)
+ end
+
+ def query
+ Gitlab::Harbor::Query.new(container.harbor_integration, query_params)
+ end
+
+ def tags
+ unless query.valid?
+ return render(
+ json: { message: 'Invalid parameters', errors: query.errors },
+ status: :unprocessable_entity
+ )
+ end
+
+ tags_json = ::Integrations::HarborSerializers::TagSerializer.new
+ .with_pagination(request, response)
+ .represent(query.tags)
+ render json: tags_json
+ end
+
+ def container
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/app/controllers/concerns/integrations/hooks_execution.rb b/app/controllers/concerns/integrations/hooks_execution.rb
index 6a9d3d51f9b..fb26840168f 100644
--- a/app/controllers/concerns/integrations/hooks_execution.rb
+++ b/app/controllers/concerns/integrations/hooks_execution.rb
@@ -3,8 +3,68 @@
module Integrations::HooksExecution
extend ActiveSupport::Concern
+ included do
+ attr_writer :hooks, :hook
+ end
+
+ def index
+ self.hooks = relation.select(&:persisted?)
+ self.hook = relation.new
+ end
+
+ def create
+ self.hook = relation.new(hook_params)
+ hook.save
+
+ unless hook.valid?
+ self.hooks = relation.select(&:persisted?)
+ flash[:alert] = hook.errors.full_messages.join.html_safe
+ end
+
+ redirect_to action: :index
+ end
+
+ def update
+ if hook.update(hook_params)
+ flash[:notice] = _('Hook was successfully updated.')
+ redirect_to action: :index
+ else
+ render 'edit'
+ end
+ end
+
+ def destroy
+ destroy_hook(hook)
+
+ redirect_to action: :index, status: :found
+ end
+
+ def edit
+ redirect_to(action: :index) unless hook
+ end
+
private
+ def hook_params
+ permitted = hook_param_names + trigger_values
+ permitted << { url_variables: [:key, :value] }
+
+ ps = params.require(:hook).permit(*permitted).to_h
+
+ ps[:url_variables] = ps[:url_variables].to_h { [_1[:key], _1[:value].presence] } if ps.key?(:url_variables)
+
+ if action_name == 'update' && ps.key?(:url_variables)
+ supplied = ps[:url_variables]
+ ps[:url_variables] = hook.url_variables.merge(supplied).compact
+ end
+
+ ps
+ end
+
+ def hook_param_names
+ %i[enable_ssl_verification token url push_events_branch_filter]
+ end
+
def destroy_hook(hook)
result = WebHooks::DestroyService.new(current_user).execute(hook)
diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb
index d256b331174..c3ad9d3dff3 100644
--- a/app/controllers/concerns/integrations/params.rb
+++ b/app/controllers/concerns/integrations/params.rb
@@ -6,7 +6,6 @@ module Integrations
ALLOWED_PARAMS_CE = [
:active,
- :add_pusher,
:alert_events,
:api_key,
:api_token,
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 07850acd23d..a5e49b1b16a 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -184,7 +184,6 @@ module IssuableActions
def paginated_discussions
return if params[:per_page].blank?
- return if issuable.instance_of?(Issue) && Feature.disabled?(:paginated_issue_discussions, project)
return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project)
strong_memoize(:paginated_discussions) do
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 4841225de08..de38d26e3fe 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -24,12 +24,9 @@ module IssuableCollections
show_alert_if_search_is_disabled
@issuables = issuables_collection
+ set_pagination
- unless pagination_disabled?
- set_pagination
-
- return if redirect_out_of_range(@issuables, @total_pages)
- end
+ return if redirect_out_of_range(@issuables, @total_pages)
if params[:label_name].present? && @project
labels_params = { project_id: @project.id, title: params[:label_name] }
@@ -59,10 +56,6 @@ module IssuableCollections
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
- def pagination_disabled?
- false
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def issuables_collection
finder.execute.preload(preload_for_collection)
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
index 0b51b3dd380..dc7ba8295b9 100644
--- a/app/controllers/concerns/product_analytics_tracking.rb
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -28,7 +28,10 @@ module ProductAnalyticsTracking
def event_enabled?(event)
events_to_ff = {
g_analytics_valuestream: :route_hll_to_snowplow,
- i_search_paid: :route_hll_to_snowplow_phase2
+
+ i_search_paid: :route_hll_to_snowplow_phase2,
+ i_search_total: :route_hll_to_snowplow_phase2,
+ i_search_advanced: :route_hll_to_snowplow_phase2
}
Feature.enabled?(events_to_ff[event.to_sym], tracking_namespace_source)
diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb
new file mode 100644
index 00000000000..1a3e7136481
--- /dev/null
+++ b/app/controllers/concerns/verifies_with_email.rb
@@ -0,0 +1,194 @@
+# frozen_string_literal: true
+
+# == VerifiesWithEmail
+#
+# Controller concern to handle verification by email
+module VerifiesWithEmail
+ extend ActiveSupport::Concern
+ include ActionView::Helpers::DateHelper
+
+ TOKEN_LENGTH = 6
+ TOKEN_VALID_FOR_MINUTES = 60
+
+ included do
+ prepend_before_action :verify_with_email, only: :create, unless: -> { two_factor_enabled? }
+ end
+
+ def verify_with_email
+ return unless user = find_user || find_verification_user
+
+ if session[:verification_user_id] && token = verification_params[:verification_token].presence
+ # The verification token is submitted, verify it
+ verify_token(user, token)
+ elsif require_email_verification_enabled?(user)
+ # Limit the amount of password guesses, since we now display the email verification page
+ # when the password is correct, which could be a giveaway when brute-forced.
+ return render_sign_in_rate_limited if check_rate_limit!(:user_sign_in, scope: user) { true }
+
+ if user.valid_password?(user_params[:password])
+ # The user has logged in successfully.
+ if user.unlock_token
+ # Prompt for the token if it already has been set
+ prompt_for_email_verification(user)
+ elsif user.access_locked? || !AuthenticationEvent.initial_login_or_known_ip_address?(user, request.ip)
+ # require email verification if:
+ # - their account has been locked because of too many failed login attempts, or
+ # - they have logged in before, but never from the current ip address
+ send_verification_instructions(user)
+ prompt_for_email_verification(user)
+ end
+ end
+ end
+ end
+
+ def resend_verification_code
+ return unless user = find_verification_user
+
+ send_verification_instructions(user)
+ prompt_for_email_verification(user)
+ end
+
+ def successful_verification
+ session.delete(:verification_user_id)
+ @redirect_url = after_sign_in_path_for(current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+
+ render layout: 'minimal'
+ end
+
+ private
+
+ def find_verification_user
+ return unless session[:verification_user_id]
+
+ User.find_by_id(session[:verification_user_id])
+ end
+
+ # After successful verification and calling sign_in, devise redirects the
+ # user to this path. Override it to show the successful verified page.
+ def after_sign_in_path_for(resource)
+ if action_name == 'create' && session[:verification_user_id]
+ return users_successful_verification_path
+ end
+
+ super
+ end
+
+ def send_verification_instructions(user)
+ return if send_rate_limited?(user)
+
+ raw_token, encrypted_token = generate_token
+ user.unlock_token = encrypted_token
+ user.lock_access!({ send_instructions: false })
+ send_verification_instructions_email(user, raw_token)
+ end
+
+ def send_verification_instructions_email(user, token)
+ return unless user.can?(:receive_notifications)
+
+ Notify.verification_instructions_email(
+ user.id,
+ token: token,
+ expires_in: TOKEN_VALID_FOR_MINUTES).deliver_later
+
+ log_verification(user, :instructions_sent)
+ end
+
+ def verify_token(user, token)
+ return handle_verification_failure(user, :rate_limited) if verification_rate_limited?(user)
+ return handle_verification_failure(user, :invalid) unless valid_token?(user, token)
+ return handle_verification_failure(user, :expired) if expired_token?(user)
+
+ handle_verification_success(user)
+ end
+
+ def generate_token
+ raw_token = SecureRandom.random_number(10**TOKEN_LENGTH).to_s.rjust(TOKEN_LENGTH, '0')
+ encrypted_token = digest_token(raw_token)
+ [raw_token, encrypted_token]
+ end
+
+ def digest_token(token)
+ Devise.token_generator.digest(User, :unlock_token, token)
+ end
+
+ def render_sign_in_rate_limited
+ message = s_('IdentityVerification|Maximum login attempts exceeded. '\
+ 'Wait %{interval} and try again.') % { interval: user_sign_in_interval }
+ redirect_to new_user_session_path, alert: message
+ end
+
+ def user_sign_in_interval
+ interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[:user_sign_in][:interval]
+ distance_of_time_in_words(interval_in_seconds)
+ end
+
+ def verification_rate_limited?(user)
+ Gitlab::ApplicationRateLimiter.throttled?(:email_verification, scope: user.unlock_token)
+ end
+
+ def send_rate_limited?(user)
+ Gitlab::ApplicationRateLimiter.throttled?(:email_verification_code_send, scope: user)
+ end
+
+ def expired_token?(user)
+ user.locked_at < (Time.current - TOKEN_VALID_FOR_MINUTES.minutes)
+ end
+
+ def valid_token?(user, token)
+ user.unlock_token == digest_token(token)
+ end
+
+ def handle_verification_failure(user, reason)
+ message = case reason
+ when :rate_limited
+ s_("IdentityVerification|You've reached the maximum amount of tries. "\
+ 'Wait %{interval} or resend a new code and try again.') % { interval: email_verification_interval }
+ when :expired
+ s_('IdentityVerification|The code has expired. Resend a new code and try again.')
+ when :invalid
+ s_('IdentityVerification|The code is incorrect. Enter it again, or resend a new code.')
+ end
+
+ user.errors.add(:base, message)
+ log_verification(user, :failed_attempt, reason)
+
+ prompt_for_email_verification(user)
+ end
+
+ def email_verification_interval
+ interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[:email_verification][:interval]
+ distance_of_time_in_words(interval_in_seconds)
+ end
+
+ def handle_verification_success(user)
+ user.unlock_access!
+ log_verification(user, :successful)
+
+ sign_in(user)
+ end
+
+ def prompt_for_email_verification(user)
+ session[:verification_user_id] = user.id
+ self.resource = user
+
+ render 'devise/sessions/email_verification'
+ end
+
+ def verification_params
+ params.require(:user).permit(:verification_token)
+ end
+
+ def log_verification(user, event, reason = nil)
+ Gitlab::AppLogger.info(
+ message: 'Email Verification',
+ event: event.to_s.titlecase,
+ username: user.username,
+ ip: request.ip,
+ reason: reason.to_s
+ )
+ end
+
+ def require_email_verification_enabled?(user)
+ Feature.enabled?(:require_email_verification, user)
+ end
+end