PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / _inc / lib / core-api / wpcom-endpoints / service-api-keys.php
jetpack / _inc / lib / core-api / wpcom-endpoints Last commit date
business-hours.php 7 months ago class-wpcom-rest-api-v2-endpoint-admin-bar.php 2 months ago class-wpcom-rest-api-v2-endpoint-admin-color.php 7 months ago class-wpcom-rest-api-v2-endpoint-admin-menu.php 1 month ago class-wpcom-rest-api-v2-endpoint-agent-guidelines-ai.php 1 week ago class-wpcom-rest-api-v2-endpoint-ai.php 1 week ago class-wpcom-rest-api-v2-endpoint-app-media.php 7 months ago class-wpcom-rest-api-v2-endpoint-application-password-extras.php 3 months ago class-wpcom-rest-api-v2-endpoint-block-editor-assets.php 1 week ago class-wpcom-rest-api-v2-endpoint-blog-stats.php 7 months ago class-wpcom-rest-api-v2-endpoint-email-preview.php 2 months ago class-wpcom-rest-api-v2-endpoint-external-media.php 7 months ago class-wpcom-rest-api-v2-endpoint-following.php 7 months ago class-wpcom-rest-api-v2-endpoint-goodreads.php 7 months ago class-wpcom-rest-api-v2-endpoint-google-docs.php 7 months ago class-wpcom-rest-api-v2-endpoint-guidelines-banner-dismissed.php 1 week ago class-wpcom-rest-api-v2-endpoint-instagram-gallery.php 2 months ago class-wpcom-rest-api-v2-endpoint-mailchimp.php 7 months ago class-wpcom-rest-api-v2-endpoint-mcp-settings.php 2 days ago class-wpcom-rest-api-v2-endpoint-newsletter-categories-list.php 7 months ago class-wpcom-rest-api-v2-endpoint-newsletter-categories-subscriptions-count.php 7 months ago class-wpcom-rest-api-v2-endpoint-newsletter-email-sent-status.php 3 months ago class-wpcom-rest-api-v2-endpoint-podcast-player.php 2 months ago class-wpcom-rest-api-v2-endpoint-profile.php 7 months ago class-wpcom-rest-api-v2-endpoint-related-posts.php 7 months ago class-wpcom-rest-api-v2-endpoint-resolve-redirect.php 7 months ago class-wpcom-rest-api-v2-endpoint-search.php 1 week ago class-wpcom-rest-api-v2-endpoint-send-email-preview.php 1 month ago class-wpcom-rest-api-v2-endpoint-subscribers-list.php 1 week ago class-wpcom-rest-api-v2-endpoint-template-loader.php 7 months ago class-wpcom-rest-api-v2-endpoint-top-posts.php 2 months ago class-wpcom-rest-api-v2-endpoint-transient.php 7 months ago class-wpcom-rest-api-v3-endpoint-blogging-prompts.php 7 months ago class-wpcom-rest-api-v3-endpoint-jitm.php 7 months ago gutenberg-available-extensions.php 7 months ago hello.php 7 months ago memberships.php 1 week ago publicize-connection-test-results.php 7 months ago service-api-keys.php 1 month ago sites-posts-featured-media-url.php 7 months ago subscribers.php 7 months ago
service-api-keys.php
340 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Get and save API keys for a site.
4 *
5 * @package automattic/jetpack
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit( 0 );
10 }
11
12 /**
13 * Service API Keys: Exposes 3rd party api keys that are used on a site.
14 *
15 * [
16 * { # Availability Object. See schema for more detail.
17 * code: (string) Displays success if the operation was successfully executed and an error code if it was not
18 * service: (string) The name of the service in question
19 * service_api_key: (string) The API key used by the service empty if one is not set yet
20 * service_api_key_source: (string) The source of the API key, defaults to "site"
21 * message: (string) User friendly message
22 * },
23 * ...
24 * ]
25 *
26 * @since 6.9
27 */
28 class WPCOM_REST_API_V2_Endpoint_Service_API_Keys extends WP_REST_Controller {
29
30 /**
31 * Constructor.
32 */
33 public function __construct() {
34 $this->namespace = 'wpcom/v2';
35 $this->rest_base = 'service-api-keys';
36
37 add_action( 'rest_api_init', array( $this, 'register_routes' ) );
38 }
39
40 /**
41 * Register endpoint routes.
42 */
43 public function register_routes() {
44 register_rest_route(
45 'wpcom/v2',
46 '/service-api-keys/(?P<service>[a-z\-_]+)',
47 array(
48 array(
49 'methods' => WP_REST_Server::READABLE,
50 'callback' => array( __CLASS__, 'get_service_api_key' ),
51 'permission_callback' => '__return_true',
52 ),
53 array(
54 'methods' => WP_REST_Server::EDITABLE,
55 'callback' => array( __CLASS__, 'update_service_api_key' ),
56 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
57 'args' => array(
58 'service_api_key' => array(
59 'required' => true,
60 'type' => 'string',
61 ),
62 ),
63 ),
64 array(
65 'methods' => WP_REST_Server::DELETABLE,
66 'callback' => array( __CLASS__, 'delete_service_api_key' ),
67 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
68 ),
69 )
70 );
71 }
72
73 /**
74 * Permission check.
75 */
76 public static function edit_others_posts_check() {
77 if ( current_user_can( 'edit_others_posts' ) ) {
78 return true;
79 }
80
81 $user_permissions_error_msg = esc_html__(
82 'You do not have the correct user permissions to perform this action.
83 Please contact your site admin if you think this is a mistake.',
84 'jetpack'
85 );
86
87 return new WP_Error( 'invalid_user_permission_edit_others_posts', $user_permissions_error_msg, rest_authorization_required_code() );
88 }
89
90 /**
91 * Return the available Gutenberg extensions schema
92 *
93 * @return array Service API Key schema
94 */
95 public function get_public_item_schema() {
96 $schema = array(
97 '$schema' => 'http://json-schema.org/draft-04/schema#',
98 'title' => 'service-api-keys',
99 'type' => 'object',
100 'properties' => array(
101 'code' => array(
102 'description' => __( 'Displays success if the operation was successfully executed and an error code if it was not', 'jetpack' ),
103 'type' => 'string',
104 ),
105 'service' => array(
106 'description' => __( 'The name of the service in question', 'jetpack' ),
107 'type' => 'string',
108 ),
109 'service_api_key' => array(
110 'description' => __( 'The API key used by the service. Empty if none has been set yet', 'jetpack' ),
111 'type' => 'string',
112 ),
113 'service_api_key_source' => array(
114 'description' => __( 'The source of the API key. Defaults to "site"', 'jetpack' ),
115 'type' => 'string',
116 ),
117 'message' => array(
118 'description' => __( 'User friendly message', 'jetpack' ),
119 'type' => 'string',
120 ),
121 ),
122 );
123
124 return $this->add_additional_fields_schema( $schema );
125 }
126
127 /**
128 * Get third party plugin API keys.
129 *
130 * @param WP_REST_Request $request {
131 * Array of parameters received by request.
132 *
133 * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
134 * }
135 */
136 public static function get_service_api_key( $request ) {
137 $service = self::validate_service_api_service( $request['service'] );
138 if ( ! $service ) {
139 return self::service_api_invalid_service_response();
140 }
141
142 switch ( $service ) {
143 case 'mapbox':
144 if ( ! class_exists( 'Jetpack_Mapbox_Helper' ) ) {
145 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-mapbox-helper.php';
146 }
147 $mapbox = Jetpack_Mapbox_Helper::get_access_token();
148 $service_api_key = $mapbox['key'];
149 $service_api_key_source = $mapbox['source'];
150 break;
151 default:
152 $option = self::key_for_api_service( $service );
153 $service_api_key = Jetpack_Options::get_option( $option, '' );
154 $service_api_key_source = 'site';
155 }
156
157 $message = esc_html__( 'API key retrieved successfully.', 'jetpack' );
158
159 return array(
160 'code' => 'success',
161 'service' => $service,
162 'service_api_key' => $service_api_key,
163 'service_api_key_source' => $service_api_key_source,
164 'message' => $message,
165 );
166 }
167
168 /**
169 * Update third party plugin API keys.
170 *
171 * @param WP_REST_Request $request {
172 * Array of parameters received by request.
173 *
174 * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
175 * }
176 */
177 public static function update_service_api_key( $request ) {
178 $service = self::validate_service_api_service( $request['service'] );
179 if ( ! $service ) {
180 return self::service_api_invalid_service_response();
181 }
182 $json_params = $request->get_json_params();
183 $params = ! empty( $json_params ) ? $json_params : $request->get_body_params();
184 $service_api_key = trim( $params['service_api_key'] );
185 $option = self::key_for_api_service( $service );
186
187 $validation = self::validate_service_api_key( $service_api_key, $service );
188 if ( ! $validation['status'] ) {
189 return new WP_Error( 'invalid_key', esc_html__( 'Invalid API Key', 'jetpack' ), array( 'status' => 404 ) );
190 }
191 $message = esc_html__( 'API key updated successfully.', 'jetpack' );
192 Jetpack_Options::update_option( $option, $service_api_key );
193 return array(
194 'code' => 'success',
195 'service' => $service,
196 'service_api_key' => Jetpack_Options::get_option( $option, '' ),
197 'service_api_key_source' => 'site',
198 'message' => $message,
199 );
200 }
201
202 /**
203 * Delete a third party plugin API key.
204 *
205 * @param WP_REST_Request $request {
206 * Array of parameters received by request.
207 *
208 * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
209 * }
210 */
211 public static function delete_service_api_key( $request ) {
212 $service = self::validate_service_api_service( $request['service'] );
213 if ( ! $service ) {
214 return self::service_api_invalid_service_response();
215 }
216 $option = self::key_for_api_service( $service );
217 Jetpack_Options::delete_option( $option );
218 $message = esc_html__( 'API key deleted successfully.', 'jetpack' );
219
220 switch ( $service ) {
221 case 'mapbox':
222 // After deleting a custom Mapbox key, try to revert to the WordPress.com one if available.
223 if ( ! class_exists( 'Jetpack_Mapbox_Helper' ) ) {
224 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-mapbox-helper.php';
225 }
226 $mapbox = Jetpack_Mapbox_Helper::get_access_token();
227 $service_api_key = $mapbox['key'];
228 $service_api_key_source = $mapbox['source'];
229 break;
230 default:
231 $service_api_key = Jetpack_Options::get_option( $option, '' );
232 $service_api_key_source = 'site';
233 }
234
235 return array(
236 'code' => 'success',
237 'service' => $service,
238 'service_api_key' => $service_api_key,
239 'service_api_key_source' => $service_api_key_source,
240 'message' => $message,
241 );
242 }
243
244 /**
245 * Validate the service provided in /service-api-keys/ endpoints.
246 * To add a service to these endpoints, add the service name to $valid_services
247 * and add '{service name}_api_key' to the non-compact return array in get_option_names(),
248 * in class-jetpack-options.php
249 *
250 * @param string $service The service the API key is for.
251 * @return string Returns the service name if valid, null if invalid.
252 */
253 public static function validate_service_api_service( $service = null ) {
254 $valid_services = array(
255 'mapbox',
256 );
257 return in_array( $service, $valid_services, true ) ? $service : null;
258 }
259
260 /**
261 * Error response for invalid service API key requests with an invalid service.
262 */
263 public static function service_api_invalid_service_response() {
264 return new WP_Error(
265 'invalid_service',
266 esc_html__( 'Invalid Service', 'jetpack' ),
267 array( 'status' => 404 )
268 );
269 }
270
271 /**
272 * Validate API Key
273 *
274 * @param string $key The API key to be validated.
275 * @param string $service The service the API key is for.
276 */
277 public static function validate_service_api_key( $key = null, $service = null ) {
278 $validation = false;
279 switch ( $service ) {
280 case 'mapbox':
281 $validation = self::validate_service_api_key_mapbox( $key );
282 break;
283 }
284 return $validation;
285 }
286
287 /**
288 * Validate Mapbox API key
289 * Based loosely on https://github.com/mapbox/geocoding-example/blob/master/php/MapboxTest.php
290 *
291 * @param string $key The API key to be validated.
292 */
293 public static function validate_service_api_key_mapbox( $key ) {
294 $status = true;
295 $msg = null;
296 $mapbox_url = sprintf(
297 'https://api.mapbox.com?%s',
298 $key
299 );
300 $mapbox_response = wp_safe_remote_get( esc_url_raw( $mapbox_url ) );
301 $mapbox_body = wp_remote_retrieve_body( $mapbox_response );
302 if ( '{"api":"mapbox"}' !== $mapbox_body ) {
303 $status = false;
304 $msg = esc_html__( 'Can\'t connect to Mapbox', 'jetpack' );
305 return array(
306 'status' => $status,
307 'error_message' => $msg,
308 );
309 }
310 $mapbox_geocode_url = esc_url_raw(
311 sprintf(
312 'https://api.mapbox.com/geocoding/v5/mapbox.places/%s.json?access_token=%s',
313 '1+broadway+new+york+ny+usa',
314 $key
315 )
316 );
317 $mapbox_geocode_response = wp_safe_remote_get( esc_url_raw( $mapbox_geocode_url ) );
318 $mapbox_geocode_body = wp_remote_retrieve_body( $mapbox_geocode_response );
319 $mapbox_geocode_json = json_decode( $mapbox_geocode_body );
320 if ( isset( $mapbox_geocode_json->message ) || ! isset( $mapbox_geocode_json->query ) ) {
321 $status = false;
322 $msg = $mapbox_geocode_json->message ?? 'Unknown error';
323 }
324 return array(
325 'status' => $status,
326 'error_message' => $msg,
327 );
328 }
329
330 /**
331 * Create site option key for service
332 *
333 * @param string $service The service to create key for.
334 */
335 private static function key_for_api_service( $service ) {
336 return $service . '_api_key';
337 }
338 }
339 wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Service_API_Keys' );
340