From 538a157a90930aa07f4b04c88f7f31e1bedfb003 Mon Sep 17 00:00:00 2001 From: exAspArk Date: Wed, 8 Apr 2020 11:35:24 -0400 Subject: [PATCH] Use trace GraphQL API instead of field extension --- lib/graphql/guard.rb | 32 +++++++++++++------ lib/graphql/guard/field_extension.rb | 16 ---------- spec/fixtures/inline_schema.rb | 9 ++++++ .../inline_without_exceptions_schema.rb | 29 ----------------- spec/graphql/guard_spec.rb | 3 +- 5 files changed, 32 insertions(+), 57 deletions(-) delete mode 100644 lib/graphql/guard/field_extension.rb delete mode 100644 spec/fixtures/inline_without_exceptions_schema.rb diff --git a/lib/graphql/guard.rb b/lib/graphql/guard.rb index 26a33d3..f94464d 100644 --- a/lib/graphql/guard.rb +++ b/lib/graphql/guard.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "graphql" -require "graphql/guard/field_extension" require "graphql/guard/version" module GraphQL @@ -9,6 +8,7 @@ class Guard NotAuthorizedError = Class.new(StandardError) ANY_FIELD_NAME = :'*' + EXECUTE_FIELD_EVENTS = %w[execute_field execute_field_lazy] DEFAULT_NOT_AUTHORIZED = ->(type, field) do raise NotAuthorizedError.new("Not authorized to access: #{type.graphql_definition}.#{field}") @@ -28,9 +28,7 @@ def initialize(policy_object: nil, not_authorized: DEFAULT_NOT_AUTHORIZED) def use(schema_definition) if schema_definition.interpreter? - fields(schema_definition).each do |field| - field.type_class.extension(GraphQL::Guard::FieldExtension, guard_instance: self) - end + schema_definition.tracer(self) else raise "Please use the graphql gem version >= 1.10 with GraphQL::Execution::Interpreter" end @@ -38,6 +36,14 @@ def use(schema_definition) add_schema_masking!(schema_definition) end + def trace(event, trace_data) + if EXECUTE_FIELD_EVENTS.include?(event) + ensure_guarded(trace_data) { yield } + else + yield + end + end + def find_guard_proc(type, field) inline_guard(field) || policy_object_guard(type, field.name.to_sym) || @@ -47,12 +53,6 @@ def find_guard_proc(type, field) private - def fields(schema_definition) - schema_definition.types.values.flat_map { |type| - type.fields.values if type.name && type.respond_to?(:fields) - }.compact - end - def add_schema_masking!(schema_definition) schema_definition.class_eval do def self.default_filter @@ -61,6 +61,18 @@ def self.default_filter end end + def ensure_guarded(trace_data) + field = trace_data[:field] + guard_proc = find_guard_proc(field.owner, field) + return yield unless guard_proc + + if guard_proc.call(trace_data[:object], trace_data[:arguments], trace_data[:query].context) + yield + else + not_authorized.call(field.owner, field.name.to_sym) + end + end + def policy_object_guard(type, field_name) @policy_object && @policy_object.guard(type.type_class, field_name) end diff --git a/lib/graphql/guard/field_extension.rb b/lib/graphql/guard/field_extension.rb deleted file mode 100644 index c71f63f..0000000 --- a/lib/graphql/guard/field_extension.rb +++ /dev/null @@ -1,16 +0,0 @@ -module GraphQL - class Guard - class FieldExtension < GraphQL::Schema::FieldExtension - def resolve(object:, arguments:, **rest) - guard_proc = options[:guard_instance].find_guard_proc(field.owner, field) - return yield(object, arguments) unless guard_proc - - if guard_proc.call(object, arguments, rest[:context]) - yield(object, arguments) - else - options[:guard_instance].not_authorized.call(field.owner, field.name.to_sym) - end - end - end - end -end diff --git a/spec/fixtures/inline_schema.rb b/spec/fixtures/inline_schema.rb index 9d52f53..1b7d7ad 100644 --- a/spec/fixtures/inline_schema.rb +++ b/spec/fixtures/inline_schema.rb @@ -33,4 +33,13 @@ class Schema < GraphQL::Schema query QueryType use GraphQL::Guard.new end + + class SchemaWithoutExceptions < GraphQL::Schema + use GraphQL::Execution::Interpreter + use GraphQL::Analysis::AST + query QueryType + use GraphQL::Guard.new(not_authorized: ->(type, field) { + GraphQL::ExecutionError.new("Not authorized to access #{type.graphql_definition}.#{field}") + }) + end end diff --git a/spec/fixtures/inline_without_exceptions_schema.rb b/spec/fixtures/inline_without_exceptions_schema.rb deleted file mode 100644 index 1af7776..0000000 --- a/spec/fixtures/inline_without_exceptions_schema.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module InlineWithoutExceptions - class PostType < GraphQL::Schema::Object - guard ->(_post, _args, ctx) { ctx[:current_user].admin? } - field :id, ID, null: false - field :title, String, null: true - end - - class QueryType < GraphQL::Schema::Object - field :posts, [PostType], null: false do - argument :user_id, ID, required: true - guard ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id } - end - - def posts(user_id:) - Post.where(user_id: user_id) - end - end - - class Schema < GraphQL::Schema - use GraphQL::Execution::Interpreter - use GraphQL::Analysis::AST - query QueryType - use GraphQL::Guard.new(not_authorized: ->(type, field) { - GraphQL::ExecutionError.new("Not authorized to access #{type.graphql_definition}.#{field}") - }) - end -end diff --git a/spec/graphql/guard_spec.rb b/spec/graphql/guard_spec.rb index 5f7da88..158394e 100644 --- a/spec/graphql/guard_spec.rb +++ b/spec/graphql/guard_spec.rb @@ -5,7 +5,6 @@ require 'fixtures/user' require 'fixtures/post' require 'fixtures/inline_schema' -require 'fixtures/inline_without_exceptions_schema' require 'fixtures/policy_object_schema' RSpec.describe GraphQL::Guard do @@ -41,7 +40,7 @@ user = User.new(id: '1', role: 'not_admin') query = "query($userId: ID!) { posts(userId: $userId) { id title } }" - result = InlineWithoutExceptions::Schema.execute(query, variables: {userId: 1}, context: {current_user: user}) + result = Inline::SchemaWithoutExceptions.execute(query, variables: {userId: 1}, context: {current_user: user}) expect(result['errors']).to eq([{ "message" => "Not authorized to access Post.id",