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, SchemaSubset

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.

Parameters:



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/graphql/schema/warden.rb', line 183

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| schema.visible?(m, context) }
  @visibility_cache.compare_by_identity
  # 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 = @schema_subset =
      nil
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

.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.

Parameters:

  • visibility_method (Symbol)

    a Warden method to call for this entry

  • entry (Object, Array<Object>)

    One or more definitions for a given name in a GraphQL Schema

  • context (GraphQL::Query::Context)
  • warden (Warden) (defaults to: Warden.from_context(context))

Returns:

  • (Object)

    entry or one of entry’s items if exactly one of them is visible for this context

  • (nil)

    If neither entry nor any of entry’s items are visible for this context



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/graphql/schema/warden.rb', line 28

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.

Parameters:

  • argument_owner (GraphQL::Field, GraphQL::InputObjectType)

Returns:

  • (Array<GraphQL::Argument>)

    Visible arguments on argument_owner



284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/graphql/schema/warden.rb', line 284

def arguments(argument_owner, ctx = nil)
  @visible_arguments ||= read_through { |o|
    args = o.arguments(@context)
    if args.any?
      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.



327
328
329
# File 'lib/graphql/schema/warden.rb', line 327

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.

Returns:

  • (Array<GraphQL::EnumType::EnumValue>)

    Visible members of enum_defn



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

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.

Parameters:

  • type_defn (GraphQL::ObjectType, GraphQL::InterfaceType)

Returns:

  • (Array<GraphQL::Field>)

    Fields on type_defn



277
278
279
280
# File 'lib/graphql/schema/warden.rb', line 277

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.

Returns:

  • (GraphQL::Argument, nil)

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



261
262
263
264
# File 'lib/graphql/schema/warden.rb', line 261

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.

Returns:

  • (GraphQL::Field, nil)

    The field named field_name on parent_type, if it exists



245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/graphql/schema/warden.rb', line 245

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).

Returns:

  • (GraphQL::BaseType, nil)

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



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

def get_type(type_name)
  @visible_types ||= read_through do |name|
    type_defn = @schema.get_type(name, @context)
    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.



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

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.

Returns:

  • (Array<GraphQL::InterfaceType>)

    Visible interfaces implemented by obj_type



316
317
318
319
320
321
322
323
324
325
# File 'lib/graphql/schema/warden.rb', line 316

def interfaces(obj_type)
  @visible_interfaces ||= read_through { |t|
    ints = t.interfaces(@context)
    if ints.any?
      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.

Returns:

  • (Boolean)

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



215
216
217
# File 'lib/graphql/schema/warden.rb', line 215

def loadable?(type, _ctx)
  !reachable_type_set.include?(type) && visible_type?(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.

Returns:

  • (Array<GraphQL::BaseType>)

    The types which may be member of type_defn



267
268
269
270
271
272
273
# File 'lib/graphql/schema/warden.rb', line 267

def possible_types(type_defn)
  @visible_possible_types ||= read_through { |type_defn|
    pt = @schema.possible_types(type_defn, @context)
    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.

Returns:

  • (Boolean)

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



239
240
241
242
# File 'lib/graphql/schema/warden.rb', line 239

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.

Returns:

  • (Array<GraphQL::BaseType>)

    Visible and reachable types in the schema



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

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.



331
332
333
334
335
336
337
338
# File 'lib/graphql/schema/warden.rb', line 331

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

#schema_subsetObject

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.



107
108
109
# File 'lib/graphql/schema/warden.rb', line 107

def schema_subset
  @schema_subset ||= SchemaSubset.new(self)
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.

Returns:

  • (Hash<String, GraphQL::BaseType>)

    Visible types in the schema



202
203
204
205
206
207
208
209
210
211
212
# File 'lib/graphql/schema/warden.rb', line 202

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

#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.

Returns:

  • (Boolean)


351
352
353
# File 'lib/graphql/schema/warden.rb', line 351

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.

Returns:

  • (Boolean)


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

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.

Parameters:

  • owner (Class, Module) (defaults to: field_defn.owner)

    If provided, confirm that field has the given owner.

Returns:

  • (Boolean)


341
342
343
344
345
346
347
348
349
# File 'lib/graphql/schema/warden.rb', line 341

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.

Returns:

  • (Boolean)


355
356
357
358
# File 'lib/graphql/schema/warden.rb', line 355

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.

Returns:

  • (Boolean)


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

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