Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/cloudinary.js

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions php/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ public function __construct( Plugin $plugin ) {
public function rest_endpoints( $endpoints ) {

$endpoints['dismiss_notice'] = array(
'method' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'rest_dismiss_notice' ),
'args' => array(),
'method' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'rest_dismiss_notice' ),
'args' => array(),
'permission_callback' => function () {
return Utils::user_can( 'manage_settings' );
},
);

$endpoints['save_settings'] = array(
Expand Down
8 changes: 5 additions & 3 deletions php/class-cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,11 @@ public function rest_endpoints( $endpoints ) {
'args' => array(),
);
$endpoints['upload_cache'] = array(
'method' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'rest_upload_cache' ),
'args' => array(),
'method' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'rest_upload_cache' ),
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
'args' => array(),

);

return $endpoints;
Expand Down
7 changes: 4 additions & 3 deletions php/class-connect.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ public function rest_endpoints( $endpoints ) {
'permission_callback' => array( 'Cloudinary\REST_API', 'rest_can_connect' ),
);
$endpoints['test_rest_api'] = array(
'method' => WP_REST_Server::READABLE,
'callback' => array( $this, 'rest_test_rest_api_connectivity' ),
'args' => array(),
'method' => WP_REST_Server::READABLE,
'callback' => array( $this, 'rest_test_rest_api_connectivity' ),
'args' => array(),
'permission_callback' => array( 'Cloudinary\REST_API', 'allow_public_health_check' ),
);

return $endpoints;
Expand Down
4 changes: 2 additions & 2 deletions php/class-cron.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ public function rest_endpoints( $endpoints ) {
$endpoints['cron_watch'] = array(
'method' => \WP_REST_Server::READABLE,
'callback' => array( $this, 'daemon_watcher' ),
'permission_callback' => '__return_true',
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
);
$endpoints['cron_process'] = array(
'method' => \WP_REST_Server::READABLE,
'callback' => array( $this, 'run_queue' ),
'permission_callback' => '__return_true',
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
);

return $endpoints;
Expand Down
40 changes: 38 additions & 2 deletions php/class-rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*/
class REST_API {

/**
* Base path for the REST API endpoints.
*
* @var string
*/
const BASE = 'cloudinary/v1';

/**
Expand All @@ -21,6 +26,13 @@ class REST_API {
*/
public $endpoints;

/**
* The nonce key used for WordPress REST API authentication.
*
* @var string
*/
const NONCE_KEY = 'wp_rest';

/**
* REST_API constructor.
*
Expand All @@ -39,13 +51,14 @@ public function rest_api_init() {
'method' => \WP_REST_Server::READABLE,
'callback' => __return_empty_array(),
'args' => array(),
'permission_callback' => '__return_true',
'permission_callback' => array( __CLASS__, 'validate_request' ),
);

$this->endpoints = apply_filters( 'cloudinary_api_rest_endpoints', array() );

foreach ( $this->endpoints as $route => $endpoint ) {
$endpoint = wp_parse_args( $endpoint, $defaults );

register_rest_route(
static::BASE,
$route,
Expand Down Expand Up @@ -81,7 +94,7 @@ public function background_request( $endpoint, $params = array(), $method = 'POS

$url = Utils::rest_url( static::BASE . '/' . $endpoint );
// Setup a call for a background sync.
$params['nonce'] = wp_create_nonce( 'wp_rest' );
$params['nonce'] = wp_create_nonce( static::NONCE_KEY );
$args = array(
'timeout' => 0.1,
'blocking' => false,
Expand Down Expand Up @@ -115,4 +128,27 @@ public function background_request( $endpoint, $params = array(), $method = 'POS
// Send request.
wp_remote_request( $url, $args );
}

/**
* Validation for request.
*
* @param \WP_REST_Request $request The original request.
*
* @return bool
*/
public static function validate_request( $request ) {
return wp_verify_nonce( $request->get_header( 'x_wp_nonce' ), self::NONCE_KEY );
}

/**
* Permission callback for public health check endpoints.
*
* Intentionally allows unauthenticated access for REST API connectivity testing.
* This endpoint is read-only and returns no sensitive data.
*
* @return bool Always returns true to allow public access.
*/
public static function allow_public_health_check() {
return true;
}
}
14 changes: 8 additions & 6 deletions php/sync/class-push-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,16 @@ public function rest_endpoints( $endpoints ) {
);

$endpoints['queue'] = array(
'method' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'process_queue' ),
'args' => array(),
'method' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'process_queue' ),
'args' => array(),
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
);
$endpoints['stats'] = array(
'method' => \WP_REST_Server::READABLE,
'callback' => array( $this->queue, 'get_total_synced_media' ),
'args' => array(),
'method' => \WP_REST_Server::READABLE,
'callback' => array( $this->queue, 'get_total_synced_media' ),
'args' => array(),
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
);

return $endpoints;
Expand Down
13 changes: 2 additions & 11 deletions php/ui/class-state.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,13 @@ public function rest_endpoints( $endpoints ) {
'method' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'set_state' ),
'args' => array(),
'permission_callback' => array( $this, 'validate_request' ),
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
);

return $endpoints;
}

/**
* Validation for request.
*
* @param \WP_REST_Request $request The original request.
*
* @return bool
*/
public function validate_request( $request ) {
return wp_verify_nonce( $request->get_header( 'x_wp_nonce' ), 'wp_rest' );
}


/**
* Set the UI state.
Expand Down
2 changes: 1 addition & 1 deletion php/ui/component/class-notice.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public function render( $echo = false ) { // phpcs:ignore Universal.NamingConven
if ( $this->setting->get_option_parent()->has_param( 'dismissible_notice' ) && ! $this->setting->get_option_parent()->has_param( 'notice_scripts' ) ) {
$args = array(
'url' => Utils::rest_url( REST_API::BASE . '/dismiss_notice' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'nonce' => wp_create_nonce( REST_API::NONCE_KEY ),
);
wp_add_inline_script( 'cloudinary', 'var CLDIS = ' . wp_json_encode( $args ), 'before' );
$this->setting->get_option_parent()->set_param( 'notice_scripts', true ); // Prevent repeated rendering.
Expand Down
5 changes: 3 additions & 2 deletions php/ui/component/class-progress-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ class Progress_Sync extends Progress_Ring {
protected function wrap( $struct ) {
$struct = parent::wrap( $struct );
if ( true === $this->setting->get_param( 'poll' ) ) {
$struct['attributes']['data-url'] = Utils::rest_url( REST_API::BASE . '/stats' );
$struct['attributes']['data-poll'] = true;
$struct['attributes']['data-url'] = Utils::rest_url( REST_API::BASE . '/stats' );
$struct['attributes']['data-poll'] = true;
$struct['attributes']['data-nonce'] = wp_create_nonce( REST_API::NONCE_KEY );
}

return $struct;
Expand Down
8 changes: 8 additions & 0 deletions src/js/components/progress.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';

const Progress = {
data: {},
nonce: '',
context: null,
init( context ) {
this.context = context;
Expand All @@ -26,6 +27,10 @@ const Progress = {
} else if ( 'circle' === item.dataset.progress ) {
this.circle( item );
}

if ( ! this.nonce ) {
this.nonce = item.dataset?.nonce;
}
} );

for ( const url in this.data ) {
Expand Down Expand Up @@ -143,6 +148,9 @@ const Progress = {
apiFetch( {
path: url,
method: 'GET',
headers: {
'X-WP-Nonce': this.nonce,
},
} ).then( ( result ) => {
this.data[ url ].items.forEach( ( item ) => {
if ( typeof result[ item.dataset.basetext ] !== 'undefined' ) {
Expand Down