PageRenderTime 59ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/service-api-keys.php

https://gitlab.com/chernushov881/charity-fund
PHP | 321 lines | 220 code | 23 blank | 78 comment | 13 complexity | ac0ac5eaeabc83d10e55618b59d2b35f MD5 | raw file
  1. <?php
  2. /**
  3. * Service API Keys: Exposes 3rd party api keys that are used on a site.
  4. *
  5. * [
  6. * { # Availabilty Object. See schema for more detail.
  7. * code: (string) Displays success if the operation was successfully executed and an error code if it was not
  8. * service: (string) The name of the service in question
  9. * service_api_key: (string) The API key used by the service empty if one is not set yet
  10. * service_api_key_source: (string) The source of the API key, defaults to "site"
  11. * message: (string) User friendly message
  12. * },
  13. * ...
  14. * ]
  15. *
  16. * @since 6.9
  17. */
  18. class WPCOM_REST_API_V2_Endpoint_Service_API_Keys extends WP_REST_Controller {
  19. function __construct() {
  20. $this->namespace = 'wpcom/v2';
  21. $this->rest_base = 'service-api-keys';
  22. add_action( 'rest_api_init', array( $this, 'register_routes' ) );
  23. }
  24. public function register_routes() {
  25. register_rest_route(
  26. 'wpcom/v2',
  27. '/service-api-keys/(?P<service>[a-z\-_]+)',
  28. array(
  29. array(
  30. 'methods' => WP_REST_Server::READABLE,
  31. 'callback' => array( __CLASS__, 'get_service_api_key' ),
  32. 'permission_callback' => '__return_true',
  33. ),
  34. array(
  35. 'methods' => WP_REST_Server::EDITABLE,
  36. 'callback' => array( __CLASS__, 'update_service_api_key' ),
  37. 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
  38. 'args' => array(
  39. 'service_api_key' => array(
  40. 'required' => true,
  41. 'type' => 'string',
  42. ),
  43. ),
  44. ),
  45. array(
  46. 'methods' => WP_REST_Server::DELETABLE,
  47. 'callback' => array( __CLASS__, 'delete_service_api_key' ),
  48. 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
  49. ),
  50. )
  51. );
  52. }
  53. public static function edit_others_posts_check() {
  54. if ( current_user_can( 'edit_others_posts' ) ) {
  55. return true;
  56. }
  57. $user_permissions_error_msg = esc_html__(
  58. 'You do not have the correct user permissions to perform this action.
  59. Please contact your site admin if you think this is a mistake.',
  60. 'jetpack'
  61. );
  62. return new WP_Error( 'invalid_user_permission_edit_others_posts', $user_permissions_error_msg, rest_authorization_required_code() );
  63. }
  64. /**
  65. * Return the available Gutenberg extensions schema
  66. *
  67. * @return array Service API Key schema
  68. */
  69. public function get_public_item_schema() {
  70. $schema = array(
  71. '$schema' => 'http://json-schema.org/draft-04/schema#',
  72. 'title' => 'service-api-keys',
  73. 'type' => 'object',
  74. 'properties' => array(
  75. 'code' => array(
  76. 'description' => __( 'Displays success if the operation was successfully executed and an error code if it was not', 'jetpack' ),
  77. 'type' => 'string',
  78. ),
  79. 'service' => array(
  80. 'description' => __( 'The name of the service in question', 'jetpack' ),
  81. 'type' => 'string',
  82. ),
  83. 'service_api_key' => array(
  84. 'description' => __( 'The API key used by the service. Empty if none has been set yet', 'jetpack' ),
  85. 'type' => 'string',
  86. ),
  87. 'service_api_key_source' => array(
  88. 'description' => __( 'The source of the API key. Defaults to "site"', 'jetpack' ),
  89. 'type' => 'string',
  90. ),
  91. 'message' => array(
  92. 'description' => __( 'User friendly message', 'jetpack' ),
  93. 'type' => 'string',
  94. ),
  95. ),
  96. );
  97. return $this->add_additional_fields_schema( $schema );
  98. }
  99. /**
  100. * Get third party plugin API keys.
  101. *
  102. * @param WP_REST_Request $request {
  103. * Array of parameters received by request.
  104. *
  105. * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
  106. * }
  107. */
  108. public static function get_service_api_key( $request ) {
  109. $service = self::validate_service_api_service( $request['service'] );
  110. if ( ! $service ) {
  111. return self::service_api_invalid_service_response();
  112. }
  113. switch ( $service ) {
  114. case 'mapbox':
  115. if ( ! class_exists( 'Jetpack_Mapbox_Helper' ) ) {
  116. jetpack_require_lib( 'class-jetpack-mapbox-helper' );
  117. }
  118. $mapbox = Jetpack_Mapbox_Helper::get_access_token();
  119. $service_api_key = $mapbox['key'];
  120. $service_api_key_source = $mapbox['source'];
  121. break;
  122. default:
  123. $option = self::key_for_api_service( $service );
  124. $service_api_key = Jetpack_Options::get_option( $option, '' );
  125. $service_api_key_source = 'site';
  126. };
  127. $message = esc_html__( 'API key retrieved successfully.', 'jetpack' );
  128. return array(
  129. 'code' => 'success',
  130. 'service' => $service,
  131. 'service_api_key' => $service_api_key,
  132. 'service_api_key_source' => $service_api_key_source,
  133. 'message' => $message,
  134. );
  135. }
  136. /**
  137. * Update third party plugin API keys.
  138. *
  139. * @param WP_REST_Request $request {
  140. * Array of parameters received by request.
  141. *
  142. * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
  143. * }
  144. */
  145. public static function update_service_api_key( $request ) {
  146. $service = self::validate_service_api_service( $request['service'] );
  147. if ( ! $service ) {
  148. return self::service_api_invalid_service_response();
  149. }
  150. $json_params = $request->get_json_params();
  151. $params = ! empty( $json_params ) ? $json_params : $request->get_body_params();
  152. $service_api_key = trim( $params['service_api_key'] );
  153. $option = self::key_for_api_service( $service );
  154. $validation = self::validate_service_api_key( $service_api_key, $service, $params );
  155. if ( ! $validation['status'] ) {
  156. return new WP_Error( 'invalid_key', esc_html__( 'Invalid API Key', 'jetpack' ), array( 'status' => 404 ) );
  157. }
  158. $message = esc_html__( 'API key updated successfully.', 'jetpack' );
  159. Jetpack_Options::update_option( $option, $service_api_key );
  160. return array(
  161. 'code' => 'success',
  162. 'service' => $service,
  163. 'service_api_key' => Jetpack_Options::get_option( $option, '' ),
  164. 'service_api_key_source' => 'site',
  165. 'message' => $message,
  166. );
  167. }
  168. /**
  169. * Delete a third party plugin API key.
  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 delete_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. $option = self::key_for_api_service( $service );
  183. Jetpack_Options::delete_option( $option );
  184. $message = esc_html__( 'API key deleted successfully.', 'jetpack' );
  185. switch ( $service ) {
  186. case 'mapbox':
  187. // After deleting a custom Mapbox key, try to revert to the WordPress.com one if available.
  188. if ( ! class_exists( 'Jetpack_Mapbox_Helper' ) ) {
  189. jetpack_require_lib( 'class-jetpack-mapbox-helper' );
  190. }
  191. $mapbox = Jetpack_Mapbox_Helper::get_access_token();
  192. $service_api_key = $mapbox['key'];
  193. $service_api_key_source = $mapbox['source'];
  194. break;
  195. default:
  196. $service_api_key = Jetpack_Options::get_option( $option, '' );
  197. $service_api_key_source = 'site';
  198. };
  199. return array(
  200. 'code' => 'success',
  201. 'service' => $service,
  202. 'service_api_key' => $service_api_key,
  203. 'service_api_key_source' => $service_api_key_source,
  204. 'message' => $message,
  205. );
  206. }
  207. /**
  208. * Validate the service provided in /service-api-keys/ endpoints.
  209. * To add a service to these endpoints, add the service name to $valid_services
  210. * and add '{service name}_api_key' to the non-compact return array in get_option_names(),
  211. * in class-jetpack-options.php
  212. *
  213. * @param string $service The service the API key is for.
  214. * @return string Returns the service name if valid, null if invalid.
  215. */
  216. public static function validate_service_api_service( $service = null ) {
  217. $valid_services = array(
  218. 'mapbox',
  219. );
  220. return in_array( $service, $valid_services, true ) ? $service : null;
  221. }
  222. /**
  223. * Error response for invalid service API key requests with an invalid service.
  224. */
  225. public static function service_api_invalid_service_response() {
  226. return new WP_Error(
  227. 'invalid_service',
  228. esc_html__( 'Invalid Service', 'jetpack' ),
  229. array( 'status' => 404 )
  230. );
  231. }
  232. /**
  233. * Validate API Key
  234. *
  235. * @param string $key The API key to be validated.
  236. * @param string $service The service the API key is for.
  237. */
  238. public static function validate_service_api_key( $key = null, $service = null ) {
  239. $validation = false;
  240. switch ( $service ) {
  241. case 'mapbox':
  242. $validation = self::validate_service_api_key_mapbox( $key );
  243. break;
  244. }
  245. return $validation;
  246. }
  247. /**
  248. * Validate Mapbox API key
  249. * Based loosely on https://github.com/mapbox/geocoding-example/blob/master/php/MapboxTest.php
  250. *
  251. * @param string $key The API key to be validated.
  252. */
  253. public static function validate_service_api_key_mapbox( $key ) {
  254. $status = true;
  255. $msg = null;
  256. $mapbox_url = sprintf(
  257. 'https://api.mapbox.com?%s',
  258. $key
  259. );
  260. $mapbox_response = wp_safe_remote_get( esc_url_raw( $mapbox_url ) );
  261. $mapbox_body = wp_remote_retrieve_body( $mapbox_response );
  262. if ( '{"api":"mapbox"}' !== $mapbox_body ) {
  263. $status = false;
  264. $msg = esc_html__( 'Can\'t connect to Mapbox', 'jetpack' );
  265. return array(
  266. 'status' => $status,
  267. 'error_message' => $msg,
  268. );
  269. }
  270. $mapbox_geocode_url = esc_url_raw(
  271. sprintf(
  272. 'https://api.mapbox.com/geocoding/v5/mapbox.places/%s.json?access_token=%s',
  273. '1+broadway+new+york+ny+usa',
  274. $key
  275. )
  276. );
  277. $mapbox_geocode_response = wp_safe_remote_get( esc_url_raw( $mapbox_geocode_url ) );
  278. $mapbox_geocode_body = wp_remote_retrieve_body( $mapbox_geocode_response );
  279. $mapbox_geocode_json = json_decode( $mapbox_geocode_body );
  280. if ( isset( $mapbox_geocode_json->message ) && ! isset( $mapbox_geocode_json->query ) ) {
  281. $status = false;
  282. $msg = $mapbox_geocode_json->message;
  283. }
  284. return array(
  285. 'status' => $status,
  286. 'error_message' => $msg,
  287. );
  288. }
  289. /**
  290. * Create site option key for service
  291. *
  292. * @param string $service The service to create key for.
  293. */
  294. private static function key_for_api_service( $service ) {
  295. return $service . '_api_key';
  296. }
  297. }
  298. wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Service_API_Keys' );