1818import java .util .Optional ;
1919import java .util .concurrent .atomic .AtomicBoolean ;
2020
21+ import static graphql .normalized .ExecutableNormalizedOperationFactory .Options ;
22+ import static graphql .normalized .ExecutableNormalizedOperationFactory .createExecutableNormalizedOperation ;
2123import static graphql .schema .FieldCoordinates .coordinates ;
2224
2325/**
@@ -44,6 +46,14 @@ public class GoodFaithIntrospection {
4446 public static final String GOOD_FAITH_INTROSPECTION_DISABLED = "GOOD_FAITH_INTROSPECTION_DISABLED" ;
4547
4648 private static final AtomicBoolean ENABLED_STATE = new AtomicBoolean (true );
49+ /**
50+ * This is the maximum number of executable fields that can be in a good faith introspection query
51+ */
52+ public static final int GOOD_FAITH_MAX_FIELDS_COUNT = 500 ;
53+ /**
54+ * This is the maximum depth a good faith introspection query can be
55+ */
56+ public static final int GOOD_FAITH_MAX_DEPTH_COUNT = 20 ;
4757
4858 /**
4959 * @return true if good faith introspection is enabled
@@ -75,7 +85,7 @@ public static boolean enabledJvmWide(boolean flag) {
7585
7686 public static Optional <ExecutionResult > checkIntrospection (ExecutionContext executionContext ) {
7787 if (isIntrospectionEnabled (executionContext .getGraphQLContext ())) {
78- ExecutableNormalizedOperation operation = executionContext . getNormalizedQueryTree (). get ( );
88+ ExecutableNormalizedOperation operation = mkOperation ( executionContext );
7989 ImmutableListMultimap <FieldCoordinates , ExecutableNormalizedField > coordinatesToENFs = operation .getCoordinatesToNormalizedFields ();
8090 for (Map .Entry <FieldCoordinates , Integer > entry : ALLOWED_FIELD_INSTANCES .entrySet ()) {
8191 FieldCoordinates coordinates = entry .getKey ();
@@ -90,6 +100,29 @@ public static Optional<ExecutionResult> checkIntrospection(ExecutionContext exec
90100 return Optional .empty ();
91101 }
92102
103+ /**
104+ * This makes an executable operation limited in size then which suits a good faith introspection query. This helps guard
105+ * against malicious queries.
106+ *
107+ * @param executionContext the execution context
108+ *
109+ * @return an executable operation
110+ */
111+ private static ExecutableNormalizedOperation mkOperation (ExecutionContext executionContext ) {
112+ Options options = Options .defaultOptions ()
113+ .maxFieldsCount (GOOD_FAITH_MAX_FIELDS_COUNT )
114+ .maxChildrenDepth (GOOD_FAITH_MAX_DEPTH_COUNT )
115+ .locale (executionContext .getLocale ())
116+ .graphQLContext (executionContext .getGraphQLContext ());
117+
118+ return createExecutableNormalizedOperation (executionContext .getGraphQLSchema (),
119+ executionContext .getOperationDefinition (),
120+ executionContext .getFragmentsByName (),
121+ executionContext .getCoercedVariables (),
122+ options );
123+
124+ }
125+
93126 private static boolean isIntrospectionEnabled (GraphQLContext graphQlContext ) {
94127 if (!isEnabledJvmWide ()) {
95128 return false ;
0 commit comments