PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
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 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-licensing / src / class-licensing.php

class-licensing.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-licensing/src/class-licensing.php

360 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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