Class: GraphQL::Schema::Warden Private

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/schema/warden.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Restrict access to a GraphQL::Schema with a user-defined visible? implementations.

When validating and executing a query, all access to schema members should go through a warden. If you access the schema directly, you may show a client something that it shouldn't be allowed to see.

Defined Under Namespace

Classes: NullWarden, PassThruWarden, VisibilityProfile

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context:, schema:) ⇒ Warden

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Warden.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/graphql/schema/warden.rb', line 200

def initialize(context:, schema:)
  @schema = schema
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
  @query = @schema.query
  @mutation = @schema.mutation
  @subscription = @schema.subscription
  @context = context
  @visibility_cache = read_through { |m| check_visible(schema, m) }
  # Initialize all ivars to improve object shape consistency:
  @types = @visible_types = @reachable_types = @visible_parent_fields =
    @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
    @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
    @visible_and_reachable_type = @unions = @unfiltered_interfaces =
    @reachable_type_set = @visibility_profile = @loadable_possible_types =
      nil
  @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
end

Instance Attribute Details

#skip_warning=(value) ⇒ Object (writeonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



218
219
220
# File 'lib/graphql/schema/warden.rb', line 218

def skip_warning=(value)
  @skip_warning = value
end

Class Method Details

.from_context(context) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



15
16
17
18
19
20
# File 'lib/graphql/schema/warden.rb', line 15

def self.from_context(context)
  context.warden || PassThruWarden
rescue NoMethodError
  # this might be a hash which won't respond to #warden
  PassThruWarden
end

.types_from_context(context) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



22
23
24
25
26
27
# File 'lib/graphql/schema/warden.rb', line 22

def self.types_from_context(context)
  context.types || PassThruWarden
rescue NoMethodError
  # this might be a hash which won't respond to #warden
  PassThruWarden
end

.use(schema) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



29
30
31
# File 'lib/graphql/schema/warden.rb', line 29

def self.use(schema)
  # no-op
end

.visible_entry?(visibility_method, entry, context, warden = Warden.from_context(context)) ⇒ Object?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/graphql/schema/warden.rb', line 39

def self.visible_entry?(visibility_method, entry, context, warden = Warden.from_context(context))
  if entry.is_a?(Array)
    visible_item = nil
    entry.each do |item|
      if warden.public_send(visibility_method, item, context)
        if visible_item.nil?
          visible_item = item
        else
          raise DuplicateNamesError.new(
            duplicated_name: item.path, duplicated_definition_1: visible_item.inspect, duplicated_definition_2: item.inspect
          )
        end
      end
    end
    visible_item
  elsif warden.public_send(visibility_method, entry, context)
    entry
  else
    nil
  end
end

Instance Method Details

#arguments(argument_owner, ctx = nil) ⇒ Array<GraphQL::Argument>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible arguments on argument_owner.



318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/graphql/schema/warden.rb', line 318

def arguments(argument_owner, ctx = nil)
  @visible_arguments ||= read_through { |o|
    args = o.arguments(@context)
    if !args.empty?
      args = args.values
      args.select! { |a| visible_argument?(a, @context) }
      args
    else
      EmptyObjects::EMPTY_ARRAY
    end
  }
  @visible_arguments[argument_owner]
end

#directivesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



361
362
363
# File 'lib/graphql/schema/warden.rb', line 361

def directives
  @schema.directives.each_value.select { |d| visible?(d) }
end

#enum_values(enum_defn) ⇒ Array<GraphQL::EnumType::EnumValue>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible members of enum_defn.



333
334
335
336
337
338
339
340
341
342
# File 'lib/graphql/schema/warden.rb', line 333

def enum_values(enum_defn)
  @visible_enum_arrays ||= read_through { |e|
    values = e.enum_values(@context)
    if values.size == 0
      raise GraphQL::Schema::Enum::MissingValuesError.new(e)
    end
    values
  }
  @visible_enum_arrays[enum_defn]
end

#fields(type_defn) ⇒ Array<GraphQL::Field>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Fields on type_defn.



311
312
313
314
# File 'lib/graphql/schema/warden.rb', line 311

def fields(type_defn)
  @visible_fields ||= read_through { |t| @schema.get_fields(t, @context).values }
  @visible_fields[type_defn]
end

#get_argument(parent_type, argument_name) ⇒ GraphQL::Argument?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The argument named argument_name on parent_type, if it exists and is visible.



295
296
297
298
# File 'lib/graphql/schema/warden.rb', line 295

def get_argument(parent_type, argument_name)
  argument = parent_type.get_argument(argument_name, @context)
  return argument if argument && visible_argument?(argument, @context)
end

#get_field(parent_type, field_name) ⇒ GraphQL::Field?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The field named field_name on parent_type, if it exists.



279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/graphql/schema/warden.rb', line 279

def get_field(parent_type, field_name)
  @visible_parent_fields ||= read_through do |type|
    read_through do |f_name|
      field_defn = @schema.get_field(type, f_name, @context)
      if field_defn && visible_field?(field_defn, nil, type)
        field_defn
      else
        nil
      end
    end
  end

  @visible_parent_fields[parent_type][field_name]
end

#get_type(type_name) ⇒ GraphQL::BaseType?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The type named type_name, if it exists (else nil).



254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/graphql/schema/warden.rb', line 254

def get_type(type_name)
  @visible_types ||= read_through do |name|
    type_defn = @schema.get_type(name, @context, false)
    if type_defn && visible_and_reachable_type?(type_defn)
      type_defn
    else
      nil
    end
  end

  @visible_types[type_name]
end

#interface_type_memberships(obj_type, _ctx = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



398
399
400
401
402
403
# File 'lib/graphql/schema/warden.rb', line 398

def interface_type_memberships(obj_type, _ctx = nil)
  @type_memberships ||= read_through do |obj_t|
    obj_t.interface_type_memberships
  end
  @type_memberships[obj_type]
end

#interfaces(obj_type) ⇒ Array<GraphQL::InterfaceType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible interfaces implemented by obj_type.



350
351
352
353
354
355
356
357
358
359
# File 'lib/graphql/schema/warden.rb', line 350

def interfaces(obj_type)
  @visible_interfaces ||= read_through { |t|
    ints = t.interfaces(@context)
    if !ints.empty?
      ints.select! { |i| visible_type?(i) }
    end
    ints
  }
  @visible_interfaces[obj_type]
end

#loadable?(type, _ctx) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns True if this type is used for loads: but not in the schema otherwise and not explicitly hidden.



234
235
236
237
238
# File 'lib/graphql/schema/warden.rb', line 234

def loadable?(type, _ctx)
  visible_type?(type) &&
    !referenced?(type) &&
    (type.respond_to?(:interfaces) ? interfaces(type).all? { |i| loadable?(i, _ctx) } : true)
end

#loadable_possible_types(abstract_type, _ctx) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This abstract type was determined to be used for loads only. All its possible types are valid possibilities here -- no filtering.



242
243
244
245
246
247
248
249
250
251
# File 'lib/graphql/schema/warden.rb', line 242

def loadable_possible_types(abstract_type, _ctx)
  @loadable_possible_types ||= read_through do |t|
    if t.is_a?(Class) # union
      t.possible_types
    else
      @schema.possible_types(abstract_type)
    end
  end
  @loadable_possible_types[abstract_type]
end

#possible_types(type_defn) ⇒ Array<GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The types which may be member of type_defn.



301
302
303
304
305
306
307
# File 'lib/graphql/schema/warden.rb', line 301

def possible_types(type_defn)
  @visible_possible_types ||= read_through { |type_defn|
    pt = @schema.possible_types(type_defn, @context, false)
    pt.select { |t| visible_and_reachable_type?(t) }
  }
  @visible_possible_types[type_defn]
end

#reachable_type?(type_name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Boolean True if the type is visible and reachable in the schema.



273
274
275
276
# File 'lib/graphql/schema/warden.rb', line 273

def reachable_type?(type_name)
  type = get_type(type_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
  type && reachable_type_set.include?(type)
end

#reachable_typesArray<GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible and reachable types in the schema.



268
269
270
# File 'lib/graphql/schema/warden.rb', line 268

def reachable_types
  @reachable_types ||= reachable_type_set.to_a
end

#root_type_for_operation(op_name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



365
366
367
368
369
370
371
372
# File 'lib/graphql/schema/warden.rb', line 365

def root_type_for_operation(op_name)
  root_type = @schema.root_type_for_operation(op_name)
  if root_type && visible?(root_type)
    root_type
  else
    nil
  end
end

#typesHash<String, GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible types in the schema.



221
222
223
224
225
226
227
228
229
230
231
# File 'lib/graphql/schema/warden.rb', line 221

def types
  @types ||= begin
    vis_types = {}
    @schema.types(@context).each do |n, t|
      if visible_and_reachable_type?(t)
        vis_types[n] = t
      end
    end
    vis_types
  end
end

#visibility_profileObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



116
117
118
# File 'lib/graphql/schema/warden.rb', line 116

def visibility_profile
  @visibility_profile ||= VisibilityProfile.new(self)
end

#visible_argument?(arg_defn, _ctx = nil) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



385
386
387
# File 'lib/graphql/schema/warden.rb', line 385

def visible_argument?(arg_defn, _ctx = nil)
  visible?(arg_defn) && visible_and_reachable_type?(arg_defn.type.unwrap)
end

#visible_enum_value?(enum_value, _ctx = nil) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



344
345
346
347
# File 'lib/graphql/schema/warden.rb', line 344

def visible_enum_value?(enum_value, _ctx = nil)
  @visible_enum_values ||= read_through { |ev| visible?(ev) }
  @visible_enum_values[enum_value]
end

#visible_field?(field_defn, _ctx = nil, owner = field_defn.owner) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



375
376
377
378
379
380
381
382
383
# File 'lib/graphql/schema/warden.rb', line 375

def visible_field?(field_defn, _ctx = nil, owner = field_defn.owner)
  # This field is visible in its own right
  visible?(field_defn) &&
    # This field's return type is visible
    visible_and_reachable_type?(field_defn.type.unwrap) &&
    # This field is either defined on this object type,
    # or the interface it's inherited from is also visible
    ((field_defn.respond_to?(:owner) && field_defn.owner == owner) || field_on_visible_interface?(field_defn, owner))
end

#visible_type?(type_defn, _ctx = nil) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



389
390
391
392
# File 'lib/graphql/schema/warden.rb', line 389

def visible_type?(type_defn, _ctx = nil)
  @type_visibility ||= read_through { |type_defn| visible?(type_defn) }
  @type_visibility[type_defn]
end

#visible_type_membership?(type_membership, _ctx = nil) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



394
395
396
# File 'lib/graphql/schema/warden.rb', line 394

def visible_type_membership?(type_membership, _ctx = nil)
  visible?(type_membership)
end