Class: RuboCop::Cop::GraphQL::NotAuthorizedNodeType

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/graphql/not_authorized_node_type.rb

Overview

Detects types that implement Node interface and not have .authorized? check. Such types can be fetched by ID and therefore should have type level check to avoid accidental information exposure.

If .authorized? is defined in a parent class, you can add parent to the “SafeBaseClasses” to avoid offenses in children.

This cop also checks the can_can_action or pundit_role methods that can be used as part of the Ruby GraphQL Pro.

Examples:

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false

  def self.authorized?(object, context)
    super && object.owner == context[:viewer]
  end
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false

  class << self
    def authorized?(object, context)
      super && object.owner == context[:viewer]
    end
  end
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  pundit_role :staff

  field :uuid, ID, null: false
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  can_can_action :staff

  field :uuid, ID, null: false
end

# bad

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false
end

Constant Summary collapse

MSG =
".authorized? should be defined for types implementing Node interface."

Instance Method Summary collapse

Instance Method Details

#has_authorized_method?(node) ⇒ Object



94
95
96
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 94

def_node_matcher :has_authorized_method?, "{`(:defs (:self) :authorized? ...) | `(:sclass (:self) `(:def :authorized? ...))}\n"

#has_can_can_action?(node) ⇒ Object



84
85
86
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 84

def_node_matcher :has_can_can_action?, "`(send nil? :can_can_action {nil_type? sym_type?})\n"

#has_pundit_role?(node) ⇒ Object



89
90
91
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 89

def_node_matcher :has_pundit_role?, "`(send nil? :pundit_role {nil_type? sym_type?})\n"

#implements_node_type?(node) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 75

def_node_matcher :implements_node_type?, "`(send nil? :implements\n  (const\n    (const\n      (const\n        (const nil? :GraphQL) :Types) :Relay) :Node))\n"

#on_class(node) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 103

def on_class(node)
  @parent_modules ||= []
  return if possible_parent_classes(node).any? { |klass| ignored_class?(klass) }

  @parent_modules << node.child_nodes[0].const_name

  add_offense(node) if implements_node_type?(node) && !implements_authorization?(node)
end

#on_module(node) ⇒ Object



98
99
100
101
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 98

def on_module(node)
  @parent_modules ||= []
  @parent_modules << node.child_nodes[0].const_name
end