Skip to content

Commit

Permalink
Add ProhibitIntrospectionQueriesRule
Browse files Browse the repository at this point in the history
  • Loading branch information
danielrearden committed Jun 3, 2020
1 parent 4f35752 commit e95cc70
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
@@ -0,0 +1,3 @@
{
"javascript.validate.enable": false
}
146 changes: 146 additions & 0 deletions src/validation/__tests__/ProhibitIntrospectionQueriesRule-test.js
@@ -0,0 +1,146 @@
// @flow strict

import { describe, it } from 'mocha';

import { ProhibitIntrospectionQueriesRule } from '../rules/optional/ProhibitIntrospectionQueriesRule';

import {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
__Schema,
} from '../../type/index';

import { expectValidationErrorsWithSchema } from './harness';

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
someQuery: {
type: new GraphQLObjectType({
name: 'SomeType',
fields: {
someField: { type: GraphQLString },
introspectionField: { type: __Schema },
},
}),
},
},
}),
});

function expectErrors(queryStr) {
return expectValidationErrorsWithSchema(
schema,
ProhibitIntrospectionQueriesRule,
queryStr,
);
}

function expectValid(queryStr) {
expectErrors(queryStr).to.deep.equal([]);
}

describe('Validate: Prohibit introspection queries', () => {
it('ignores valid fields including __typename', () => {
expectValid(`
{
someQuery {
__typename
someField
}
}
`);
});

it('ignores fields not in the schema', () => {
expectValid(`
{
__introspect
}
`);
});

it('reports error when a field with introspection type is requested', () => {
expectErrors(`
{
__schema {
queryType {
name
}
}
}
`).to.deep.equal([
{
locations: [
{
column: 9,
line: 3,
},
],
message:
'GraphQL introspection has been disabled, but the requested query contained the field "__schema".',
},
{
locations: [
{
column: 11,
line: 4,
},
],
message:
'GraphQL introspection has been disabled, but the requested query contained the field "queryType".',
},
]);
});

it('reports error when a field with an introspection type is requested and aliased', () => {
expectErrors(`
{
s: __schema {
queryType {
name
}
}
}
`).to.deep.equal([
{
locations: [
{
column: 9,
line: 3,
},
],
message:
'GraphQL introspection has been disabled, but the requested query contained the field "__schema".',
},
{
locations: [
{
column: 11,
line: 4,
},
],
message:
'GraphQL introspection has been disabled, but the requested query contained the field "queryType".',
},
]);
});

it('reports error for non-standard introspection fields', () => {
expectErrors(`
{
someQuery {
introspectionField
}
}
`).to.deep.equal([
{
message:
'GraphQL introspection has been disabled, but the requested query contained the field "introspectionField".',
locations: [{ line: 4, column: 11 }],
},
]);
});
});
3 changes: 3 additions & 0 deletions src/validation/index.js
Expand Up @@ -94,3 +94,6 @@ export { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule';
export { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule';
export { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule';
export { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule';

// Optional rules not defined by the GraphQL Specification
export { ProhibitIntrospectionQueriesRule } from './rules/optional/ProhibitIntrospectionQueriesRule';
@@ -0,0 +1,16 @@
import { ASTVisitor } from '../../../language/visitor';
import { ValidationContext } from '../../ValidationContext';

/**
* Prohibit introspection queries
*
* A GraphQL document is only valid if all fields selected are not fields that
* return an introspection type.
*
* Note: This rule is optional and is not part of the Validation section of the
* GraphQL Specification. This rule effectively disables introspection, which
* does not reflect best practices and should only be done if absolutely necessary.
*/
export function ProhibitIntrospectionQueriesRule(
context: ValidationContext,
): ASTVisitor;
41 changes: 41 additions & 0 deletions src/validation/rules/optional/ProhibitIntrospectionQueriesRule.js
@@ -0,0 +1,41 @@
// @flow strict

import { GraphQLError } from '../../../error/GraphQLError';

import { type FieldNode } from '../../../language/ast';
import { type ASTVisitor } from '../../../language/visitor';

import { type ValidationContext } from '../../ValidationContext';

import { getNamedType } from '../../../type/definition';
import { isIntrospectionType } from '../../../type/introspection';

/**
* Prohibit introspection queries
*
* A GraphQL document is only valid if all fields selected are not fields that
* return an introspection type.
*
* Note: This rule is optional and is not part of the Validation section of the
* GraphQL Specification. This rule effectively disables introspection, which
* does not reflect best practices and should only be done if absolutely necessary.
*/
export function ProhibitIntrospectionQueriesRule(
context: ValidationContext,
): ASTVisitor {
return {
Field(node: FieldNode) {
const fieldType = context.getType();
if (fieldType) {
if (isIntrospectionType(getNamedType(fieldType))) {
context.reportError(
new GraphQLError(
`GraphQL introspection has been disabled, but the requested query contained the field "${node.name.value}".`,
node,
),
);
}
}
},
};
}

0 comments on commit e95cc70

Please sign in to comment.