forked from wundergraph/graphql-go-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
request_fields_validator.go
132 lines (106 loc) · 4.01 KB
/
request_fields_validator.go
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package graphql
import (
"fmt"
"github.com/matthewmcneely/graphql-go-tools/v2/pkg/operationreport"
)
type RequestFieldsValidator interface {
Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error)
}
type FieldRestrictionValidator interface {
ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error)
}
type FieldRestrictionListKind int
const (
AllowList FieldRestrictionListKind = iota
BlockList
)
type FieldRestrictionList struct {
Kind FieldRestrictionListKind
Types []Type
}
type DefaultFieldsValidator struct {
}
// Validate validates a request by checking if `restrictions` contains blocked fields.
//
// Deprecated: This function can only handle blocked fields. Use `ValidateByFieldList` if you
// want to check for blocked or allowed fields instead.
func (d DefaultFieldsValidator) Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error) {
restrictionList := FieldRestrictionList{
Kind: BlockList,
Types: restrictions,
}
return d.ValidateByFieldList(request, schema, restrictionList)
}
// ValidateByFieldList will validate a request by using a list of allowed or blocked fields.
func (d DefaultFieldsValidator) ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error) {
report := operationreport.Report{}
if len(restrictionList.Types) == 0 {
return fieldsValidationResult(report, true, "", "")
}
requestedTypes := make(RequestTypes)
NewExtractor().ExtractFieldsFromRequest(request, schema, &report, requestedTypes)
if restrictionList.Kind == BlockList {
return d.checkForBlockedFields(restrictionList, requestedTypes, report)
}
return d.checkForAllowedFields(restrictionList, requestedTypes, report)
}
func (d DefaultFieldsValidator) checkForBlockedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) {
for _, typeFromList := range restrictionList.Types {
requestedFields, hasRestrictedType := requestTypes[typeFromList.Name]
if !hasRestrictedType {
continue
}
for _, field := range typeFromList.Fields {
_, requestHasField := requestedFields[field]
if requestHasField {
return fieldsValidationResult(report, false, typeFromList.Name, field)
}
}
}
return fieldsValidationResult(report, true, "", "")
}
func (d DefaultFieldsValidator) checkForAllowedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) {
allowedFieldsLookupMap := make(map[string]map[string]bool)
for _, allowedType := range restrictionList.Types {
allowedFieldsLookupMap[allowedType.Name] = make(map[string]bool)
for _, allowedField := range allowedType.Fields {
allowedFieldsLookupMap[allowedType.Name][allowedField] = true
}
}
for requestType, requestFields := range requestTypes {
for requestField := range requestFields {
isAllowedField := allowedFieldsLookupMap[requestType][requestField]
if !isAllowedField {
return fieldsValidationResult(report, false, requestType, requestField)
}
}
}
return fieldsValidationResult(report, true, "", "")
}
type RequestFieldsValidationResult struct {
Valid bool
Errors Errors
}
func fieldsValidationResult(report operationreport.Report, valid bool, typeName, fieldName string) (RequestFieldsValidationResult, error) {
result := RequestFieldsValidationResult{
Valid: valid,
Errors: nil,
}
var errors RequestErrors
if !result.Valid {
errors = append(errors, RequestError{
Message: fmt.Sprintf("field: %s is restricted on type: %s", fieldName, typeName),
})
}
result.Errors = errors
if !report.HasErrors() {
return result, nil
}
errors = append(errors, RequestErrorsFromOperationReport(report)...)
result.Errors = errors
var err error
if len(report.InternalErrors) > 0 {
err = report.InternalErrors[0]
}
return result, err
}