Skip to content

Commit

Permalink
Merge pull request from GHSA-mf7v-fq88-cf62
Browse files Browse the repository at this point in the history
Improve checks on proxy endpoints on v3.5
  • Loading branch information
acicovic authored Feb 13, 2023
2 parents f6c00c9 + 4452be4 commit ccad870
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.5.3](https://github.com/Parsely/wp-parsely/compare/3.5.2...3.5.3) - 2023-02-13

### Fixed

- Improve checks on proxy endpoints

## [3.5.2](https://github.com/Parsely/wp-parsely/compare/3.5.1...3.5.2) - 2022-09-27

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Parse.ly

Stable tag: 3.5.2
Stable tag: 3.5.3
Requires at least: 5.0
Tested up to: 6.0.2
Requires PHP: 7.1
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wp-parsely",
"version": "3.5.2",
"version": "3.5.3",
"private": true,
"description": "The Parse.ly plugin facilitates real-time and historical analytics to your content through a platform designed and built for digital publishing.",
"author": "parsely, hbbtstar, jblz, mikeyarce, GaryJ, parsely_mike, pauarge",
Expand Down
12 changes: 1 addition & 11 deletions src/Endpoints/class-analytics-posts-api-proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class Analytics_Posts_API_Proxy extends Base_API_Proxy {
* Registers the endpoint's WP REST route.
*/
public function run(): void {
$this->register_endpoint( '/analytics/posts' );
$this->register_endpoint( '/analytics/posts', 'publish_posts' );
}

/**
Expand Down Expand Up @@ -61,14 +61,4 @@ static function( stdClass $item ) use ( $date_format, $stats_base_url ) {

return $result;
}

/**
* Determines if there are enough permissions to call the endpoint.
*
* @return bool
*/
public function permission_callback(): bool {
// Unauthenticated.
return true;
}
}
32 changes: 29 additions & 3 deletions src/Endpoints/class-base-api-proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ abstract class Base_API_Proxy {
*/
protected $parsely;

/**
* Capability of the user based on which we should allow access to endpoint.
*
* `null` should be used for all public endpoints.
*
* @var string|null
*/
protected $user_capability;

/**
* Proxy object which does the actual calls to the Parse.ly API.
*
Expand Down Expand Up @@ -60,7 +69,19 @@ abstract public function get_items( WP_REST_Request $request ): stdClass;
*
* @return bool
*/
abstract public function permission_callback(): bool;
public function permission_callback(): bool {
// This endpoint does not require any capability checks.
if ( is_null( $this->user_capability ) ) {
return true;
}

// The user has the required capability to access this endpoint.
if ( current_user_can( $this->user_capability ) ) {
return true;
}

return false;
}

/**
* Constructor.
Expand All @@ -77,9 +98,13 @@ public function __construct( Parsely $parsely, Proxy $proxy ) {
/**
* Registers the endpoint's WP REST route.
*
* @param string $endpoint The endpoint (e.g. /analytics/posts).
* @param string $endpoint The endpoint's route (e.g. /stats/posts).
* @param string|null $user_capability Capability of the user based on which we should allow access to endpoint.
* @param bool $show_in_index Show endpoint in /wp-json view if TRUE.
*/
protected function register_endpoint( string $endpoint ): void {
protected function register_endpoint( string $endpoint, ?string $user_capability, $show_in_index = false ): void {
$this->user_capability = $user_capability;

$filter_key = trim( str_replace( '/', '_', $endpoint ), '_' );
if ( ! apply_filters( 'wp_parsely_enable_' . $filter_key . '_api_proxy', true ) ) {
return;
Expand All @@ -105,6 +130,7 @@ protected function register_endpoint( string $endpoint ): void {
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'permission_callback' ),
'args' => $get_items_args,
'show_in_index' => $show_in_index,
),
);

Expand Down
12 changes: 1 addition & 11 deletions src/Endpoints/class-related-api-proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class Related_API_Proxy extends Base_API_Proxy {
* Registers the endpoint's WP REST route.
*/
public function run(): void {
$this->register_endpoint( '/related' );
$this->register_endpoint( '/related', null, true );
}

/**
Expand Down Expand Up @@ -55,14 +55,4 @@ static function( stdClass $item ) {

return $result;
}

/**
* Determines if there are enough permissions to call the endpoint.
*
* @return bool
*/
public function permission_callback(): bool {
// Unauthenticated.
return true;
}
}
19 changes: 19 additions & 0 deletions tests/Integration/Endpoints/AnalyticsPostsProxyEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ public function test_do_not_register_route_when_proxy_is_disabled(): void {
parent::test_do_not_register_route_when_proxy_is_disabled();
}

/**
* Verifies forbidden error when current user doesn't have proper capabilities.
*
* @covers \Parsely\Endpoints\Base_API_Proxy::permission_callback
*
* @uses \Parsely\Endpoints\Base_API_Proxy::register_endpoint
* @uses \Parsely\Endpoints\Analytics_Posts_API_Proxy::register_endpoint
*/
public function test_access_of_analytics_posts_endpoint_is_forbidden(): void {
$response = rest_get_server()->dispatch( new WP_REST_Request( 'GET', self::$route ) );
$error = $response->as_error();

self::assertSame( 401, $response->get_status() );
self::assertSame( 'rest_forbidden', $error->get_error_code() );
self::assertSame( 'Sorry, you are not allowed to do that.', $error->get_error_message() );
}

/**
* Verifies that calling `GET /wp-parsely/v1/analytics/posts` returns an
* error and does not perform a remote call when the apikey is not populated
Expand All @@ -85,6 +102,7 @@ public function test_do_not_register_route_when_proxy_is_disabled(): void {
* @uses \Parsely\Endpoints\Base_API_Proxy::register_endpoint
*/
public function test_get_items_fails_without_apikey_set() {
$this->set_admin_user();
parent::test_get_items_fails_without_apikey_set();
}

Expand Down Expand Up @@ -112,6 +130,7 @@ public function test_get_items_fails_without_apikey_set() {
public function test_get_items() {
TestCase::set_options( array( 'apikey' => 'example.com' ) );
TestCase::set_options( array( 'api_secret' => 'test' ) );
$this->set_admin_user();

$dispatched = 0;
$date_format = get_option( 'date_format' );
Expand Down
10 changes: 10 additions & 0 deletions tests/Integration/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,14 @@ public function go_to_new_post(): int {

return $post_id;
}

/**
* Sets current user as admin.
*
* @param int $admin_user_id User ID for the site administrator.
* Default is 1 which is assigned to first admin user while creating the site.
*/
public function set_admin_user( $admin_user_id = 1 ): void {
wp_set_current_user( $admin_user_id );
}
}
2 changes: 1 addition & 1 deletion tests/e2e/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
visitAdminPage,
} from '@wordpress/e2e-test-utils';

export const PLUGIN_VERSION = '3.5.2';
export const PLUGIN_VERSION = '3.5.3';

export const waitForWpAdmin = () => page.waitForSelector( 'body.wp-admin' );

Expand Down
4 changes: 2 additions & 2 deletions wp-parsely.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* Plugin Name: Parse.ly
* Plugin URI: https://www.parse.ly/help/integration/wordpress
* Description: This plugin makes it a snap to add Parse.ly tracking code and metadata to your WordPress blog.
* Version: 3.5.2
* Version: 3.5.3
* Author: Parse.ly
* Author URI: https://www.parse.ly
* Text Domain: wp-parsely
Expand Down Expand Up @@ -52,7 +52,7 @@
return;
}

const PARSELY_VERSION = '3.5.2';
const PARSELY_VERSION = '3.5.3';
const PARSELY_FILE = __FILE__;

require __DIR__ . '/src/class-parsely.php';
Expand Down

0 comments on commit ccad870

Please sign in to comment.