Skip to content

Commit

Permalink
MERL-803: overriding introspection (#1594)
Browse files Browse the repository at this point in the history
* initial commit for overriding introspection via WP filter

* added test for filter value

* test: confirm behavior of `filter_introspection()`

* chore: adjust error message in `generatePossibleTypes()`

* chore: add changeset

---------

Co-authored-by: John Parris <[email protected]>
Co-authored-by: Jason Bahl <[email protected]>
  • Loading branch information
3 people authored Oct 12, 2023
1 parent 604e9e3 commit d3d30aa
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/serious-monkeys-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@faustwp/cli': minor
'@faustwp/wordpress-plugin': minor
---

Added support for authenticated WPGraphQL introspection queries using FAUST_SECRET_KEY. It is no longer required to enable "Public Introspection" in WPGraphQL.
5 changes: 3 additions & 2 deletions packages/faustwp-cli/src/generatePossibleTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'isomorphic-fetch';
import fs from 'fs';

import { infoLog, errorLog, debugLog } from './stdout/index.js';
import { getGraphqlEndpoint, getWpUrl } from './utils/index.js';
import { getGraphqlEndpoint, getWpSecret, getWpUrl } from './utils/index.js';

type PossibleTypes = {
[key: string]: any;
Expand All @@ -25,6 +25,7 @@ export async function generatePossibleTypes(): Promise<void> {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-faust-secret': getWpSecret() || '',
},
body: JSON.stringify({
variables: {},
Expand Down Expand Up @@ -81,7 +82,7 @@ export async function generatePossibleTypes(): Promise<void> {

errorLog("Unable to update this project's possibleTypes schema");
errorLog(
`Make sure you have "Enable Public Introspection" checked in WPGraphQL: ${getWpUrl()}/wp-admin/admin.php?page=graphql-settings`,
`Make sure the FAUST_SECRET_KEY value in your environment matches the value in the Faust WordPress plugin settings, or that you have "Enable Public Introspection" checked in WPGraphQL if not using FAUST_SECRET_KEY: ${getWpUrl()}/wp-admin/admin.php?page=graphql-settings`,
);

process.exit(0);
Expand Down
30 changes: 30 additions & 0 deletions plugins/faustwp/includes/graphql/callbacks.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace WPE\FaustWP\GraphQL;

use function WPE\FaustWP\Auth\generate_authorization_code;
use function WPE\FaustWP\Settings\get_secret_key;
use GraphQL\Type\Definition\ResolveInfo;
use WPGraphQL\AppContext;

Expand Down Expand Up @@ -44,6 +45,35 @@ function register_templates_field() {
);
}

add_filter( 'graphql_get_setting_section_field_value', __NAMESPACE__ . '\\filter_introspection', 10, 5 );
/**
* Enables WPGraphQL public introspection option
* when authenticated requests come from Faust.
*
* @param mixed $value The value of the field.
* @param mixed $default_value The default value if there is no value set.
* @param string $option_name The name of the option.
* @param array $section_fields The setting values within the section.
* @param string $section_name The name of the section the setting belongs to.
*/
function filter_introspection( $value, $default_value, $option_name, $section_fields, $section_name ) {
if ( 'public_introspection_enabled' !== $option_name ) {
return $value;
}

// check header for faust secret key.
if ( ! isset( $_SERVER['HTTP_X_FAUST_SECRET'] ) ) {
return $value;
};

$secret_key = get_secret_key();
if ( $secret_key !== $_SERVER['HTTP_X_FAUST_SECRET'] ) {
return $value;
}

return 'on';
}

add_action( 'graphql_register_types', __NAMESPACE__ . '\\register_faust_toolbar_field' );
/**
* Registers a field on the User model called "shouldShowFaustToolbar" which
Expand Down
77 changes: 77 additions & 0 deletions plugins/faustwp/tests/integration/GraphQLCallbacksTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
faustwp_update_setting,
};

use function WPE\FaustWP\GraphQL\{
filter_introspection,
};

class GraphQLCallbacksTests extends \WP_UnitTestCase {

private $graphqlResponse;
Expand Down Expand Up @@ -107,6 +111,10 @@ public function setUp(): void {
$this->graphqlResponse->data = $this->responseData;
}

public function test_graphql_section_field_value() {
$this->assertSame( 10, has_action( 'graphql_get_setting_section_field_value', 'WPE\FaustWP\GraphQL\filter_introspection' ) );
}

public function test_graphql_request_results_filter() {
$this->assertSame( 10, has_action( 'graphql_request_results', 'WPE\FaustWP\Replacement\url_replacement' ) );
}
Expand Down Expand Up @@ -137,4 +145,73 @@ public function test_url_replacement_replaces_url_fields_when_rewrites_are_enabl
$filteredRespone = url_replacement( $this->graphqlResponse );
$this->assertSame( $this->expectedData, $filteredRespone->data );
}

/**
* Tests filter_introspection() does not modify values unrelated to public introspection.
*/
public function test_filter_introspection_returns_same_value_for_unrelated_option_name(): void {
$input = 'leave me alone';
self::assertSame(
$input,
filter_introspection( $input, false, 'stylesheet', [], 'default' )
);
}

/**
* Tests filter_introspection() does not enable public introspection when the Faust secret key is not present.
*/
public function test_filter_introspection_returns_same_value_when_faust_secret_key_is_not_present(): void {
$input = 'leave me alone';
self::assertSame(
$input,
filter_introspection( $input, false, 'public_introspection_enabled', [], 'default' )
);
}

/**
* Tests filter_introspection() does not enable public introspection when the Faust secret key is incorrect.
*/
public function test_filter_introspection_returns_same_value_when_faust_secret_key_is_present_but_incorrect(): void {
global $_SERVER;
$_SERVER['HTTP_X_FAUST_SECRET'] = 'wrong-key';

$input = 'leave me alone';
self::assertSame(
$input,
filter_introspection( $input, false, 'public_introspection_enabled', [], 'default' )
);
}

/**
* Tests filter_introspection() enables public introspection when the Faust secret key is correct.
*/
public function test_filter_introspection_returns_on_when_faust_secret_key_is_present_and_correct(): void {
global $_SERVER;
$_SERVER['HTTP_X_FAUST_SECRET'] = 'correct-key';

tests_add_filter( 'faustwp_get_setting', [ $this, 'filter_secret_key' ], 10, 3 );

$input = 'this should not be returned. "on" should be returned.';

self::assertSame(
'on',
filter_introspection( $input, false, 'public_introspection_enabled', [], 'default' )
);

remove_filter( 'faustwp_get_setting', [ $this, 'filter_secret_key' ] );
}

/**
* Filters the secret key value for testing.
*
* @param mixed $value The setting value.
* @param string $name The setting name.
* @param mixed $default Optional setting value.
*/
public function filter_secret_key( $value, $name, $default ) {
if ( 'secret_key' !== $name ) {
return $value;
}
return 'correct-key';
}
}

0 comments on commit d3d30aa

Please sign in to comment.