Plugin Directory

source: jetpack/trunk/class.jetpack-client-server.php @ 2110047

Last change on this file since 2110047 was 2110047, checked in by jeherve, 5 years ago

Jetpack 7.5 Beta 1

https://github.com/Automattic/jetpack/releases/tag/7.5-beta

File size: 8.8 KB
Line 
1<?php
2
3use Automattic\Jetpack\Connection\Client;
4use Automattic\Jetpack\Tracking;
5
6/**
7 * Client = Plugin
8 * Client Server = API Methods the Plugin must respond to
9 */
10class Jetpack_Client_Server {
11
12        /**
13         * Authorizations
14         */
15        function client_authorize() {
16                $data              = stripslashes_deep( $_GET );
17                $data['auth_type'] = 'client';
18                $role              = Jetpack::translate_current_user_to_role();
19                $redirect          = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
20
21                check_admin_referer( "jetpack-authorize_{$role}_{$redirect}" );
22
23                $tracking = new Tracking();
24                $result = $this->authorize( $data );
25                if ( is_wp_error( $result ) ) {
26                        Jetpack::state( 'error', $result->get_error_code() );
27
28                        $tracking->record_user_event( 'jpc_client_authorize_fail', array(
29                                'error_code' => $result->get_error_code(),
30                                'error_message' => $result->get_error_message()
31                        ) );
32                } else {
33                        /**
34                         * Fires after the Jetpack client is authorized to communicate with WordPress.com.
35                         *
36                         * @since 4.2.0
37                         *
38                         * @param int Jetpack Blog ID.
39                         */
40                        do_action( 'jetpack_client_authorized', Jetpack_Options::get_option( 'id' ) );
41                }
42
43                if ( wp_validate_redirect( $redirect ) ) {
44                        // Exit happens below in $this->do_exit()
45                        wp_safe_redirect( $redirect );
46                } else {
47                        // Exit happens below in $this->do_exit()
48                        wp_safe_redirect( Jetpack::admin_url() );
49                }
50
51                $tracking->record_user_event( 'jpc_client_authorize_success' );
52
53                $this->do_exit();
54        }
55
56        function authorize( $data = array() ) {
57                $redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
58
59                $jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' );
60                // Checking if site has been active/connected previously before recording unique connection
61                if ( ! $jetpack_unique_connection ) {
62                        // jetpack_unique_connection option has never been set
63                        $jetpack_unique_connection = array(
64                                'connected'     => 0,
65                                'disconnected'  => 0,
66                                'version'       => '3.6.1',
67                        );
68
69                        update_option( 'jetpack_unique_connection', $jetpack_unique_connection );
70
71                        //track unique connection
72                        $jetpack = $this->get_jetpack();
73
74                        $jetpack->stat( 'connections', 'unique-connection' );
75                        $jetpack->do_stats( 'server_side' );
76                }
77
78                // increment number of times connected
79                $jetpack_unique_connection['connected'] += 1;
80                Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection );
81
82                $role = Jetpack::translate_current_user_to_role();
83
84                if ( ! $role ) {
85                        return new Jetpack_Error( 'no_role', 'Invalid request.', 400 );
86                }
87
88                $cap = Jetpack::translate_role_to_cap( $role );
89                if ( ! $cap ) {
90                        return new Jetpack_Error( 'no_cap', 'Invalid request.', 400 );
91                }
92
93                if ( ! empty( $data['error'] ) ) {
94                        return new Jetpack_Error( $data['error'], 'Error included in the request.', 400 );
95                }
96
97                if ( ! isset( $data['state'] ) ) {
98                        return new Jetpack_Error( 'no_state', 'Request must include state.', 400 );
99                }
100
101                if (��! ctype_digit( $data['state'] ) ) {
102                        return new Jetpack_Error( $data['error'], 'State must be an integer.', 400 );
103                }
104
105                $current_user_id = get_current_user_id();
106                if ( $current_user_id != $data['state'] ) {
107                        return new Jetpack_Error( 'wrong_state', 'State does not match current user.', 400 );
108                }
109
110                if ( empty( $data['code'] ) ) {
111                        return new Jetpack_Error( 'no_code', 'Request must include an authorization code.', 400 );
112                }
113
114                $token = $this->get_token( $data );
115
116                if ( is_wp_error( $token ) ) {
117                        $code = $token->get_error_code();
118                        if ( empty( $code ) ) {
119                                $code = 'invalid_token';
120                        }
121                        return new Jetpack_Error( $code, $token->get_error_message(), 400 );
122                }
123
124                if ( ! $token ) {
125                        return new Jetpack_Error( 'no_token', 'Error generating token.', 400 );
126                }
127
128                $is_master_user = ! Jetpack::is_active();
129
130                Jetpack::update_user_token( $current_user_id, sprintf( '%s.%d', $token, $current_user_id ), $is_master_user );
131
132                if ( ! $is_master_user ) {
133                        Jetpack::state( 'message', 'linked' );
134                        // Don't activate anything since we are just connecting a user.
135                        return 'linked';
136                }
137
138                // If this site has been through the Jetpack Onboarding flow, delete the onboarding token
139                Jetpack::invalidate_onboarding_token();
140
141                // If redirect_uri is SSO, ensure SSO module is enabled
142                parse_str( parse_url( $data['redirect_uri'], PHP_URL_QUERY ), $redirect_options );
143
144                /** This filter is documented in class.jetpack-cli.php */
145                $jetpack_start_enable_sso = apply_filters( 'jetpack_start_enable_sso', true );
146
147                $activate_sso = (
148                        isset( $redirect_options['action'] ) &&
149                        'jetpack-sso' === $redirect_options['action'] &&
150                        $jetpack_start_enable_sso
151                );
152
153                $do_redirect_on_error = ( 'client' === $data['auth_type'] );
154
155                Jetpack::handle_post_authorization_actions( $activate_sso, $do_redirect_on_error );
156
157                return 'authorized';
158        }
159
160        public static function deactivate_plugin( $probable_file, $probable_title ) {
161                include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
162                if ( is_plugin_active( $probable_file ) ) {
163                        deactivate_plugins( $probable_file );
164                        return 1;
165                } else {
166                        // If the plugin is not in the usual place, try looking through all active plugins.
167                        $active_plugins = Jetpack::get_active_plugins();
168                        foreach ( $active_plugins as $plugin ) {
169                                $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
170                                if ( $data['Name'] == $probable_title ) {
171                                        deactivate_plugins( $plugin );
172                                        return 1;
173                                }
174                        }
175                }
176
177                return 0;
178        }
179
180        /**
181         * @return object|WP_Error
182         */
183        function get_token( $data ) {
184                $role = Jetpack::translate_current_user_to_role();
185
186                if ( ! $role ) {
187                        return new Jetpack_Error( 'role', __( 'An administrator for this blog must set up the Jetpack connection.', 'jetpack' ) );
188                }
189
190                $client_secret = Jetpack_Data::get_access_token();
191                if ( ! $client_secret ) {
192                        return new Jetpack_Error( 'client_secret', __( 'You need to register your Jetpack before connecting it.', 'jetpack' ) );
193                }
194
195                $redirect = isset( $data['redirect'] ) ? esc_url_raw( (string) $data['redirect'] ) : '';
196                $redirect_uri = ( 'calypso' === $data['auth_type'] )
197                        ? $data['redirect_uri']
198                        : add_query_arg( array(
199                                'action' => 'authorize',
200                                '_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ),
201                                'redirect' => $redirect ? urlencode( $redirect ) : false,
202                        ), menu_page_url( 'jetpack', false ) );
203
204                // inject identity for analytics
205                $tracks = new Automattic\Jetpack\Tracking();
206                $tracks_identity = $tracks->tracks_get_identity( get_current_user_id() );
207
208                $body = array(
209                        'client_id' => Jetpack_Options::get_option( 'id' ),
210                        'client_secret' => $client_secret->secret,
211                        'grant_type' => 'authorization_code',
212                        'code' => $data['code'],
213                        'redirect_uri' => $redirect_uri,
214                        '_ui' => $tracks_identity['_ui'],
215                        '_ut' => $tracks_identity['_ut'],
216                );
217
218                $args = array(
219                        'method' => 'POST',
220                        'body' => $body,
221                        'headers' => array(
222                                'Accept' => 'application/json',
223                        ),
224                );
225                $response = Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'token' ) ), $args );
226
227                if ( is_wp_error( $response ) ) {
228                        return new Jetpack_Error( 'token_http_request_failed', $response->get_error_message() );
229                }
230
231                $code = wp_remote_retrieve_response_code( $response );
232                $entity = wp_remote_retrieve_body( $response );
233
234                if ( $entity ) {
235                        $json = json_decode( $entity );
236                } else {
237                        $json = false;
238                }
239
240                if ( 200 != $code || ! empty( $json->error ) ) {
241                        if ( empty( $json->error ) ) {
242                                return new Jetpack_Error( 'unknown', '', $code );
243                        }
244
245                        $error_description = isset( $json->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $json->error_description ) : '';
246
247                        return new Jetpack_Error( (string) $json->error, $error_description, $code );
248                }
249
250                if ( empty( $json->access_token ) || ! is_scalar( $json->access_token ) ) {
251                        return new Jetpack_Error( 'access_token', '', $code );
252                }
253
254                if ( empty( $json->token_type ) || 'X_JETPACK' != strtoupper( $json->token_type ) ) {
255                        return new Jetpack_Error( 'token_type', '', $code );
256                }
257
258                if ( empty( $json->scope ) ) {
259                        return new Jetpack_Error( 'scope', 'No Scope', $code );
260                }
261
262                @list( $role, $hmac ) = explode( ':', $json->scope );
263                if ( empty( $role ) || empty( $hmac ) ) {
264                        return new Jetpack_Error( 'scope', 'Malformed Scope', $code );
265                }
266
267                if ( Jetpack::sign_role( $role ) !== $json->scope ) {
268                        return new Jetpack_Error( 'scope', 'Invalid Scope', $code );
269                }
270
271                if ( ! $cap = Jetpack::translate_role_to_cap( $role ) ) {
272                        return new Jetpack_Error( 'scope', 'No Cap', $code );
273                }
274
275                if ( ! current_user_can( $cap ) ) {
276                        return new Jetpack_Error( 'scope', 'current_user_cannot', $code );
277                }
278
279                /**
280                 * Fires after user has successfully received an auth token.
281                 *
282                 * @since 3.9.0
283                 */
284                do_action( 'jetpack_user_authorized' );
285
286                return (string) $json->access_token;
287        }
288
289        public function get_jetpack() {
290                return Jetpack::init();
291        }
292
293        public function do_exit() {
294                exit;
295        }
296}
Note: See TracBrowser for help on using the repository browser.