debian-mirror-gitlab/app/finders/concerns/finder_with_cross_project_access.rb

87 lines
2.2 KiB
Ruby
Raw Normal View History

2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2020-03-09 13:42:32 +05:30
# Module to prepend into finders to specify whether or not the finder requires
2018-03-27 19:54:05 +05:30
# cross project access
#
# This module depends on the finder implementing the following methods:
#
2019-02-15 15:39:39 +05:30
# - `#execute` should return an `ActiveRecord::Relation` or the `model` needs to
# be defined in the call to `requires_cross_project_access`.
2018-03-27 19:54:05 +05:30
# - `#current_user` the user that requires access (or nil)
module FinderWithCrossProjectAccess
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
extend Gitlab::CrossProjectAccess::ClassMethods
2019-02-15 15:39:39 +05:30
cattr_accessor :finder_model
def self.requires_cross_project_access(*args)
super
self.finder_model = extract_model_from_arguments(args)
end
private
def self.extract_model_from_arguments(args)
args.detect { |argument| argument.is_a?(Hash) && argument[:model] }
&.fetch(:model)
end
2018-03-27 19:54:05 +05:30
end
override :execute
2021-01-29 00:20:46 +05:30
def execute(*args, **kwargs)
2018-03-27 19:54:05 +05:30
check = Gitlab::CrossProjectAccess.find_check(self)
2019-02-15 15:39:39 +05:30
original = -> { super }
2018-03-27 19:54:05 +05:30
2019-02-15 15:39:39 +05:30
return original.call unless check
return original.call if should_skip_cross_project_check || can_read_cross_project?
2018-03-27 19:54:05 +05:30
if check.should_run?(self)
2019-02-15 15:39:39 +05:30
finder_model&.none || original.call.model.none
2018-03-27 19:54:05 +05:30
else
2019-02-15 15:39:39 +05:30
original.call
2018-03-27 19:54:05 +05:30
end
end
# We can skip the cross project check for finding indivitual records.
# this would be handled by the `can?(:read_*, result)` call in `FinderMethods`
# itself.
override :find_by!
def find_by!(*args)
skip_cross_project_check { super }
end
override :find_by
def find_by(*args)
skip_cross_project_check { super }
end
override :find
def find(*args)
skip_cross_project_check { super }
end
attr_accessor :should_skip_cross_project_check
def skip_cross_project_check
self.should_skip_cross_project_check = true
yield
ensure
# The find could raise an `ActiveRecord::RecordNotFound`, after which we
# still want to re-enable the check.
self.should_skip_cross_project_check = false
end
def can_read_cross_project?
Ability.allowed?(current_user, :read_cross_project)
end
def can_read_project?(project)
Ability.allowed?(current_user, :read_project, project)
end
end