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:
authorNick Thomas <nick@gitlab.com>2017-08-16 16:04:41 +0300
committerBob Van Landuyt <bob@vanlanduyt.co>2018-06-05 21:47:42 +0300
commit9c6c17cbcdb8bf8185fc1b873dcfd08f723e4df5 (patch)
tree624dba30e87ed0ea39afa0535d92c37c7718daef /lib/gitlab/graphql
parent67dc43db2f30095cce7fe01d7f475d084be936e8 (diff)
Add a minimal GraphQL API
Diffstat (limited to 'lib/gitlab/graphql')
-rw-r--r--lib/gitlab/graphql/authorize.rb55
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/gitlab/graphql/authorize.rb b/lib/gitlab/graphql/authorize.rb
new file mode 100644
index 00000000000..1df130e519a
--- /dev/null
+++ b/lib/gitlab/graphql/authorize.rb
@@ -0,0 +1,55 @@
+module Gitlab
+ module Graphql
+ # Allow fields to declare permissions their objects must have. The field
+ # will be set to nil unless all required permissions are present.
+ class Authorize
+ SETUP_PROC = -> (type, *args) do
+ type.metadata[:authorize] ||= []
+ type.metadata[:authorize].concat(args)
+ end
+
+ INSTRUMENT_PROC = -> (schema) do
+ schema.instrument(:field, new)
+ end
+
+ def self.register!
+ GraphQL::Schema.accepts_definitions(enable_authorization: INSTRUMENT_PROC)
+ GraphQL::Field.accepts_definitions(authorize: SETUP_PROC)
+ end
+
+ # Replace the resolver for the field with one that will only return the
+ # resolved object if the permissions check is successful.
+ #
+ # Collections are not supported. Apply permissions checks for those at the
+ # database level instead, to avoid loading superfluous data from the DB
+ def instrument(_type, field)
+ return field unless field.metadata.include?(:authorize)
+
+ old_resolver = field.resolve_proc
+
+ new_resolver = -> (obj, args, ctx) do
+ resolved_obj = old_resolver.call(obj, args, ctx)
+ checker = build_checker(ctx[:current_user], field.metadata[:authorize])
+
+ 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)
+ proc do |obj|
+ obj if abilities.all? { |ability| Ability.allowed?(current_user, ability, obj) }
+ end
+ end
+ end
+ end
+end