mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-25 22:36:02 +03:00
Merge pull request #131 from n1ru4l/feature-disable-introspection-validation-rule
Add DisableIntrospection validation rule
This commit is contained in:
commit
141afc1cf7
18
README.md
18
README.md
@ -559,6 +559,24 @@ $queryDepth->setMaxQueryDepth($maxQueryDepth = 10);
|
|||||||
GraphQL::execute(/*...*/);
|
GraphQL::execute(/*...*/);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Disabling Introspection
|
||||||
|
|
||||||
|
This is a PHP port of [graphql-disable-introspection](https://github.com/helfer/graphql-disable-introspection).
|
||||||
|
The rule prohibits queries that contain `__type` or `__schema` fields.
|
||||||
|
|
||||||
|
This document validator rule is disabled by default. Here an example to enable it:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use GraphQL\GraphQL;
|
||||||
|
use GraphQL\Validator\Rules\DisableIntrospection;
|
||||||
|
|
||||||
|
/** @var \GraphQL\Validator\Rules\DisableIntrospection $disableIntrospection */
|
||||||
|
$disableIntrospection = DocumentValidator::getRule('DisableIntrospection');
|
||||||
|
$disableIntrospection->setEnabled(DisableIntrospection::ENABLED);
|
||||||
|
|
||||||
|
GraphQL::execute(/*...*/);
|
||||||
|
```
|
||||||
|
|
||||||
### More Examples
|
### More Examples
|
||||||
Make sure to check [tests](https://github.com/webonyx/graphql-php/tree/master/tests) for more usage examples.
|
Make sure to check [tests](https://github.com/webonyx/graphql-php/tree/master/tests) for more usage examples.
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ use GraphQL\Utils;
|
|||||||
use GraphQL\Utils\TypeInfo;
|
use GraphQL\Utils\TypeInfo;
|
||||||
use GraphQL\Validator\Rules\ArgumentsOfCorrectType;
|
use GraphQL\Validator\Rules\ArgumentsOfCorrectType;
|
||||||
use GraphQL\Validator\Rules\DefaultValuesOfCorrectType;
|
use GraphQL\Validator\Rules\DefaultValuesOfCorrectType;
|
||||||
|
use GraphQL\Validator\Rules\DisableIntrospection;
|
||||||
use GraphQL\Validator\Rules\FieldsOnCorrectType;
|
use GraphQL\Validator\Rules\FieldsOnCorrectType;
|
||||||
use GraphQL\Validator\Rules\FragmentsOnCompositeTypes;
|
use GraphQL\Validator\Rules\FragmentsOnCompositeTypes;
|
||||||
use GraphQL\Validator\Rules\KnownArgumentNames;
|
use GraphQL\Validator\Rules\KnownArgumentNames;
|
||||||
@ -100,6 +101,7 @@ class DocumentValidator
|
|||||||
'UniqueInputFieldNames' => new UniqueInputFieldNames(),
|
'UniqueInputFieldNames' => new UniqueInputFieldNames(),
|
||||||
|
|
||||||
// Query Security
|
// Query Security
|
||||||
|
'DisableIntrospection' => new DisableIntrospection(DisableIntrospection::DISABLED), // DEFAULT DISABLED
|
||||||
'QueryDepth' => new QueryDepth(QueryDepth::DISABLED), // default disabled
|
'QueryDepth' => new QueryDepth(QueryDepth::DISABLED), // default disabled
|
||||||
'QueryComplexity' => new QueryComplexity(QueryComplexity::DISABLED), // default disabled
|
'QueryComplexity' => new QueryComplexity(QueryComplexity::DISABLED), // default disabled
|
||||||
];
|
];
|
||||||
|
50
src/Validator/Rules/DisableIntrospection.php
Normal file
50
src/Validator/Rules/DisableIntrospection.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Validator\Rules;
|
||||||
|
|
||||||
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Language\AST\FieldNode;
|
||||||
|
use GraphQL\Language\AST\NodeKind;
|
||||||
|
use GraphQL\Validator\ValidationContext;
|
||||||
|
|
||||||
|
class DisableIntrospection extends AbstractQuerySecurity
|
||||||
|
{
|
||||||
|
const ENABLED = 1;
|
||||||
|
private $isEnabled;
|
||||||
|
|
||||||
|
public function __construct($enabled)
|
||||||
|
{
|
||||||
|
$this->setEnabled($enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEnabled($enabled)
|
||||||
|
{
|
||||||
|
$this->isEnabled = $enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function introspectionDisabledMessage()
|
||||||
|
{
|
||||||
|
return 'GraphQL introspection is not allowed, but the query contained __schema or __type';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isEnabled()
|
||||||
|
{
|
||||||
|
return $this->isEnabled !== static::DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(ValidationContext $context)
|
||||||
|
{
|
||||||
|
return $this->invokeIfNeeded(
|
||||||
|
$context,
|
||||||
|
[
|
||||||
|
NodeKind::FIELD => function (FieldNode $node) use ($context) {
|
||||||
|
if ($node->name->value === '__type' || $node->name->value === '__schema') {
|
||||||
|
$context->reportError(new Error(
|
||||||
|
static::introspectionDisabledMessage(),
|
||||||
|
[$node]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
128
tests/Validator/DisableIntrospectionTest.php
Normal file
128
tests/Validator/DisableIntrospectionTest.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Tests\Validator;
|
||||||
|
|
||||||
|
use GraphQL\Error\FormattedError;
|
||||||
|
use GraphQL\Language\SourceLocation;
|
||||||
|
use GraphQL\Validator\Rules\DisableIntrospection;
|
||||||
|
|
||||||
|
class DisableIntrospectionTest extends TestCase
|
||||||
|
{
|
||||||
|
// Validate: Disable Introspection
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it fails if the query contains __schema
|
||||||
|
*/
|
||||||
|
public function testQueryContainsSchema()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new DisableIntrospection(DisableIntrospection::ENABLED), '
|
||||||
|
query {
|
||||||
|
__schema {
|
||||||
|
queryType {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
',
|
||||||
|
[$this->error(3, 9)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it fails if the query contains __type
|
||||||
|
*/
|
||||||
|
public function testQueryContainsType()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new DisableIntrospection(DisableIntrospection::ENABLED), '
|
||||||
|
query {
|
||||||
|
__type(
|
||||||
|
name: "Query"
|
||||||
|
){
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
',
|
||||||
|
[$this->error(3, 9)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it does not fail on a query that does not contain __type
|
||||||
|
*/
|
||||||
|
public function testValidQuery()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new DisableIntrospection(DisableIntrospection::ENABLED), '
|
||||||
|
query {
|
||||||
|
user {
|
||||||
|
name
|
||||||
|
email
|
||||||
|
friends {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it does not fail when not enabled
|
||||||
|
*/
|
||||||
|
public function testQueryWhenDisabled()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new DisableIntrospection(DisableIntrospection::DISABLED), '
|
||||||
|
query {
|
||||||
|
__type(
|
||||||
|
name: "Query"
|
||||||
|
){
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it has a public interface for enabeling the rule
|
||||||
|
*/
|
||||||
|
public function testPublicEnableInterface()
|
||||||
|
{
|
||||||
|
$disableIntrospection = new DisableIntrospection(DisableIntrospection::DISABLED);
|
||||||
|
$disableIntrospection->setEnabled(DisableIntrospection::ENABLED);
|
||||||
|
$this->expectFailsRule($disableIntrospection, '
|
||||||
|
query {
|
||||||
|
__type(
|
||||||
|
name: "Query"
|
||||||
|
){
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
',
|
||||||
|
[$this->error(3, 9)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it has a public interface for disableing the rule
|
||||||
|
*/
|
||||||
|
public function testPublicDisableInterface()
|
||||||
|
{
|
||||||
|
$disableIntrospection = new DisableIntrospection(DisableIntrospection::ENABLED);
|
||||||
|
$disableIntrospection->setEnabled(DisableIntrospection::DISABLED);
|
||||||
|
$this->expectPassesRule($disableIntrospection, '
|
||||||
|
query {
|
||||||
|
__type(
|
||||||
|
name: "Query"
|
||||||
|
){
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function error($line, $column)
|
||||||
|
{
|
||||||
|
return FormattedError::create(
|
||||||
|
DisableIntrospection::introspectionDisabledMessage(),
|
||||||
|
[ new SourceLocation($line, $column) ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user