Skip to content

Commit ed23449

Browse files
Merge pull request #1135 from cloudinary/improve-rest-api-endpoints
Improve permission_callback of Cloudinary Rest API endpoints
2 parents 3e2624e + 922c379 commit ed23449

11 files changed

Lines changed: 78 additions & 34 deletions

js/cloudinary.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

php/class-admin.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ public function __construct( Plugin $plugin ) {
108108
public function rest_endpoints( $endpoints ) {
109109

110110
$endpoints['dismiss_notice'] = array(
111-
'method' => WP_REST_Server::CREATABLE,
112-
'callback' => array( $this, 'rest_dismiss_notice' ),
113-
'args' => array(),
111+
'method' => WP_REST_Server::CREATABLE,
112+
'callback' => array( $this, 'rest_dismiss_notice' ),
113+
'args' => array(),
114+
'permission_callback' => function () {
115+
return Utils::user_can( 'manage_settings' );
116+
},
114117
);
115118

116119
$endpoints['save_settings'] = array(

php/class-cache.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,11 @@ public function rest_endpoints( $endpoints ) {
352352
'args' => array(),
353353
);
354354
$endpoints['upload_cache'] = array(
355-
'method' => \WP_REST_Server::CREATABLE,
356-
'callback' => array( $this, 'rest_upload_cache' ),
357-
'args' => array(),
355+
'method' => \WP_REST_Server::CREATABLE,
356+
'callback' => array( $this, 'rest_upload_cache' ),
357+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
358+
'args' => array(),
359+
358360
);
359361

360362
return $endpoints;

php/class-connect.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ public function rest_endpoints( $endpoints ) {
132132
'permission_callback' => array( 'Cloudinary\REST_API', 'rest_can_connect' ),
133133
);
134134
$endpoints['test_rest_api'] = array(
135-
'method' => WP_REST_Server::READABLE,
136-
'callback' => array( $this, 'rest_test_rest_api_connectivity' ),
137-
'args' => array(),
135+
'method' => WP_REST_Server::READABLE,
136+
'callback' => array( $this, 'rest_test_rest_api_connectivity' ),
137+
'args' => array(),
138+
'permission_callback' => array( 'Cloudinary\REST_API', 'allow_public_health_check' ),
138139
);
139140

140141
return $endpoints;

php/class-cron.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,12 @@ public function rest_endpoints( $endpoints ) {
187187
$endpoints['cron_watch'] = array(
188188
'method' => \WP_REST_Server::READABLE,
189189
'callback' => array( $this, 'daemon_watcher' ),
190-
'permission_callback' => '__return_true',
190+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
191191
);
192192
$endpoints['cron_process'] = array(
193193
'method' => \WP_REST_Server::READABLE,
194194
'callback' => array( $this, 'run_queue' ),
195-
'permission_callback' => '__return_true',
195+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
196196
);
197197

198198
return $endpoints;

php/class-rest-api.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
*/
1313
class REST_API {
1414

15+
/**
16+
* Base path for the REST API endpoints.
17+
*
18+
* @var string
19+
*/
1520
const BASE = 'cloudinary/v1';
1621

1722
/**
@@ -21,6 +26,13 @@ class REST_API {
2126
*/
2227
public $endpoints;
2328

29+
/**
30+
* The nonce key used for WordPress REST API authentication.
31+
*
32+
* @var string
33+
*/
34+
const NONCE_KEY = 'wp_rest';
35+
2436
/**
2537
* REST_API constructor.
2638
*
@@ -39,13 +51,14 @@ public function rest_api_init() {
3951
'method' => \WP_REST_Server::READABLE,
4052
'callback' => __return_empty_array(),
4153
'args' => array(),
42-
'permission_callback' => '__return_true',
54+
'permission_callback' => array( __CLASS__, 'validate_request' ),
4355
);
4456

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

4759
foreach ( $this->endpoints as $route => $endpoint ) {
4860
$endpoint = wp_parse_args( $endpoint, $defaults );
61+
4962
register_rest_route(
5063
static::BASE,
5164
$route,
@@ -81,7 +94,7 @@ public function background_request( $endpoint, $params = array(), $method = 'POS
8194

8295
$url = Utils::rest_url( static::BASE . '/' . $endpoint );
8396
// Setup a call for a background sync.
84-
$params['nonce'] = wp_create_nonce( 'wp_rest' );
97+
$params['nonce'] = wp_create_nonce( static::NONCE_KEY );
8598
$args = array(
8699
'timeout' => 0.1,
87100
'blocking' => false,
@@ -115,4 +128,27 @@ public function background_request( $endpoint, $params = array(), $method = 'POS
115128
// Send request.
116129
wp_remote_request( $url, $args );
117130
}
131+
132+
/**
133+
* Validation for request.
134+
*
135+
* @param \WP_REST_Request $request The original request.
136+
*
137+
* @return bool
138+
*/
139+
public static function validate_request( $request ) {
140+
return wp_verify_nonce( $request->get_header( 'x_wp_nonce' ), self::NONCE_KEY );
141+
}
142+
143+
/**
144+
* Permission callback for public health check endpoints.
145+
*
146+
* Intentionally allows unauthenticated access for REST API connectivity testing.
147+
* This endpoint is read-only and returns no sensitive data.
148+
*
149+
* @return bool Always returns true to allow public access.
150+
*/
151+
public static function allow_public_health_check() {
152+
return true;
153+
}
118154
}

php/sync/class-push-sync.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,16 @@ public function rest_endpoints( $endpoints ) {
124124
);
125125

126126
$endpoints['queue'] = array(
127-
'method' => \WP_REST_Server::CREATABLE,
128-
'callback' => array( $this, 'process_queue' ),
129-
'args' => array(),
127+
'method' => \WP_REST_Server::CREATABLE,
128+
'callback' => array( $this, 'process_queue' ),
129+
'args' => array(),
130+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
130131
);
131132
$endpoints['stats'] = array(
132-
'method' => \WP_REST_Server::READABLE,
133-
'callback' => array( $this->queue, 'get_total_synced_media' ),
134-
'args' => array(),
133+
'method' => \WP_REST_Server::READABLE,
134+
'callback' => array( $this->queue, 'get_total_synced_media' ),
135+
'args' => array(),
136+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
135137
);
136138

137139
return $endpoints;

php/ui/class-state.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,22 +98,13 @@ public function rest_endpoints( $endpoints ) {
9898
'method' => \WP_REST_Server::CREATABLE,
9999
'callback' => array( $this, 'set_state' ),
100100
'args' => array(),
101-
'permission_callback' => array( $this, 'validate_request' ),
101+
'permission_callback' => array( 'Cloudinary\REST_API', 'validate_request' ),
102102
);
103103

104104
return $endpoints;
105105
}
106106

107-
/**
108-
* Validation for request.
109-
*
110-
* @param \WP_REST_Request $request The original request.
111-
*
112-
* @return bool
113-
*/
114-
public function validate_request( $request ) {
115-
return wp_verify_nonce( $request->get_header( 'x_wp_nonce' ), 'wp_rest' );
116-
}
107+
117108

118109
/**
119110
* Set the UI state.

php/ui/component/class-notice.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public function render( $echo = false ) { // phpcs:ignore Universal.NamingConven
117117
if ( $this->setting->get_option_parent()->has_param( 'dismissible_notice' ) && ! $this->setting->get_option_parent()->has_param( 'notice_scripts' ) ) {
118118
$args = array(
119119
'url' => Utils::rest_url( REST_API::BASE . '/dismiss_notice' ),
120-
'nonce' => wp_create_nonce( 'wp_rest' ),
120+
'nonce' => wp_create_nonce( REST_API::NONCE_KEY ),
121121
);
122122
wp_add_inline_script( 'cloudinary', 'var CLDIS = ' . wp_json_encode( $args ), 'before' );
123123
$this->setting->get_option_parent()->set_param( 'notice_scripts', true ); // Prevent repeated rendering.

php/ui/component/class-progress-sync.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ class Progress_Sync extends Progress_Ring {
3434
protected function wrap( $struct ) {
3535
$struct = parent::wrap( $struct );
3636
if ( true === $this->setting->get_param( 'poll' ) ) {
37-
$struct['attributes']['data-url'] = Utils::rest_url( REST_API::BASE . '/stats' );
38-
$struct['attributes']['data-poll'] = true;
37+
$struct['attributes']['data-url'] = Utils::rest_url( REST_API::BASE . '/stats' );
38+
$struct['attributes']['data-poll'] = true;
39+
$struct['attributes']['data-nonce'] = wp_create_nonce( REST_API::NONCE_KEY );
3940
}
4041

4142
return $struct;

0 commit comments

Comments
 (0)