summaryrefslogtreecommitdiff
path: root/lib/gitlab/cross_project_access
diff options
context:
space:
mode:
authorBob Van Landuyt <bob@vanlanduyt.co>2017-12-11 15:21:06 +0100
committerBob Van Landuyt <bob@vanlanduyt.co>2018-02-22 17:11:36 +0100
commit148816cd67a314f17e79c107270cc708501bdd39 (patch)
treeeba07d109322392bb5862b715adc066a0ebbdf95 /lib/gitlab/cross_project_access
parentb5306075c21f5546d1447052558da6227629c15e (diff)
downloadgitlab-ce-148816cd67a314f17e79c107270cc708501bdd39.tar.gz
Port `read_cross_project` ability from EE
Diffstat (limited to 'lib/gitlab/cross_project_access')
-rw-r--r--lib/gitlab/cross_project_access/check_collection.rb47
-rw-r--r--lib/gitlab/cross_project_access/check_info.rb66
-rw-r--r--lib/gitlab/cross_project_access/class_methods.rb48
3 files changed, 161 insertions, 0 deletions
diff --git a/lib/gitlab/cross_project_access/check_collection.rb b/lib/gitlab/cross_project_access/check_collection.rb
new file mode 100644
index 00000000000..88376232065
--- /dev/null
+++ b/lib/gitlab/cross_project_access/check_collection.rb
@@ -0,0 +1,47 @@
+module Gitlab
+ class CrossProjectAccess
+ class CheckCollection
+ attr_reader :checks
+
+ def initialize
+ @checks = []
+ end
+
+ def add_collection(collection)
+ @checks |= collection.checks
+ end
+
+ def add_check(check)
+ @checks << check
+ end
+
+ def should_run?(object)
+ skips, runs = arranged_checks
+
+ # If one rule tells us to skip, we skip the cross project check
+ return false if skips.any? { |check| check.should_skip?(object) }
+
+ # If the rule isn't skipped, we run it if any of the checks says we
+ # should run
+ runs.any? { |check| check.should_run?(object) }
+ end
+
+ def arranged_checks
+ return [@skips, @runs] if @skips && @runs
+
+ @skips = []
+ @runs = []
+
+ @checks.each do |check|
+ if check.skip
+ @skips << check
+ else
+ @runs << check
+ end
+ end
+
+ [@skips, @runs]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cross_project_access/check_info.rb b/lib/gitlab/cross_project_access/check_info.rb
new file mode 100644
index 00000000000..e8a845c7f1e
--- /dev/null
+++ b/lib/gitlab/cross_project_access/check_info.rb
@@ -0,0 +1,66 @@
+module Gitlab
+ class CrossProjectAccess
+ class CheckInfo
+ attr_accessor :actions, :positive_condition, :negative_condition, :skip
+
+ def initialize(actions, positive_condition, negative_condition, skip)
+ @actions = actions
+ @positive_condition = positive_condition
+ @negative_condition = negative_condition
+ @skip = skip
+ end
+
+ def should_skip?(object)
+ return !should_run?(object) unless @skip
+
+ skip_for_action = @actions[current_action(object)]
+ skip_for_action = false if @actions[current_action(object)].nil?
+
+ # We need to do the opposite of what was defined in the following cases:
+ # - skip_cross_project_access_check index: true, if: -> { false }
+ # - skip_cross_project_access_check index: true, unless: -> { true }
+ if positive_condition_is_false?(object)
+ skip_for_action = !skip_for_action
+ end
+
+ if negative_condition_is_true?(object)
+ skip_for_action = !skip_for_action
+ end
+
+ skip_for_action
+ end
+
+ def should_run?(object)
+ return !should_skip?(object) if @skip
+
+ run_for_action = @actions[current_action(object)]
+ run_for_action = true if @actions[current_action(object)].nil?
+
+ # We need to do the opposite of what was defined in the following cases:
+ # - requires_cross_project_access index: true, if: -> { false }
+ # - requires_cross_project_access index: true, unless: -> { true }
+ if positive_condition_is_false?(object)
+ run_for_action = !run_for_action
+ end
+
+ if negative_condition_is_true?(object)
+ run_for_action = !run_for_action
+ end
+
+ run_for_action
+ end
+
+ def positive_condition_is_false?(object)
+ @positive_condition && !object.instance_exec(&@positive_condition)
+ end
+
+ def negative_condition_is_true?(object)
+ @negative_condition && object.instance_exec(&@negative_condition)
+ end
+
+ def current_action(object)
+ object.respond_to?(:action_name) ? object.action_name.to_sym : nil
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cross_project_access/class_methods.rb b/lib/gitlab/cross_project_access/class_methods.rb
new file mode 100644
index 00000000000..90eac94800c
--- /dev/null
+++ b/lib/gitlab/cross_project_access/class_methods.rb
@@ -0,0 +1,48 @@
+module Gitlab
+ class CrossProjectAccess
+ module ClassMethods
+ def requires_cross_project_access(*args)
+ positive_condition, negative_condition, actions = extract_params(args)
+
+ Gitlab::CrossProjectAccess.add_check(
+ self,
+ actions: actions,
+ positive_condition: positive_condition,
+ negative_condition: negative_condition
+ )
+ end
+
+ def skip_cross_project_access_check(*args)
+ positive_condition, negative_condition, actions = extract_params(args)
+
+ Gitlab::CrossProjectAccess.add_check(
+ self,
+ actions: actions,
+ positive_condition: positive_condition,
+ negative_condition: negative_condition,
+ skip: true
+ )
+ end
+
+ private
+
+ def extract_params(args)
+ actions = {}
+ positive_condition = nil
+ negative_condition = nil
+
+ args.each do |argument|
+ if argument.is_a?(Hash)
+ positive_condition = argument.delete(:if)
+ negative_condition = argument.delete(:unless)
+ actions.merge!(argument)
+ else
+ actions[argument] = true
+ end
+ end
+
+ [positive_condition, negative_condition, actions]
+ end
+ end
+ end
+end