diff --git a/projects/plugins/jetpack/changelog/dsgcom-534-validate-site-verification-codes b/projects/plugins/jetpack/changelog/dsgcom-534-validate-site-verification-codes new file mode 100644 index 000000000000..4d82de2c40a9 --- /dev/null +++ b/projects/plugins/jetpack/changelog/dsgcom-534-validate-site-verification-codes @@ -0,0 +1,4 @@ +Significance: patch +Type: bugfix + +Site Verification: Reject invalid verification codes instead of reporting a successful save. diff --git a/projects/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php b/projects/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php index 1b1b96fa48d4..1f61f86facee 100644 --- a/projects/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php +++ b/projects/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php @@ -1235,6 +1235,21 @@ function ( &$value ) { case 'verification_services_codes': $verification_codes = jetpack_verification_validate( $value ); + foreach ( $value as $service_key => $raw_code ) { + if ( '' === $raw_code || null === $raw_code ) { + continue; + } + + $validated_code = $verification_codes[ $service_key ] ?? ''; + if ( '' === $validated_code ) { + return new WP_Error( + 'invalid_input', + __( 'Invalid site verification code. Enter only the content value from the meta tag.', 'jetpack' ), + 400 + ); + } + } + if ( update_option( 'verification_services_codes', $verification_codes ) ) { $updated[ $key ] = $verification_codes; } diff --git a/projects/plugins/jetpack/modules/verification-tools/verification-tools-utils.php b/projects/plugins/jetpack/modules/verification-tools/verification-tools-utils.php index 1f916e96a55e..268bcafe284e 100644 --- a/projects/plugins/jetpack/modules/verification-tools/verification-tools-utils.php +++ b/projects/plugins/jetpack/modules/verification-tools/verification-tools-utils.php @@ -13,17 +13,25 @@ * @param array $verification_services_codes - array of verification codes. */ function jetpack_verification_validate( $verification_services_codes ) { + $code_pattern = '/^[a-z0-9_-]+$/i'; + foreach ( $verification_services_codes as $key => $code ) { + $code = is_scalar( $code ) ? (string) $code : ''; + // Parse html meta tag if it does not look like a valid code. - if ( ! preg_match( '/^[a-z0-9_-]+$/i', $code ) ) { + if ( ! preg_match( $code_pattern, $code ) ) { $code = jetpack_verification_get_code( $code ); } - $code = esc_attr( trim( $code ) ); + $code = esc_attr( trim( (string) $code ) ); // limit length to 100 chars. $code = substr( $code, 0, 100 ); + if ( '' !== $code && ! preg_match( $code_pattern, $code ) ) { + $code = ''; + } + /** * Fire after each Verification code was validated. * diff --git a/projects/plugins/jetpack/tests/php/json-api/WPCOM_JSON_API_Site_Settings_V1_4_Endpoint_Test.php b/projects/plugins/jetpack/tests/php/json-api/WPCOM_JSON_API_Site_Settings_V1_4_Endpoint_Test.php index 1e67cc412998..84bd995bb700 100644 --- a/projects/plugins/jetpack/tests/php/json-api/WPCOM_JSON_API_Site_Settings_V1_4_Endpoint_Test.php +++ b/projects/plugins/jetpack/tests/php/json-api/WPCOM_JSON_API_Site_Settings_V1_4_Endpoint_Test.php @@ -181,6 +181,44 @@ public function test_post_settings_sets_key_values( $setting_name, $setting_valu $this->assertSame( $expected_value, $updated[ $setting_name ] ); } + /** + * Invalid site verification codes return an actionable client error and are not saved. + */ + public function test_post_rejects_invalid_site_verification_code() { + $setting = wp_json_encode( + array( 'verification_services_codes' => array( 'bing' => 'not.a.valid.token' ) ), + JSON_UNESCAPED_SLASHES + ); + + $response = $this->make_post_request( $setting ); + + $this->assertWPError( $response ); + $this->assertSame( 'invalid_input', $response->get_error_code() ); + $this->assertSame( 400, $response->get_error_data() ); + $this->assertFalse( get_option( 'verification_services_codes' ) ); + } + + /** + * A valid site verification meta tag is reduced to its content value and saved. + */ + public function test_post_saves_site_verification_code_from_meta_tag() { + $setting = wp_json_encode( + array( + 'verification_services_codes' => array( + 'bing' => '', + ), + ), + JSON_UNESCAPED_SLASHES + ); + + $response = $this->make_post_request( $setting ); + + $this->assertSame( + array( 'bing' => '12C1203B5086AECE94EB3A3D9830B2E' ), + $response['updated']['verification_services_codes'] + ); + } + /** * The free tier description is capped to 500 characters to match the * paid-tier description field. diff --git a/projects/plugins/jetpack/tests/php/modules/verification-tools/Jetpack_Verification_Tools_Utils_Test.php b/projects/plugins/jetpack/tests/php/modules/verification-tools/Jetpack_Verification_Tools_Utils_Test.php index 0327e019dc08..7dd41ea8e533 100644 --- a/projects/plugins/jetpack/tests/php/modules/verification-tools/Jetpack_Verification_Tools_Utils_Test.php +++ b/projects/plugins/jetpack/tests/php/modules/verification-tools/Jetpack_Verification_Tools_Utils_Test.php @@ -1,6 +1,7 @@ assertSame( + array( $service => $code ), + jetpack_verification_validate( array( $service => $code ) ) + ); + } + + /** + * Verification codes with invalid characters are rejected for every service. + * + * @dataProvider invalid_verification_code_provider + * + * @param string $service Verification service key. + * @param string $code Verification code. + */ + #[DataProvider( 'invalid_verification_code_provider' )] + public function test_invalid_code_is_rejected_for_every_service( $service, $code ) { + $this->assertSame( + array( $service => '' ), + jetpack_verification_validate( array( $service => $code ) ) + ); + } + + /** + * Provide valid verification codes. + * + * @return array Test cases. + */ + public static function valid_verification_code_provider() { + return array( + 'google' => array( 'google', 'verification_Code-123' ), + 'bing' => array( 'bing', 'verification_Code-123' ), + 'pinterest' => array( 'pinterest', 'verification_Code-123' ), + 'yandex' => array( 'yandex', 'verification_Code-123' ), + 'facebook' => array( 'facebook', 'verification_Code-123' ), + ); + } + + /** + * Provide invalid verification codes. + * + * @return array Test cases. + */ + public static function invalid_verification_code_provider() { + return array( + 'google' => array( 'google', 'invalid.code' ), + 'bing' => array( 'bing', 'invalid.code' ), + 'pinterest' => array( 'pinterest', 'invalid.code' ), + 'yandex' => array( 'yandex', 'invalid.code' ), + 'facebook' => array( 'facebook', 'invalid.code' ), + ); + } }