Skip to content

Commit

Permalink
Merge branch 'field-visibility' of github.com:carlagouveia/graphql-ph…
Browse files Browse the repository at this point in the history
…p into field-visibility
  • Loading branch information
carlagouveia committed Sep 28, 2023
2 parents d84d73c + cda80c3 commit 2f1a131
Show file tree
Hide file tree
Showing 24 changed files with 185 additions and 207 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/autoformat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ jobs:
composer-normalize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: shivammathur/setup-php@v2
with:
coverage: none
extensions: mbstring
php-version: 7.4
php-version: 8.2

- uses: ramsey/composer-install@v2

Expand All @@ -30,15 +30,15 @@ jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: shivammathur/setup-php@v2
with:
coverage: none
extensions: mbstring
php-version: 8.1
php-version: 8.2

- uses: ramsey/composer-install@v2

Expand All @@ -55,15 +55,15 @@ jobs:
php-cs-fixer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: shivammathur/setup-php@v2
with:
coverage: none
extensions: mbstring
php-version: 7.4
php-version: 8.2

- uses: ramsey/composer-install@v2

Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ on:

jobs:
deploy-docs:
name: Deploy docs
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@1.26
- uses: mhausenblas/mkdocs-deploy-gh-pages@1.26 # https://github.com/mhausenblas/mkdocs-deploy-gh-pages/releases
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

Expand All @@ -84,7 +84,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

## v15.6.3

### Fixed

- Fix printing of single line descriptions with Unicode https://github.com/webonyx/graphql-php/pull/1436

## v15.6.2

### Fixed
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ bench: ## Runs benchmarks with phpbench
.PHONY: docs
docs: ## Generate the class-reference docs
php generate-class-reference.php
prettier --write docs/class-reference.md

vendor: composer.json composer.lock
composer install
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
"amphp/http-server": "^2.1",
"dms/phpunit-arraysubset-asserts": "dev-master",
"ergebnis/composer-normalize": "^2.28",
"friendsofphp/php-cs-fixer": "3.28.0",
"mll-lab/php-cs-fixer-config": "^5",
"nyholm/psr7": "^1.5",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "1.10.32",
"phpstan/phpstan": "1.10.35",
"phpstan/phpstan-phpunit": "1.3.14",
"phpstan/phpstan-strict-rules": "1.5.1",
"phpunit/phpunit": "^9.5 || ^10",
Expand Down
23 changes: 19 additions & 4 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
## Protection Against Malicious Queries

GraphQL allows a large degree of dynamism and flexibility for clients to control what happens on the server during query execution.
Malicious clients may abuse this by sending very deep and complex queries whose execution exhausts server resources.

At a basic level, it is recommended to limit the resources a single HTTP request can use through PHP settings such as:

- [`max_execution_time`](https://www.php.net/manual/en/info.configuration.php#ini.max-execution-time)
- [`memory_limit`](https://www.php.net/manual/en/ini.core.php#ini.memory-limit)
- [`post_max_size`](https://www.php.net/manual/en/ini.core.php#ini.post-max-size)

In addition, graphql-php offers security mechanisms that are specific to GraphQL.

## Query Complexity Analysis

This is a PHP port of [Query Complexity Analysis](https://sangria-graphql.github.io/learn/#query-complexity-analysis) in Sangria implementation.
This is a port of [Query Complexity Analysis in Sangria](https://sangria-graphql.github.io/learn#query-complexity-analysis).

Complexity analysis is a separate validation rule which calculates query complexity score before execution.
Every field in the query gets a default score 1 (including ObjectType nodes). Total complexity of the
Expand Down Expand Up @@ -48,10 +61,12 @@ $type = new ObjectType([

## Limiting Query Depth

This is a PHP port of [Limiting Query Depth](https://sangria-graphql.github.io/learn/#limiting-query-depth) in Sangria implementation.
For example, max depth of the introspection query is **7**.
This is a port of [Limiting Query Depth in Sangria](https://sangria-graphql.github.io/learn#limiting-query-depth).

This is a simpler approach that limits the nesting depth a query can have.
For example, the depth of the default introspection query is **7**.

It is disabled by default. You may enable it by setting a maximum query depth:
This rule is disabled by default. You may enable it by setting a maximum query depth:

```php
use GraphQL\GraphQL;
Expand Down
6 changes: 1 addition & 5 deletions src/Executor/ReferenceExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,7 @@ protected function resolveField(ObjectType $parentType, $rootValue, \ArrayObject

$fieldName = $fieldNode->name->value;
$fieldDef = $this->getFieldDef($exeContext->schema, $parentType, $fieldName);
if ($fieldDef === null) {
return static::$UNDEFINED;
}

if (! $fieldDef->isVisible($contextValue)) {
if ($fieldDef === null || ! $fieldDef->isVisible()) {
return static::$UNDEFINED;
}

Expand Down
76 changes: 32 additions & 44 deletions src/Language/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
use GraphQL\Utils\Utils;

/**
* A Lexer is a stateful stream generator in that every time
* it is advanced, it returns the next token in the Source. Assuming the
* source lexes, the final Token emitted by the lexer will be of kind
* EOF, after which the lexer will repeatedly return the same EOF token
* whenever called.
* A lexer is a stateful stream generator, it returns the next token in the Source when advanced.
* Assuming the source is valid, the final returned token will be EOF,
* after which the lexer will repeatedly return the same EOF token whenever called.
*
* Algorithm is O(N) both on memory and time.
*
Expand All @@ -20,8 +18,8 @@
*/
class Lexer
{
// https://spec.graphql.org/October2021/#sec-Punctuators
private const TOKEN_BANG = 33;
private const TOKEN_HASH = 35;
private const TOKEN_DOLLAR = 36;
private const TOKEN_AMP = 38;
private const TOKEN_PAREN_L = 40;
Expand Down Expand Up @@ -119,19 +117,19 @@ private function readToken(Token $prev): Token
[, $code, $bytes] = $this->readChar(true);

switch ($code) {
case self::TOKEN_BANG:
case self::TOKEN_BANG: // !
return new Token(Token::BANG, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_HASH: // #
case 35: // #
$this->moveStringCursor(-1, -1 * $bytes);

return $this->readComment($line, $col, $prev);
case self::TOKEN_DOLLAR:
case self::TOKEN_DOLLAR: // $
return new Token(Token::DOLLAR, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_AMP:
case self::TOKEN_AMP: // &
return new Token(Token::AMP, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_PAREN_L:
case self::TOKEN_PAREN_L: // (
return new Token(Token::PAREN_L, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_PAREN_R:
case self::TOKEN_PAREN_R: // )
return new Token(Token::PAREN_R, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_DOT: // .
[, $charCode1] = $this->readChar(true);
Expand All @@ -142,21 +140,21 @@ private function readToken(Token $prev): Token
}

break;
case self::TOKEN_COLON:
case self::TOKEN_COLON: // :
return new Token(Token::COLON, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_EQUALS:
case self::TOKEN_EQUALS: // =
return new Token(Token::EQUALS, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_AT:
case self::TOKEN_AT: // @
return new Token(Token::AT, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_BRACKET_L:
case self::TOKEN_BRACKET_L: // [
return new Token(Token::BRACKET_L, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_BRACKET_R:
case self::TOKEN_BRACKET_R: // ]
return new Token(Token::BRACKET_R, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_BRACE_L:
case self::TOKEN_BRACE_L: // {
return new Token(Token::BRACE_L, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_PIPE:
case self::TOKEN_PIPE: // |
return new Token(Token::PIPE, $position, $position + 1, $line, $col, $prev);
case self::TOKEN_BRACE_R:
case self::TOKEN_BRACE_R: // }
return new Token(Token::BRACE_R, $position, $position + 1, $line, $col, $prev);
// A-Z
case 65:
Expand Down Expand Up @@ -416,18 +414,17 @@ private function readString(int $line, int $col, Token $prev): Token
$start = $this->position;

// Skip leading quote and read first string char:
[$char, $code, $bytes] = $this->moveStringCursor(1, 1)->readChar();
[$char, $code, $bytes] = $this->moveStringCursor(1, 1)
->readChar();

$chunk = '';
$value = '';

while (
$code !== null
// not LineTerminator
&& $code !== 10 && $code !== 13
&& $code !== 10 && $code !== 13 // not LineTerminator
) {
// Closing Quote (")
if ($code === 34) {
if ($code === 34) { // Closing Quote (")
$value .= $chunk;

// Skip quote
Expand Down Expand Up @@ -462,8 +459,8 @@ private function readString(int $line, int $col, Token $prev): Token
$value .= '\\';
break;
case 98:
$value .= \chr(8);
break; // \b (backspace)
$value .= \chr(8); // \b (backspace)
break;

Check warning on line 463 in src/Language/Lexer.php

View check run for this annotation

Codecov / codecov/patch

src/Language/Lexer.php#L462-L463

Added lines #L462 - L463 were not covered by tests
case 102:
$value .= "\f";
break;
Expand All @@ -478,7 +475,7 @@ private function readString(int $line, int $col, Token $prev): Token
break;
case 117:
$position = $this->position;
[$hex] = $this->readChars(4, true);
[$hex] = $this->readChars(4);
if (\preg_match('/[0-9a-fA-F]{4}/', $hex) !== 1) {
throw new SyntaxError(
$this->source,
Expand All @@ -493,7 +490,7 @@ private function readString(int $line, int $col, Token $prev): Token
// UTF-16 surrogate pair detection and handling.
$highOrderByte = $code >> 8;
if ($highOrderByte >= 0xD8 && $highOrderByte <= 0xDF) {
[$utf16Continuation] = $this->readChars(6, true);
[$utf16Continuation] = $this->readChars(6);
if (\preg_match('/^\\\u[0-9a-fA-F]{4}$/', $utf16Continuation) !== 1) {
throw new SyntaxError(
$this->source,
Expand Down Expand Up @@ -623,11 +620,8 @@ private function assertValidStringCharacterCode(int $code, int $position): void
{
// SourceCharacter
if ($code < 0x0020 && $code !== 0x0009) {
throw new SyntaxError(
$this->source,
$position,
'Invalid character within String: ' . Utils::printCharCode($code)
);
$char = Utils::printCharCode($code);
throw new SyntaxError($this->source, $position, "Invalid character within String: {$char}");
}
}

Expand All @@ -639,11 +633,8 @@ private function assertValidBlockStringCharacterCode(int $code, int $position):
{
// SourceCharacter
if ($code < 0x0020 && $code !== 0x0009 && $code !== 0x000A && $code !== 0x000D) {
throw new SyntaxError(
$this->source,
$position,
'Invalid character within String: ' . Utils::printCharCode($code)
);
$char = Utils::printCharCode($code);
throw new SyntaxError($this->source, $position, "Invalid character within String: {$char}");
}
}

Expand Down Expand Up @@ -739,7 +730,6 @@ private function readChar(bool $advance = false, int $byteStreamPosition = null)
$bytes = 4;
}

$utf8char = '';
for ($pos = $byteStreamPosition; $pos < $byteStreamPosition + $bytes; ++$pos) {
$utf8char .= $this->source->body[$pos];
}
Expand All @@ -762,7 +752,7 @@ private function readChar(bool $advance = false, int $byteStreamPosition = null)
*
* @return array{string, int}
*/
private function readChars(int $charCount, bool $advance): array
private function readChars(int $charCount): array
{
$result = '';
$totalBytes = 0;
Expand All @@ -775,9 +765,7 @@ private function readChars(int $charCount, bool $advance): array
$result .= $char;
}

if ($advance) {
$this->moveStringCursor($charCount, $totalBytes);
}
$this->moveStringCursor($charCount, $totalBytes);

return [$result, $totalBytes];
}
Expand Down
Loading

0 comments on commit 2f1a131

Please sign in to comment.