summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2016-09-11 07:55:30 -0400
committerAnthony G. Basile <blueness@gentoo.org>2016-09-11 07:55:30 -0400
commit665c15ca32b65c69491c564860f89d932ef774ec (patch)
treec65975754c261f1e99cd987e1095b2b27e702d87 /plugins/jetpack/_inc/lib/core-api
parentUpdate theme mantra to 2.6.0 (diff)
downloadblogs-gentoo-665c15ca32b65c69491c564860f89d932ef774ec.tar.gz
blogs-gentoo-665c15ca32b65c69491c564860f89d932ef774ec.tar.bz2
blogs-gentoo-665c15ca32b65c69491c564860f89d932ef774ec.zip
Update plugin jetpack to 4.3.1
Diffstat (limited to 'plugins/jetpack/_inc/lib/core-api')
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php986
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php33
2 files changed, 1019 insertions, 0 deletions
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
new file mode 100644
index 00000000..5843cdea
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
@@ -0,0 +1,986 @@
+<?php
+/**
+ * This is the base class for every Core API endpoint Jetpack uses.
+ *
+ */
+class Jetpack_Core_API_Module_Toggle_Endpoint
+ extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
+
+ /**
+ * List of modules that require WPCOM public access.
+ *
+ * @since 4.3.0
+ *
+ * @var array
+ */
+ private $modules_requiring_public = array(
+ 'photon',
+ 'enhanced-distribution',
+ 'json-api',
+ );
+
+ /**
+ * Check if the module requires the site to be publicly accessible from WPCOM.
+ * If the site meets this requirement, the module is activated. Otherwise an error is returned.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * @type bool $active should module be activated.
+ * }
+ *
+ * @return WP_REST_Response|WP_Error A REST response if the request was served successfully, otherwise an error.
+ */
+ public function process( $data ) {
+ if ( $data['active'] ) {
+ return $this->activate_module( $data );
+ } else {
+ return $this->deactivate_module( $data );
+ }
+ }
+
+ /**
+ * If it's a valid Jetpack module, activate it.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * }
+ *
+ * @return bool|WP_Error True if module was activated. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function activate_module( $data ) {
+ if ( ! Jetpack::is_module( $data['slug'] ) ) {
+ return new WP_Error(
+ 'not_found',
+ esc_html__( 'The requested Jetpack module was not found.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ if (
+ in_array( $data['slug'], $this->modules_requiring_public )
+ && ! $this->is_site_public()
+ ) {
+ return new WP_Error(
+ 'rest_cannot_publish',
+ __( 'This module requires your site to be set to publicly accessible.', 'jetpack' ),
+ array( 'status' => 424 )
+ );
+ }
+
+ if ( Jetpack::activate_module( $data['slug'], false, false ) ) {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'The requested Jetpack module was activated.', 'jetpack' ),
+ ) );
+ }
+
+ return new WP_Error(
+ 'activation_failed',
+ esc_html__( 'The requested Jetpack module could not be activated.', 'jetpack' ),
+ array( 'status' => 424 )
+ );
+ }
+
+ /**
+ * If it's a valid Jetpack module, deactivate it.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * }
+ *
+ * @return bool|WP_Error True if module was activated. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function deactivate_module( $data ) {
+ if ( ! Jetpack::is_module( $data['slug'] ) ) {
+ return new WP_Error(
+ 'not_found',
+ esc_html__( 'The requested Jetpack module was not found.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ if ( ! Jetpack::is_module_active( $data['slug'] ) ) {
+ return new WP_Error(
+ 'already_inactive',
+ esc_html__( 'The requested Jetpack module was already inactive.', 'jetpack' ),
+ array( 'status' => 409 )
+ );
+ }
+
+ if ( Jetpack::deactivate_module( $data['slug'] ) ) {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'The requested Jetpack module was deactivated.', 'jetpack' ),
+ ) );
+ }
+ return new WP_Error(
+ 'deactivation_failed',
+ esc_html__( 'The requested Jetpack module could not be deactivated.', 'jetpack' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ /**
+ * Check that the current user has permissions to manage Jetpack modules.
+ *
+ * @since 4.3.0
+ *
+ * @return bool
+ */
+ public function can_request() {
+ return current_user_can( 'jetpack_manage_modules' );
+ }
+}
+
+class Jetpack_Core_API_Module_List_Endpoint {
+
+ public function process( $request ) {
+ if ( 'GET' === $request->get_method() ) {
+ return $this->get_modules( $request );
+ } else {
+ return $this->activate_modules( $request );
+ }
+ }
+
+ /**
+ * Get a list of all Jetpack modules and their information.
+ *
+ * @since 4.3.0
+ *
+ * @return array Array of Jetpack modules.
+ */
+ public function get_modules() {
+ require_once( JETPACK__PLUGIN_DIR . 'class.jetpack-admin.php' );
+
+ $modules = Jetpack_Admin::init()->get_modules();
+ foreach ( $modules as $slug => $properties ) {
+ $modules[ $slug ]['options'] =
+ Jetpack_Core_Json_Api_Endpoints::prepare_options_for_response( $slug );
+ if (
+ isset( $modules[ $slug ]['requires_connection'] )
+ && $modules[ $slug ]['requires_connection']
+ && Jetpack::is_development_mode()
+ ) {
+ $modules[ $slug ]['activated'] = false;
+ }
+ }
+
+ $modules = Jetpack::get_translated_modules( $modules );
+
+ return Jetpack_Core_Json_Api_Endpoints::prepare_modules_for_response( $modules );
+ }
+
+ /**
+ * Activate a list of valid Jetpack modules.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * }
+ *
+ * @return bool|WP_Error True if modules were activated. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public static function activate_modules( $data ) {
+ $params = $data->get_json_params();
+
+ if (
+ ! isset( $params['modules'] )
+ || is_array( $params['modules'] )
+ ) {
+ return new WP_Error(
+ 'not_found',
+ esc_html__( 'The requested Jetpack module was not found.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $activated = array();
+ $failed = array();
+
+ foreach ( $params['modules'] as $module ) {
+ if ( Jetpack::activate_module( $module, false, false ) ) {
+ $activated[] = $module;
+ } else {
+ $failed[] = $module;
+ }
+ }
+
+ if ( empty( $failed ) ) {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'All modules activated.', 'jetpack' ),
+ ) );
+ }
+
+ $error = '';
+
+ $activated_count = count( $activated );
+ if ( $activated_count > 0 ) {
+ $activated_last = array_pop( $activated );
+ $activated_text = $activated_count > 1 ? sprintf(
+ /* Translators: first variable is a list followed by the last item, which is the second variable. Example: dog, cat and bird. */
+ __( '%1$s and %2$s', 'jetpack' ),
+ join( ', ', $activated ), $activated_last ) : $activated_last;
+
+ $error = sprintf(
+ /* Translators: the variable is a module name. */
+ _n( 'The module %s was activated.', 'The modules %s were activated.', $activated_count, 'jetpack' ),
+ $activated_text ) . ' ';
+ }
+
+ $failed_count = count( $failed );
+ if ( count( $failed ) > 0 ) {
+ $failed_last = array_pop( $failed );
+ $failed_text = $failed_count > 1 ? sprintf(
+ /* Translators: first variable is a list followed by the last item, which is the second variable. Example: dog, cat and bird. */
+ __( '%1$s and %2$s', 'jetpack' ),
+ join( ', ', $failed ), $failed_last ) : $failed_last;
+
+ $error = sprintf(
+ /* Translators: the variable is a module name. */
+ _n( 'The module %s failed to be activated.', 'The modules %s failed to be activated.', $failed_count, 'jetpack' ),
+ $failed_text ) . ' ';
+ }
+
+ return new WP_Error(
+ 'activation_failed',
+ esc_html( $error ),
+ array( 'status' => 424 )
+ );
+ }
+
+ public function can_request( $request ) {
+ if ( 'GET' === $request->get_method() ) {
+ return current_user_can( 'jetpack_admin_page' );
+ } else {
+ return current_user_can( 'jetpack_manage_modules' );
+ }
+ }
+}
+
+class Jetpack_Core_API_Module_Endpoint
+ extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
+
+ public function process( $data ) {
+ if ( 'GET' === $data->get_method() ) {
+ return $this->get_module( $data );
+ } else {
+ return $this->update_module( $data );
+ }
+ }
+
+ /**
+ * Get information about a specific and valid Jetpack module.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * }
+ *
+ * @return mixed|void|WP_Error
+ */
+ public function get_module( $data ) {
+ if ( Jetpack::is_module( $data['slug'] ) ) {
+
+ $module = Jetpack::get_module( $data['slug'] );
+
+ $module['options'] = Jetpack_Core_Json_Api_Endpoints::prepare_options_for_response( $data['slug'] );
+
+ if (
+ isset( $module['requires_connection'] )
+ && $module['requires_connection']
+ && Jetpack::is_development_mode()
+ ) {
+ $module['activated'] = false;
+ }
+
+ $i18n = jetpack_get_module_i18n( $data['slug'] );
+ if ( isset( $module['name'] ) ) {
+ $module['name'] = $i18n['name'];
+ }
+ if ( isset( $module['description'] ) ) {
+ $module['description'] = $i18n['description'];
+ $module['short_description'] = $i18n['description'];
+ }
+
+ return Jetpack_Core_Json_Api_Endpoints::prepare_modules_for_response( $module );
+ }
+
+ return new WP_Error(
+ 'not_found',
+ esc_html__( 'The requested Jetpack module was not found.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ /**
+ * If it's a valid Jetpack module and configuration parameters have been sent, update it.
+ *
+ * @since 4.3.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Module slug.
+ * }
+ *
+ * @return bool|WP_Error True if module was updated. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function update_module( $data ) {
+ if ( ! Jetpack::is_module( $data['slug'] ) ) {
+ return new WP_Error( 'not_found', esc_html__( 'The requested Jetpack module was not found.', 'jetpack' ), array( 'status' => 404 ) );
+ }
+
+ if ( ! Jetpack::is_module_active( $data['slug'] ) ) {
+ return new WP_Error( 'inactive', esc_html__( 'The requested Jetpack module is inactive.', 'jetpack' ), array( 'status' => 409 ) );
+ }
+
+ // Get parameters to update the module.
+ $params = $data->get_json_params();
+
+ // Exit if no parameters were passed.
+ if ( ! is_array( $params ) ) {
+ return new WP_Error( 'missing_options', esc_html__( 'Missing options.', 'jetpack' ), array( 'status' => 404 ) );
+ }
+
+ // Get available module options.
+ $options = Jetpack_Core_Json_Api_Endpoints::get_module_available_options( $data['slug'] );
+
+ // Options that are invalid or failed to update.
+ $invalid = array();
+ $not_updated = array();
+
+ // Used if response is successful. The message can be overwritten and additional data can be added here.
+ $response = array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'The requested Jetpack module was updated.', 'jetpack' ),
+ );
+
+ foreach ( $params as $option => $value ) {
+ // If option is invalid, don't go any further.
+ if ( ! in_array( $option, array_keys( $options ) ) ) {
+ $invalid[] = $option;
+ continue;
+ }
+
+ // Used if there was an error. Can be overwritten with specific error messages.
+ $error = '';
+
+ // Set to true if the option update was successful.
+ $updated = false;
+
+ // Properly cast value based on its type defined in endpoint accepted args.
+ $value = Jetpack_Core_Json_Api_Endpoints::cast_value( $value, $options[ $option ] );
+
+ switch ( $option ) {
+ case 'monitor_receive_notifications':
+ $monitor = new Jetpack_Monitor();
+
+ // If we got true as response, consider it done.
+ $updated = true === $monitor->update_option_receive_jetpack_monitor_notification( $value );
+ break;
+
+ case 'post_by_email_address':
+ if ( 'create' == $value ) {
+ $result = $this->_process_post_by_email(
+ 'jetpack.createPostByEmailAddress',
+ esc_html__( 'Unable to create the Post by Email address. Please try again later.', 'jetpack' )
+ );
+ } elseif ( 'regenerate' == $value ) {
+ $result = $this->_process_post_by_email(
+ 'jetpack.regeneratePostByEmailAddress',
+ esc_html__( 'Unable to regenerate the Post by Email address. Please try again later.', 'jetpack' )
+ );
+ } elseif ( 'delete' == $value ) {
+ $result = $this->_process_post_by_email(
+ 'jetpack.deletePostByEmailAddress',
+ esc_html__( 'Unable to delete the Post by Email address. Please try again later.', 'jetpack' )
+ );
+ } else {
+ $result = false;
+ }
+
+ // If we got an email address (create or regenerate) or 1 (delete), consider it done.
+ if ( preg_match( '/[a-z0-9]+@post.wordpress.com/', $result ) ) {
+ $response[ $option ] = $result;
+ $updated = true;
+ } elseif ( 1 == $result ) {
+ $updated = true;
+ } elseif ( is_array( $result ) && isset( $result['message'] ) ) {
+ $error = $result['message'];
+ }
+ break;
+
+ case 'jetpack_protect_key':
+ $protect = Jetpack_Protect_Module::instance();
+ if ( 'create' == $value ) {
+ $result = $protect->get_protect_key();
+ } else {
+ $result = false;
+ }
+
+ // If we got one of Protect keys, consider it done.
+ if ( preg_match( '/[a-z0-9]{40,}/i', $result ) ) {
+ $response[ $option ] = $result;
+ $updated = true;
+ }
+ break;
+
+ case 'jetpack_protect_global_whitelist':
+ $updated = jetpack_protect_save_whitelist( explode( PHP_EOL, str_replace( array( ' ', ',' ), array( '', "\n" ), $value ) ) );
+ if ( is_wp_error( $updated ) ) {
+ $error = $updated->get_error_message();
+ }
+ break;
+
+ case 'show_headline':
+ case 'show_thumbnails':
+ $grouped_options = $grouped_options_current = (array) Jetpack_Options::get_option( 'relatedposts' );
+ $grouped_options[ $option ] = $value;
+
+ // If option value was the same, consider it done.
+ $updated = $grouped_options_current != $grouped_options ? Jetpack_Options::update_option( 'relatedposts', $grouped_options ) : true;
+ break;
+
+ case 'google':
+ case 'bing':
+ case 'pinterest':
+ $grouped_options = $grouped_options_current = (array) get_option( 'verification_services_codes' );
+ $grouped_options[ $option ] = $value;
+
+ // If option value was the same, consider it done.
+ $updated = $grouped_options_current != $grouped_options ? update_option( 'verification_services_codes', $grouped_options ) : true;
+ break;
+
+ case 'sharing_services':
+ $sharer = new Sharing_Service();
+
+ // If option value was the same, consider it done.
+ $updated = $value != $sharer->get_blog_services() ? $sharer->set_blog_services( $value['visible'], $value['hidden'] ) : true;
+ break;
+
+ case 'button_style':
+ case 'sharing_label':
+ case 'show':
+ $sharer = new Sharing_Service();
+ $grouped_options = $sharer->get_global_options();
+ $grouped_options[ $option ] = $value;
+ $updated = $sharer->set_global_options( $grouped_options );
+ break;
+
+ case 'custom':
+ $sharer = new Sharing_Service();
+ $updated = $sharer->new_service( stripslashes( $value['sharing_name'] ), stripslashes( $value['sharing_url'] ), stripslashes( $value['sharing_icon'] ) );
+
+ // Return new custom service
+ $response[ $option ] = $updated;
+ break;
+
+ case 'sharing_delete_service':
+ $sharer = new Sharing_Service();
+ $updated = $sharer->delete_service( $value );
+ break;
+
+ case 'jetpack-twitter-cards-site-tag':
+ $value = trim( ltrim( strip_tags( $value ), '@' ) );
+ $updated = get_option( $option ) !== $value ? update_option( $option, $value ) : true;
+ break;
+
+ case 'onpublish':
+ case 'onupdate':
+ case 'Bias Language':
+ case 'Cliches':
+ case 'Complex Expression':
+ case 'Diacritical Marks':
+ case 'Double Negative':
+ case 'Hidden Verbs':
+ case 'Jargon Language':
+ case 'Passive voice':
+ case 'Phrases to Avoid':
+ case 'Redundant Expression':
+ case 'guess_lang':
+ if ( in_array( $option, array( 'onpublish', 'onupdate' ) ) ) {
+ $atd_option = 'AtD_check_when';
+ } elseif ( 'guess_lang' == $option ) {
+ $atd_option = 'AtD_guess_lang';
+ $option = 'true';
+ } else {
+ $atd_option = 'AtD_options';
+ }
+ $user_id = get_current_user_id();
+ $grouped_options_current = AtD_get_options( $user_id, $atd_option );
+ unset( $grouped_options_current['name'] );
+ $grouped_options = $grouped_options_current;
+ if ( $value && ! isset( $grouped_options [ $option ] ) ) {
+ $grouped_options [ $option ] = $value;
+ } elseif ( ! $value && isset( $grouped_options [ $option ] ) ) {
+ unset( $grouped_options [ $option ] );
+ }
+ // If option value was the same, consider it done, otherwise try to update it.
+ $options_to_save = implode( ',', array_keys( $grouped_options ) );
+ $updated = $grouped_options != $grouped_options_current ? AtD_update_setting( $user_id, $atd_option, $options_to_save ) : true;
+ break;
+
+ case 'ignored_phrases':
+ case 'unignore_phrase':
+ $user_id = get_current_user_id();
+ $atd_option = 'AtD_ignored_phrases';
+ $grouped_options = $grouped_options_current = explode( ',', AtD_get_setting( $user_id, $atd_option ) );
+ if ( 'ignored_phrases' == $option ) {
+ $grouped_options = explode( ',', $value );
+ } else {
+ $index = array_search( $value, $grouped_options );
+ if ( false !== $index ) {
+ unset( $grouped_options[ $index ] );
+ $grouped_options = array_values( $grouped_options );
+ }
+ }
+ $ignored_phrases = implode( ',', array_filter( array_map( 'strip_tags', $grouped_options ) ) );
+ $updated = $grouped_options != $grouped_options_current ? AtD_update_setting( $user_id, $atd_option, $ignored_phrases ) : true;
+ break;
+
+ case 'admin_bar':
+ case 'roles':
+ case 'count_roles':
+ case 'blog_id':
+ case 'do_not_track':
+ case 'hide_smile':
+ case 'version':
+ $grouped_options = $grouped_options_current = (array) get_option( 'stats_options' );
+ $grouped_options[ $option ] = $value;
+
+ // If option value was the same, consider it done.
+ $updated = $grouped_options_current != $grouped_options ? update_option( 'stats_options', $grouped_options ) : true;
+ break;
+
+ case 'wp_mobile_featured_images':
+ case 'wp_mobile_excerpt':
+ $value = ( 'enabled' === $value ) ? '1' : '0';
+ // break intentionally omitted
+ default:
+ // If option value was the same, consider it done.
+ $updated = get_option( $option ) != $value ? update_option( $option, $value ) : true;
+ break;
+ }
+
+ // The option was not updated.
+ if ( ! $updated ) {
+ $not_updated[ $option ] = $error;
+ }
+ }
+
+ if ( empty( $invalid ) && empty( $not_updated ) ) {
+ // The option was updated.
+ return rest_ensure_response( $response );
+ } else {
+ $invalid_count = count( $invalid );
+ $not_updated_count = count( $not_updated );
+ $error = '';
+ if ( $invalid_count > 0 ) {
+ $error = sprintf(
+ /* Translators: the plural variable is a comma-separated list. Example: dog, cat, bird. */
+ _n( 'Invalid option for this module: %s.', 'Invalid options for this module: %s.', $invalid_count, 'jetpack' ),
+ join( ', ', $invalid )
+ );
+ }
+ if ( $not_updated_count > 0 ) {
+ $not_updated_messages = array();
+ foreach ( $not_updated as $not_updated_option => $not_updated_message ) {
+ if ( ! empty( $not_updated_message ) ) {
+ $not_updated_messages[] = sprintf(
+ /* Translators: the first variable is a module option name. The second is the error message . */
+ __( 'Extra info for %1$s: %2$s', 'jetpack' ),
+ $not_updated_option, $not_updated_message );
+ }
+ }
+ if ( ! empty( $error ) ) {
+ $error .= ' ';
+ }
+ $error .= sprintf(
+ /* Translators: the plural variable is a comma-separated list. Example: dog, cat, bird. */
+ _n( 'Option not updated: %s.', 'Options not updated: %s.', $not_updated_count, 'jetpack' ),
+ join( ', ', array_keys( $not_updated ) ) );
+ if ( ! empty( $not_updated_messages ) ) {
+ $error .= ' ' . join( '. ', $not_updated_messages );
+ }
+
+ }
+ // There was an error because some options were updated but others were invalid or failed to update.
+ return new WP_Error( 'some_updated', esc_html( $error ), array( 'status' => 400 ) );
+ }
+
+ }
+
+ /**
+ * Calls WPCOM through authenticated request to create, regenerate or delete the Post by Email address.
+ * @todo: When all settings are updated to use endpoints, move this to the Post by Email module and replace __process_ajax_proxy_request.
+ *
+ * @since 4.3.0
+ *
+ * @param string $endpoint Process to call on WPCOM to create, regenerate or delete the Post by Email address.
+ * @param string $error Error message to return.
+ *
+ * @return array
+ */
+ private function _process_post_by_email( $endpoint, $error ) {
+ if ( ! current_user_can( 'edit_posts' ) ) {
+ return array( 'message' => $error );
+ }
+
+ $this->xmlrpc->query( $endpoint );
+
+ if ( $this->xmlrpc->isError() ) {
+ return array( 'message' => $error );
+ }
+
+ $response = $this->xmlrpc->getResponse();
+ if ( empty( $response ) ) {
+ return array( 'message' => $error );
+ }
+
+ // Used only in Jetpack_Core_Json_Api_Endpoints::get_remote_value.
+ update_option( 'post_by_email_address' . get_current_user_id(), $response );
+
+ return $response;
+ }
+
+ /**
+ * Check if user is allowed to perform the update.
+ *
+ * @since 4.3
+ *
+ * @param WP_REST_Request $request
+ *
+ * @return bool
+ */
+ public function can_request( $request ) {
+ if ( 'GET' === $request->get_method() ) {
+ return current_user_can( 'jetpack_admin_page' );
+ } else {
+ $module = Jetpack_Core_Json_Api_Endpoints::get_module_requested();
+ // User is trying to create, regenerate or delete its PbE || ATD settings.
+ if ( 'post-by-email' === $module || 'after-the-deadline' === $module ) {
+ return current_user_can( 'edit_posts' ) && current_user_can( 'jetpack_admin_page' );
+ }
+ return current_user_can( 'jetpack_configure_modules' );
+ }
+ }
+}
+
+class Jetpack_Core_API_Module_Data_Endpoint {
+
+ public function process( $request ) {
+ switch( $request['slug'] ) {
+ case 'protect':
+ return $this->get_protect_data();
+ case 'stats':
+ return $this->get_stats_data( $request );
+ case 'akismet':
+ return $this->get_akismet_data();
+ case 'monitor':
+ return $this->get_monitor_data();
+ case 'verification-tools':
+ return $this->get_verification_tools_data();
+ case 'vaultpress':
+ return $this->get_vaultpress_data();
+ }
+ }
+
+ /**
+ * Get number of blocked intrusion attempts.
+ *
+ * @since 4.3.0
+ *
+ * @return mixed|WP_Error Number of blocked attempts if protection is enabled. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function get_protect_data() {
+ if ( Jetpack::is_module_active( 'protect' ) ) {
+ return get_site_option( 'jetpack_protect_blocked_attempts' );
+ }
+
+ return new WP_Error(
+ 'not_active',
+ esc_html__( 'The requested Jetpack module is not active.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ /**
+ * Get number of spam messages blocked by Akismet.
+ *
+ * @since 4.3.0
+ *
+ * @return int|string Number of spam blocked by Akismet. Otherwise, an error message.
+ */
+ public function get_akismet_data() {
+ if ( ! is_wp_error( $status = $this->akismet_is_active_and_registered() ) ) {
+ return rest_ensure_response( Akismet_Admin::get_stats( Akismet::get_api_key() ) );
+ } else {
+ return $status->get_error_code();
+ }
+ }
+
+ /**
+ * Is Akismet registered and active?
+ *
+ * @since 4.3.0
+ *
+ * @return bool|WP_Error True if Akismet is active and registered. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ private function akismet_is_active_and_registered() {
+ if ( ! file_exists( WP_PLUGIN_DIR . '/akismet/class.akismet.php' ) ) {
+ return new WP_Error( 'not_installed', esc_html__( 'Please install Akismet.', 'jetpack' ), array( 'status' => 400 ) );
+ }
+
+ if ( ! class_exists( 'Akismet' ) ) {
+ return new WP_Error( 'not_active', esc_html__( 'Please activate Akismet.', 'jetpack' ), array( 'status' => 400 ) );
+ }
+
+ // What about if Akismet is put in a sub-directory or maybe in mu-plugins?
+ require_once WP_PLUGIN_DIR . '/akismet/class.akismet.php';
+ require_once WP_PLUGIN_DIR . '/akismet/class.akismet-admin.php';
+ $akismet_key = Akismet::verify_key( Akismet::get_api_key() );
+
+ if ( ! $akismet_key || 'invalid' === $akismet_key || 'failed' === $akismet_key ) {
+ return new WP_Error( 'invalid_key', esc_html__( 'Invalid Akismet key. Please contact support.', 'jetpack' ), array( 'status' => 400 ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Get stats data for this site
+ *
+ * @since 4.1.0
+ *
+ * @param WP_REST_Request $data {
+ * Array of parameters received by request.
+ *
+ * @type string $date Date range to restrict results to.
+ * }
+ *
+ * @return int|string Number of spam blocked by Akismet. Otherwise, an error message.
+ */
+ public function get_stats_data( WP_REST_Request $data ) {
+ // Get parameters to fetch Stats data.
+ $range = $data->get_param( 'range' );
+
+ // If no parameters were passed.
+ if (
+ empty ( $range )
+ || ! in_array( $range, array( 'day', 'week', 'month' ), true )
+ ) {
+ $range = 'day';
+ }
+
+ if ( ! function_exists( 'stats_get_from_restapi' ) ) {
+ require_once( JETPACK__PLUGIN_DIR . 'modules/stats.php' );
+ }
+
+ $response = array(
+ 'general' => stats_get_from_restapi(),
+ );
+
+ switch ( $range ) {
+ case 'day':
+ $response['day'] = stats_get_from_restapi( array(), 'visits?unit=day&quantity=30' );
+ break;
+ case 'week':
+ $response['week'] = stats_get_from_restapi( array(), 'visits?unit=week&quantity=14' );
+ break;
+ case 'month':
+ $response['month'] = stats_get_from_restapi( array(), 'visits?unit=month&quantity=12&' );
+ break;
+ }
+
+ return rest_ensure_response( $response );
+ }
+
+ /**
+ * Get date of last downtime.
+ *
+ * @since 4.3.0
+ *
+ * @return mixed|WP_Error Number of days since last downtime. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function get_monitor_data() {
+ if ( ! Jetpack::is_module_active( 'monitor' ) ) {
+ return new WP_Error(
+ 'not_active',
+ esc_html__( 'The requested Jetpack module is not active.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $monitor = new Jetpack_Monitor();
+ $last_downtime = $monitor->monitor_get_last_downtime();
+ if ( is_wp_error( $last_downtime ) ) {
+ return $last_downtime;
+ } else if ( false === strtotime( $last_downtime ) ) {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'date' => null,
+ ) );
+ } else {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'date' => human_time_diff( strtotime( $last_downtime ), strtotime( 'now' ) ),
+ ) );
+ }
+ }
+
+ /**
+ * Get services that this site is verified with.
+ *
+ * @since 4.3.0
+ *
+ * @return mixed|WP_Error List of services that verified this site. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function get_verification_tools_data() {
+ if ( ! Jetpack::is_module_active( 'verification-tools' ) ) {
+ return new WP_Error(
+ 'not_active',
+ esc_html__( 'The requested Jetpack module is not active.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $verification_services_codes = get_option( 'verification_services_codes' );
+ if (
+ ! is_array( $verification_services_codes )
+ || empty( $verification_services_codes )
+ ) {
+ return new WP_Error(
+ 'empty',
+ esc_html__( 'Site not verified with any service.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $services = array();
+ foreach ( jetpack_verification_services() as $name => $service ) {
+ if ( is_array( $service ) && ! empty( $verification_services_codes[ $name ] ) ) {
+ switch ( $name ) {
+ case 'google':
+ $services[] = 'Google';
+ break;
+ case 'bing':
+ $services[] = 'Bing';
+ break;
+ case 'pinterest':
+ $services[] = 'Pinterest';
+ break;
+ }
+ }
+ }
+
+ if ( empty( $services ) ) {
+ return new WP_Error(
+ 'empty',
+ esc_html__( 'Site not verified with any service.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ if ( 2 > count( $services ) ) {
+ $message = esc_html(
+ sprintf(
+ /* translators: %s is a service name like Google, Bing, Pinterest, etc. */
+ __( 'Your site is verified with %s.', 'jetpack' ),
+ $services[0]
+ )
+ );
+ } else {
+ $copy_services = $services;
+ $last = count( $copy_services ) - 1;
+ $last_service = $copy_services[ $last ];
+ unset( $copy_services[ $last ] );
+ $message = esc_html(
+ sprintf(
+ /* translators: %1$s is a comma separated list of services, and %2$s is a single service name like Google, Bing, Pinterest, etc. */
+ __( 'Your site is verified with %1$s and %2$s.', 'jetpack' ),
+ join( ', ', $copy_services ),
+ $last_service
+ )
+ );
+ }
+
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => $message,
+ 'services' => $services,
+ ) );
+ }
+
+ /**
+ * Get VaultPress site data including, among other things, the date of the last backup if it was completed.
+ *
+ * @since 4.3.0
+ *
+ * @return mixed|WP_Error VaultPress site data. Otherwise, a WP_Error instance with the corresponding error.
+ */
+ public function get_vaultpress_data() {
+ if ( ! class_exists( 'VaultPress' ) ) {
+ return new WP_Error(
+ 'not_active',
+ esc_html__( 'The requested Jetpack module is not active.', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $vaultpress = new VaultPress();
+ if ( ! $vaultpress->is_registered() ) {
+ return rest_ensure_response( array(
+ 'code' => 'not_registered',
+ 'message' => esc_html__( 'You need to register for VaultPress.', 'jetpack' )
+ ) );
+ }
+
+ $data = json_decode( base64_decode( $vaultpress->contact_service( 'plugin_data' ) ) );
+ if ( is_wp_error( $data ) ) {
+ return $data;
+ } else if ( ! $data->backups->last_backup ) {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'VaultPress is active and will back up your site soon.', 'jetpack' ),
+ 'data' => $data,
+ ) );
+ } else {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html(
+ sprintf(
+ __( 'Your site was successfully backed-up %s ago.', 'jetpack' ),
+ human_time_diff(
+ $data->backups->last_backup,
+ current_time( 'timestamp' )
+ )
+ )
+ ),
+ 'data' => $data,
+ ) );
+ }
+ }
+
+ public function can_request() {
+ return current_user_can( 'jetpack_admin_page' );
+ }
+}
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php
new file mode 100644
index 00000000..78dfe595
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * This is the base class for every Core API endpoint that needs an XMLRPC client.
+ *
+ */
+abstract class Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
+
+ /**
+ * An instance of the Jetpack XMLRPC client to make WordPress.com requests
+ *
+ * @private
+ * @var Jetpack_IXR_Client
+ */
+ protected $xmlrpc;
+
+ /**
+ * @param Jetpack_IXR_Client $xmlrpc
+ */
+ public function __construct( $xmlrpc ) {
+ $this->xmlrpc = $xmlrpc;
+ }
+
+ /**
+ * Checks if the site is public and returns the result.
+ * @return Boolean $is_public
+ */
+ protected function is_site_public() {
+ if ( $this->xmlrpc->query( 'jetpack.isSitePubliclyAccessible', home_url() ) ) {
+ return $this->xmlrpc->getResponse();
+ }
+ return false;
+ }
+} \ No newline at end of file