2018-11-09 13:39:43 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-05-23 03:55:14 -04:00
|
|
|
module Gitlab
|
|
|
|
module Graphql
|
|
|
|
module Authorize
|
|
|
|
class Instrumentation
|
|
|
|
# Replace the resolver for the field with one that will only return the
|
|
|
|
# resolved object if the permissions check is successful.
|
|
|
|
def instrument(_type, field)
|
2019-02-17 20:19:49 -05:00
|
|
|
required_permissions = Array.wrap(field.metadata[:authorize])
|
|
|
|
return field if required_permissions.empty?
|
2018-05-23 03:55:14 -04:00
|
|
|
|
|
|
|
old_resolver = field.resolve_proc
|
|
|
|
|
|
|
|
new_resolver = -> (obj, args, ctx) do
|
|
|
|
resolved_obj = old_resolver.call(obj, args, ctx)
|
2019-02-17 20:19:49 -05:00
|
|
|
checker = build_checker(ctx[:current_user], required_permissions)
|
2018-05-23 03:55:14 -04:00
|
|
|
|
|
|
|
if resolved_obj.respond_to?(:then)
|
|
|
|
resolved_obj.then(&checker)
|
|
|
|
else
|
|
|
|
checker.call(resolved_obj)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
field.redefine do
|
|
|
|
resolve(new_resolver)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def build_checker(current_user, abilities)
|
2019-02-12 10:30:23 -05:00
|
|
|
lambda do |value|
|
2018-05-23 03:55:14 -04:00
|
|
|
# Load the elements if they weren't loaded by BatchLoader yet
|
2019-02-12 10:30:23 -05:00
|
|
|
value = value.sync if value.respond_to?(:sync)
|
|
|
|
|
|
|
|
check = lambda do |object|
|
|
|
|
abilities.all? do |ability|
|
|
|
|
Ability.allowed?(current_user, ability, object)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-02-13 12:26:00 -05:00
|
|
|
case value
|
|
|
|
when Array
|
|
|
|
value.select(&check)
|
|
|
|
else
|
|
|
|
value if check.call(value)
|
|
|
|
end
|
2018-05-23 03:55:14 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|