blob: f3ca82ec6975a6f3511dc60e43e854c0f1b634e7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
# frozen_string_literal: true
module Gitlab
module Graphql
module Authorize
class AuthorizeFieldService
def initialize(field)
@field = field
@old_resolve_proc = @field.resolve_proc
end
def authorizations?
authorizations.present?
end
def authorized_resolve
proc do |obj, args, ctx|
resolved_obj = @old_resolve_proc.call(obj, args, ctx)
checker = build_checker(ctx[:current_user])
if resolved_obj.respond_to?(:then)
resolved_obj.then(&checker)
else
checker.call(resolved_obj)
end
end
end
private
def authorizations
@authorizations ||= (type_authorizations + field_authorizations).uniq
end
# Returns any authorize metadata from the return type of @field
def type_authorizations
type = @field.type
# When the return type of @field is a collection, find the singular type
if type.get_field('edges')
type = node_type_for_relay_connection(type)
elsif type.list?
type = node_type_for_basic_connection(type)
end
Array.wrap(type.metadata[:authorize])
end
# Returns any authorize metadata from @field
def field_authorizations
Array.wrap(@field.metadata[:authorize])
end
def build_checker(current_user)
lambda do |value|
# Load the elements if they were not loaded by BatchLoader yet
value = value.sync if value.respond_to?(:sync)
check = lambda do |object|
authorizations.all? do |ability|
Ability.allowed?(current_user, ability, object)
end
end
case value
when Array, ActiveRecord::Relation
value.select(&check)
else
value if check.call(value)
end
end
end
# Returns the singular type for relay connections.
# This will be the type class of edges.node
def node_type_for_relay_connection(type)
type = type.get_field('edges').type.unwrap.get_field('node')&.type
if type.nil?
raise Gitlab::Graphql::Errors::ConnectionDefinitionError,
'Connection Type must conform to the Relay Cursor Connections Specification'
end
type
end
# Returns the singular type for basic connections, for example `[Types::ProjectType]`
def node_type_for_basic_connection(type)
type.unwrap
end
end
end
end
end
|