PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.2-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.2-a.1
16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 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 / jetpack_vendor / automattic / jetpack-licensing / src / class-licensing.php
jetpack / jetpack_vendor / automattic / jetpack-licensing / src Last commit date
class-endpoints.php 8 months ago class-licensing.php 8 months ago
class-licensing.php
360 lines
1 <?php
2 /**
3 * A Terms of Service class for Jetpack.
4 *
5 * @package automattic/jetpack-licensing
6 */
7
8 namespace Automattic\Jetpack;
9
10 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11 use Automattic\Jetpack\Licensing\Endpoints;
12 use Jetpack_IXR_ClientMulticall;
13 use Jetpack_Options;
14 use WP_Error;
15
16 /**
17 * Class Licensing.
18 * Helper class that is responsible for attaching licenses to the current site.
19 *
20 * @since 1.1.1
21 */
22 class Licensing {
23 /**
24 * Name of the WordPress option that holds all known Jetpack licenses.
25 *
26 * @const string
27 */
28 const LICENSES_OPTION_NAME = 'jetpack_licenses';
29
30 /**
31 * Name of the WordPress transient that holds the last license attaching error, if any.
32 *
33 * @const string
34 */
35 const ERROR_TRANSIENT_NAME = 'jetpack_licenses_error';
36
37 /**
38 * Holds the singleton instance of this class.
39 *
40 * @var self
41 */
42 protected static $instance = false;
43
44 /**
45 * Singleton.
46 *
47 * @static
48 */
49 public static function instance() {
50 if ( ! self::$instance ) {
51 self::$instance = new self();
52 }
53
54 return self::$instance;
55 }
56
57 /**
58 * Initialize.
59 *
60 * @return void
61 */
62 public function initialize() {
63 add_action( 'add_option_' . self::LICENSES_OPTION_NAME, array( $this, 'attach_stored_licenses' ) );
64 add_action( 'update_option_' . self::LICENSES_OPTION_NAME, array( $this, 'attach_stored_licenses' ) );
65 add_action( 'jetpack_authorize_ending_authorized', array( $this, 'attach_stored_licenses_on_connection' ) );
66 add_action( 'rest_api_init', array( $this, 'initialize_endpoints' ) );
67 }
68
69 /**
70 * Initialize endpoints required for Licensing package.
71 *
72 * @since 1.7.0
73 *
74 * @return void
75 */
76 public function initialize_endpoints() {
77 $endpoints = new Endpoints();
78 $endpoints->register_endpoints();
79 }
80
81 /**
82 * Get Jetpack connection manager instance.
83 *
84 * @return Connection_Manager
85 */
86 protected function connection() {
87 static $connection;
88
89 if ( null === $connection ) {
90 $connection = new Connection_Manager();
91 }
92
93 return $connection;
94 }
95
96 /**
97 * Get the last license attach request error that has occurred, if any.
98 *
99 * @return string Human-readable error message or an empty string.
100 */
101 public function last_error() {
102 return Jetpack_Options::get_option( 'licensing_error', '' );
103 }
104
105 /**
106 * Log an error to be surfaced to the user at a later time.
107 *
108 * @param string $error Human-readable error message.
109 * @return void
110 */
111 public function log_error( $error ) {
112 $substr = function_exists( 'mb_substr' ) ? 'mb_substr' : 'substr';
113 Jetpack_Options::update_option( 'licensing_error', $substr( $error, 0, 1024 ) );
114 }
115
116 /**
117 * Get all stored licenses.
118 *
119 * @return string[] License keys.
120 */
121 public function stored_licenses() {
122 $licenses = (array) get_option( self::LICENSES_OPTION_NAME, array() );
123 $licenses = array_filter( $licenses, 'is_scalar' );
124 $licenses = array_map( 'strval', $licenses );
125 $licenses = array_filter( $licenses );
126
127 return $licenses;
128 }
129
130 /**
131 * Append a license
132 *
133 * @param string $license A jetpack license key.
134 * @return bool True if the option was updated with the new license, false otherwise.
135 */
136 public function append_license( $license ) {
137 $licenses = $this->stored_licenses();
138
139 array_push( $licenses, $license );
140
141 return update_option( self::LICENSES_OPTION_NAME, $licenses );
142 }
143
144 /**
145 * Make an authenticated WP.com XMLRPC multicall request to attach the provided license keys.
146 *
147 * @param string[] $licenses License keys to attach.
148 * @return Jetpack_IXR_ClientMulticall
149 */
150 protected function attach_licenses_request( array $licenses ) {
151 $xml = new Jetpack_IXR_ClientMulticall( array( 'timeout' => 30 ) );
152
153 foreach ( $licenses as $license ) {
154 $xml->addCall( 'jetpack.attachLicense', $license );
155 }
156
157 $xml->query();
158
159 return $xml;
160 }
161
162 /**
163 * Attach the given licenses.
164 *
165 * @param string[] $licenses Licenses to attach.
166 * @return array|WP_Error Results for each license (which may include WP_Error instances) or a WP_Error instance.
167 */
168 public function attach_licenses( array $licenses ) {
169 if ( ! $this->connection()->has_connected_owner() ) {
170 return new WP_Error( 'not_connected', __( 'Jetpack doesn\'t have a connected owner.', 'jetpack-licensing' ) );
171 }
172
173 if ( empty( $licenses ) ) {
174 return array();
175 }
176
177 $xml = $this->attach_licenses_request( $licenses );
178
179 if ( $xml->isError() ) {
180 $error = new WP_Error( 'request_failed', __( 'License attach request failed.', 'jetpack-licensing' ) );
181 $error->add( $xml->getErrorCode(), $xml->getErrorMessage() );
182 return $error;
183 }
184
185 $results = array_map(
186 function ( $response ) {
187 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
188 return new WP_Error( $response['faultCode'], $response['faultString'] );
189 }
190
191 return $response;
192 },
193 (array) $xml->getResponse()
194 );
195
196 return $results;
197 }
198
199 /**
200 * Attach all stored licenses.
201 *
202 * @return array|WP_Error Results for each license (which may include WP_Error instances) or a WP_Error instance.
203 */
204 public function attach_stored_licenses() {
205 $licenses = $this->stored_licenses();
206 $results = $this->attach_licenses( $licenses );
207
208 if ( is_wp_error( $results ) ) {
209 if ( 'request_failed' === $results->get_error_code() ) {
210 $this->log_error(
211 __( 'Failed to attach your Jetpack license(s). Please try reconnecting Jetpack.', 'jetpack-licensing' )
212 );
213 }
214
215 return $results;
216 }
217
218 $failed = array();
219
220 foreach ( $results as $index => $result ) {
221 if ( isset( $licenses[ $index ] ) && is_wp_error( $result ) ) {
222 $failed[] = $licenses[ $index ];
223 }
224 }
225
226 if ( ! empty( $failed ) ) {
227 $this->log_error(
228 sprintf(
229 /* translators: %s is a comma-separated list of license keys. */
230 __( 'The following Jetpack licenses are invalid, already in use, or revoked: %s', 'jetpack-licensing' ),
231 implode( ', ', $failed )
232 )
233 );
234 }
235
236 return $results;
237 }
238
239 /**
240 * Attach all stored licenses during connection flow for the connection owner.
241 *
242 * @return void
243 */
244 public function attach_stored_licenses_on_connection() {
245 if ( $this->connection()->is_connection_owner() ) {
246 $this->attach_stored_licenses();
247 }
248 }
249
250 /**
251 * Is the current user allowed to use the Licensing Input UI?
252 *
253 * @since 1.4.0
254 * @return bool
255 */
256 public static function is_licensing_input_enabled() {
257 /**
258 * Filter that checks if the user is allowed to see the Licensing UI. `true` enables it.
259 *
260 * @since 1.4.0
261 *
262 * @param bool False by default.
263 */
264 return apply_filters( 'jetpack_licensing_ui_enabled', false ) && current_user_can( 'jetpack_connect_user' );
265 }
266
267 /**
268 * Gets the user-licensing activation notice dismissal info.
269 *
270 * @since 10.4.0
271 * @return array
272 */
273 public function get_license_activation_notice_dismiss() {
274
275 $default = array(
276 'last_detached_count' => null,
277 'last_dismissed_time' => null,
278 );
279
280 if ( $this->connection()->is_user_connected() && $this->connection()->is_connection_owner() ) {
281 return Jetpack_Options::get_option( 'licensing_activation_notice_dismiss', $default );
282 }
283
284 return $default;
285 }
286
287 /**
288 * Load current user's licenses.
289 *
290 * @param bool $unattached_only Only return unattached and not revoked licenses.
291 *
292 * @return array
293 */
294 public function get_user_licenses( $unattached_only = false ) {
295 $licenses = Endpoints::get_user_licenses();
296
297 if ( empty( $licenses->items ) ) {
298 return array();
299 }
300
301 $items = $licenses->items;
302
303 if ( $unattached_only ) {
304 $items = array_filter(
305 $items,
306 static function ( $item ) {
307 return $item->attached_at === null && $item->revoked_at === null;
308 }
309 );
310 }
311
312 return $items;
313 }
314
315 /**
316 * If the destination URL is checkout page,
317 * see if there are unattached licenses they could use instead of getting a new one.
318 * If found, redirect the user to license activation.
319 *
320 * @param string $dest_url User's destination URL.
321 *
322 * @return void
323 */
324 public function handle_user_connected_redirect( $dest_url ) {
325 if ( ! preg_match( '#^https://[^/]+/checkout/#i', $dest_url ) ) {
326 return;
327 }
328
329 $licenses = $this->get_user_licenses( true );
330 $plugin_slug = null;
331
332 $query_string = wp_parse_url( $dest_url, PHP_URL_QUERY );
333 if ( $query_string ) {
334 parse_str( $query_string, $query_args );
335
336 if ( $query_args['redirect_to']
337 && preg_match( '/^admin\.php\?page=(jetpack-\w+)/i', $query_args['redirect_to'], $matches )
338 ) {
339 $plugin_slug = $matches[1];
340 }
341 }
342
343 /**
344 * Check for the user's unattached licenses.
345 *
346 * @since 3.8.2
347 *
348 * @param bool $has_license Whether a license was already found.
349 * @param array $licenses Unattached licenses belonging to the user.
350 * @param string $plugin_slug Slug of the plugin that initiated the flow.
351 */
352 if ( $plugin_slug && count( $licenses )
353 && apply_filters( 'jetpack_connection_user_has_license', false, $licenses, $plugin_slug )
354 ) {
355 wp_safe_redirect( '/wp-admin/admin.php?page=my-jetpack#/add-license' );
356 exit( 0 );
357 }
358 }
359 }
360