Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.08% covered (success)
98.08%
51 / 52
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
REST_Controller
98.08% covered (success)
98.08%
51 / 52
75.00% covered (warning)
75.00%
3 / 4
7
0.00% covered (danger)
0.00%
0 / 1
 register_rest_routes
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
1
 helper_script_permissions_callback
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 install_helper_script
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 delete_helper_script
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * The Jetpack Helper Script Rest Controller class.
4 * Registers the REST routes.
5 *
6 * @package automattic/jetpack-transport-helper
7 */
8
9// After changing this file, consider increasing the version number ("VXXX") in all the files using this namespace, in
10// order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide
11// to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin
12// are installed, or in some other cases).
13namespace Automattic\Jetpack\Transport_Helper\V0005;
14
15use Automattic\Jetpack\Backup\V0005\Helper_Script_Manager;
16use Automattic\Jetpack\Connection\Rest_Authentication;
17use WP_Error;
18use WP_REST_Request;
19use WP_REST_Server;
20// phpcs:ignore WordPress.Utils.I18nTextDomainFixer.MissingArgs
21use function esc_html__;
22use function is_wp_error;
23use function register_rest_route;
24use function rest_authorization_required_code;
25use function rest_ensure_response;
26
27/**
28 * Registers the REST routes.
29 */
30class REST_Controller {
31    /**
32     * Registers the REST routes.
33     *
34     * @access public
35     * @static
36     */
37    public static function register_rest_routes() {
38        // Install a Helper Script to assist with fetching data.
39        register_rest_route(
40            'jetpack/v4',
41            // This route can be generalized once we no longer depend on the backup package
42            '/backup-helper-script',
43            array(
44                'methods'             => WP_REST_Server::CREATABLE,
45                'callback'            => __CLASS__ . '::install_helper_script',
46                'permission_callback' => __CLASS__ . '::helper_script_permissions_callback',
47                'args'                => array(
48                    'helper' => array(
49                        'description' => __( 'base64 encoded Helper Script body.', 'jetpack-transport-helper' ),
50                        'type'        => 'string',
51                        'required'    => true,
52                    ),
53                ),
54            )
55        );
56
57        // Delete a Helper Script.
58        register_rest_route(
59            'jetpack/v4',
60            // This route can be generalized once we no longer depend on the backup package
61            '/backup-helper-script',
62            array(
63                'methods'             => WP_REST_Server::DELETABLE,
64                'callback'            => __CLASS__ . '::delete_helper_script',
65                'permission_callback' => __CLASS__ . '::helper_script_permissions_callback',
66                'args'                => array(
67                    'path' => array(
68                        'description' => __( 'Path to Helper Script', 'jetpack-transport-helper' ),
69                        'type'        => 'string',
70                        'required'    => true,
71                    ),
72                ),
73            )
74        );
75    }
76
77    /**
78     * The Jetpack endpoints should only be available via site-level authentication.
79     * This means that the corresponding endpoints can only be accessible from WPCOM.
80     *
81     * @access public
82     * @static
83     *
84     * @return bool|WP_Error True if a blog token was used to sign the request, WP_Error otherwise.
85     */
86    public static function helper_script_permissions_callback() {
87        if ( Rest_Authentication::is_signed_with_blog_token() ) {
88            return true;
89        }
90
91        $error_msg = esc_html__(
92            'You are not allowed to perform this action.',
93            'jetpack-transport-helper'
94        );
95
96        return new WP_Error( 'rest_forbidden', $error_msg, array( 'status' => rest_authorization_required_code() ) );
97    }
98
99    /**
100     * Install the Helper Script.
101     *
102     * @access public
103     * @static
104     *
105     * @param WP_REST_Request $request The request sent to the WP REST API.
106     *
107     * @return array|WP_Error An array with installation info on success:
108     *
109     *   'path'    (string) Helper script installation path on the filesystem.
110     *   'url'     (string) URL to the helper script.
111     *   'abspath' (string) WordPress root.
112     *
113     *   or an instance of WP_Error on failure.
114     */
115    public static function install_helper_script( $request ) {
116        $helper_script = $request->get_param( 'helper' );
117
118        // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
119        $helper_script = base64_decode( $helper_script );
120        if ( ! $helper_script ) {
121            return new WP_Error( 'invalid_args', __( 'Helper Script body must be base64 encoded', 'jetpack-transport-helper' ), 400 );
122        }
123
124        $installation_info = Helper_Script_Manager::install_helper_script( $helper_script );
125        Helper_Script_Manager::cleanup_expired_helper_scripts();
126
127        return rest_ensure_response( $installation_info );
128    }
129
130    /**
131     * Delete a Helper Script.
132     *
133     * @access public
134     * @static
135     *
136     * @param WP_REST_Request $request The request sent to the WP REST API.
137     *
138     * @return array|WP_Error An array with 'success' key indicating the result of the delete operation.
139     */
140    public static function delete_helper_script( $request ) {
141        $path_to_helper_script = $request->get_param( 'path' );
142
143        $delete_result = Helper_Script_Manager::delete_helper_script( $path_to_helper_script );
144        Helper_Script_Manager::cleanup_expired_helper_scripts();
145
146        if ( is_wp_error( $delete_result ) ) {
147            return $delete_result;
148        }
149
150        return rest_ensure_response( array( 'success' => true ) );
151    }
152}