PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | src/reprint-export/class-rest-controller.php +143 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,143 @@
1 +<?php
2 +/**
3 + * REST controller for Jetpack Reprint export provisioning endpoints.
4 + *
5 + * Requires a verified Jetpack user token for a site administrator.
6 + *
7 + * @package automattic/jetpack
8 + */
9 +
10 +namespace Automattic\Jetpack\Reprint_Export;
11 +
12 +use Automattic\Jetpack\Connection\Rest_Authentication;
13 +use WP_REST_Controller;
14 +use WP_REST_Response;
15 +use WP_REST_Server;
16 +
17 +/**
18 + * Reprint exporter REST controller.
19 + */
20 +class REST_Controller extends WP_REST_Controller {
21 +
22 + /**
23 + * The API namespace.
24 + *
25 + * @var string
26 + */
27 + protected $namespace = 'jetpack/v4';
28 +
29 + /**
30 + * The REST base path.
31 + *
32 + * @var string
33 + */
34 + protected $rest_base = 'reprint';
35 +
36 + /**
37 + * Registers the reprint export routes.
38 + */
39 + public function register_routes() {
40 + register_rest_route(
41 + $this->namespace,
42 + '/' . $this->rest_base . '/rotate-export-secret',
43 + array(
44 + array(
45 + 'methods' => WP_REST_Server::CREATABLE,
46 + 'callback' => array( $this, 'rotate_secret' ),
47 + 'permission_callback' => array( $this, 'permission_check' ),
48 + ),
49 + )
50 + );
51 +
52 + register_rest_route(
53 + $this->namespace,
54 + '/' . $this->rest_base . '/enable-export',
55 + array(
56 + array(
57 + 'methods' => WP_REST_Server::CREATABLE,
58 + 'callback' => array( $this, 'enable_export' ),
59 + 'permission_callback' => array( $this, 'permission_check' ),
60 + ),
61 + )
62 + );
63 + }
64 +
65 + /**
66 + * Opens the export window without rotating the secret, so a client that
67 + * already has one can reopen a window that has closed.
68 + *
69 + * Registered only where the feature is available, so clients also use a 404
70 + * from here to tell whether the site supports export at all.
71 + *
72 + * @return WP_REST_Response The unix timestamp the window was opened at.
73 + */
74 + public function enable_export() {
75 + $enabled_at = Reprint_Exporter::open_export_window();
76 +
77 + Reprint_Exporter::record_event(
78 + 'window_opened',
79 + array( 'user_id' => get_current_user_id() )
80 + );
81 +
82 + return new WP_REST_Response( array( 'enabled_at' => $enabled_at ), 200 );
83 + }
84 +
85 + /**
86 + * Rotates the shared secret and returns it.
87 + *
88 + * Uses random_bytes() rather than wp_generate_password(). That helper is for
89 + * passwords a person reads and types, and sites can filter it through
90 + * `random_password` to enforce their own policy — an extension point we do
91 + * not want on a credential. random_bytes() also throws rather than quietly
92 + * falling back to a weaker source, which wp_rand() will do.
93 + *
94 + * @return WP_REST_Response The new secret on success, or a 500 error.
95 + */
96 + public function rotate_secret() {
97 + $secret = bin2hex( random_bytes( 32 ) );
98 +
99 + if ( ! Reprint_Exporter::store_secret( $secret ) ) {
100 + return new WP_REST_Response(
101 + array( 'error' => 'Failed to persist the new secret.' ),
102 + 500
103 + );
104 + }
105 +
106 + Reprint_Exporter::record_event(
107 + 'secret_rotated',
108 + array( 'user_id' => get_current_user_id() )
109 + );
110 +
111 + return new WP_REST_Response( array( 'secret' => $secret ), 200 );
112 + }
113 +
114 + /**
115 + * Permission callback: a Jetpack-signed request from a site administrator.
116 + *
117 + * Deliberately a role check, not a capability one. This hands out a secret
118 + * that streams the whole database and file tree, and no capability says
119 + * that — `manage_options` is the closest, but plugins grant it to shop
120 + * managers and the like.
121 + *
122 + * @return bool
123 + */
124 + public function permission_check() {
125 + if ( ! Rest_Authentication::is_signed_with_user_token() ) {
126 + return false;
127 + }
128 +
129 + $user = wp_get_current_user();
130 + if ( ! $user || ! $user->exists() ) {
131 + return false;
132 + }
133 +
134 + // Network administrator only: the export takes every table and everything
135 + // under ABSPATH, so a subsite administrator would leave with every other
136 + // site's users, content and uploads.
137 + if ( is_multisite() ) {
138 + return is_super_admin( $user->ID );
139 + }
140 +
141 + return in_array( 'administrator', $user->roles, true );
142 + }
143 +}