PluginProbe
Image Optimization – Compress Images and Convert to WebP or AVIF / 1.6.6
Image Optimization – Compress Images and Convert to WebP or AVIF v1.6.6
1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 All 32 releases
image-optimization / modules / connect / classes / service.php

service.php in Image Optimization – Compress Images and Convert to WebP or AVIF 1.6.6, at modules/connect/classes/service.php

298 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImageOptimization\Modules\Connect\Classes;
4
5 use ImageOptimization\Modules\Connect\Classes\Exceptions\Service_Exception;
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit; // Exit if accessed directly
9 }
10
11 /**
12 * Class Service
13 */
14 class Service {
15 const REFRESH_TOKEN_LOCK = '_connect_refresh_token';
16
17 /**
18 * Registers new client and returns client ID
19 *
20 * @return string
21 * @throws Service_Exception
22 */
23 public static function register_client(): string {
24 $clients_url = Utils::get_clients_url();
25
26 if ( ! $clients_url ) {
27 throw new Service_Exception( 'Missing client registration URL' );
28 }
29
30 $client_data = self::request( $clients_url, [
31 'method' => 'POST',
32 'headers' => [
33 'Content-Type' => 'application/json',
34 ],
35 'body' => wp_json_encode( [
36 'redirect_uri' => Utils::get_redirect_uri(),
37 'app_type' => Config::APP_TYPE,
38 ] ),
39 ], 201 );
40
41 $client_id = $client_data['client_id'] ?? null;
42 $client_secret = $client_data['client_secret'] ?? null;
43
44 Data::set_client_id( $client_id );
45 Data::set_client_secret( $client_secret );
46 Data::set_home_url();
47
48 return $client_id;
49 }
50
51 /**
52 * Deactivate license
53 *
54 * @return void
55 * @throws Service_Exception
56 */
57 public static function deactivate_license(): void {
58 $client_id = Data::get_client_id();
59
60 if ( ! $client_id ) {
61 throw new Service_Exception( 'Missing client ID' );
62 }
63
64 $deactivation_url = Utils::get_deactivation_url( $client_id );
65
66 if ( ! $deactivation_url ) {
67 throw new Service_Exception( 'Missing deactivation URL' );
68 }
69
70 $access_token = Data::get_access_token();
71
72 if ( ! $access_token ) {
73 throw new Service_Exception( 'Missing access token' );
74 }
75
76 $refresh_token = Data::get_refresh_token();
77
78 if ( ! $refresh_token ) {
79 throw new Service_Exception( 'Missing refresh token' );
80 }
81
82 self::request( $deactivation_url, [
83 'method' => 'DELETE',
84 'headers' => [
85 'Authorization' => "Bearer {$access_token}",
86 ],
87 ], 204 );
88
89 self::get_token( 'refresh_token', $refresh_token );
90 }
91
92 /**
93 * disconnect
94 *
95 * @return void
96 * @throws Service_Exception
97 */
98 public static function disconnect(): void {
99 $sessions_url = Utils::get_sessions_url();
100
101 if ( ! $sessions_url ) {
102 throw new Service_Exception( 'Missing sessions URL' );
103 }
104
105 $access_token = Data::get_access_token();
106
107 if ( ! $access_token ) {
108 throw new Service_Exception( 'Missing access token' );
109 }
110
111 self::request( $sessions_url, [
112 'method' => 'DELETE',
113 'headers' => [
114 'Content-Type' => 'application/json',
115 'Authorization' => "Bearer {$access_token}",
116 ],
117 ], 204 );
118
119 Data::clear_session();
120 }
121
122 /**
123 * Get token & optionally save to user
124 *
125 * @param string $grant_type
126 *
127 * @param string|null $credential
128 *
129 * @return array
130 * @throws Service_Exception
131 */
132 public static function get_token( string $grant_type, ?string $credential = null, ?bool $update = true ): array {
133 $token_url = Utils::get_token_url();
134
135 if ( ! $token_url ) {
136 throw new Service_Exception( 'Missing token URL' );
137 }
138
139 $client_id = Data::get_client_id();
140 $client_secret = Data::get_client_secret();
141
142 if ( empty( $client_id ) || empty( $client_secret ) ) {
143 throw new Service_Exception( 'Missing client ID or secret' );
144 }
145
146 $body = [
147 'grant_type' => $grant_type,
148 'redirect_uri' => Utils::get_redirect_uri(),
149 ];
150
151 switch ( $grant_type ) {
152 case GrantTypes::AUTHORIZATION_CODE:
153 $body['code'] = $credential;
154 break;
155 case GrantTypes::REFRESH_TOKEN:
156 $body[ GrantTypes::REFRESH_TOKEN ] = $credential;
157 break;
158 case GrantTypes::CLIENT_CREDENTIALS:
159 $body['redirect_uri'] = Utils::get_redirect_uri( Data::get_home_url() );
160
161 break;
162 default:
163 throw new Service_Exception( 'Invalid grant type' );
164 }
165
166 $data = self::request( $token_url, [
167 'method' => 'POST',
168 'headers' => [
169 'x-elementor-apps' => Config::APP_NAME,
170 'Authorization' => 'Basic ' . base64_encode( "{$client_id}:{$client_secret}" ),
171 ],
172 'body' => $body,
173 ] );
174
175 if ( $update ) {
176 Data::set_connect_mode_data( Data::TOKEN_ID, $data['id_token'] ?? null );
177 Data::set_connect_mode_data( Data::ACCESS_TOKEN, $data['access_token'] ?? null );
178 Data::set_connect_mode_data( Data::REFRESH_TOKEN, $data['refresh_token'] ?? null );
179 Data::set_connect_mode_data( Data::OPTION_OWNER_USER_ID, get_current_user_id() );
180 }
181
182 return $data;
183 }
184
185 public static function jwt_decode( $payload ): string {
186 static $jwks = null;
187
188 $jwks_url = Utils::get_jwks_url();
189 if ( ! $jwks_url ) {
190 return __( 'Missing JWKS URL' );
191 }
192
193 if ( ! $jwks ) {
194 $jwks = self::request( $jwks_url, [
195 'method' => 'GET',
196 ] );
197 }
198 if ( ! class_exists( 'JWT' ) ) {
199 require_once IMAGE_OPTIMIZATION_PATH . 'vendor/autoload.php';
200 }
201
202 try {
203 $decoded = \Firebase\JWT\JWT::decode( $payload, \Firebase\JWT\JWK::parseKeySet( $jwks ) );
204 return json_encode( $decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
205 } catch ( \Throwable $th ) {
206 if ( $th instanceof \Firebase\JWT\ExpiredException ) {
207 self::get_token( GrantTypes::REFRESH_TOKEN, Data::get_refresh_token() );
208 return self::jwt_decode( $payload );
209 }
210 return $th->getMessage();
211 }
212 }
213
214 /**
215 * @param string $url
216 * @param array $args
217 * @param int $valid_response_code
218 *
219 * @return array|null
220 * @throws Service_Exception
221 */
222 public static function request( string $url, array $args, int $valid_response_code = 200 ): ?array {
223 $args['timeout'] = 30;
224
225 $response = wp_remote_request( $url, $args );
226
227 if ( is_wp_error( $response ) ) {
228 error_log( '[Connect Service]: ' . $response->get_error_message() );
229 throw new Service_Exception( $response->get_error_message() );
230 }
231
232 if ( $valid_response_code !== wp_remote_retrieve_response_code( $response ) ) {
233 error_log( '[Connect Service]: invalid status code' . wp_remote_retrieve_response_code( $response ) );
234 throw new Service_Exception( wp_remote_retrieve_body( $response ) );
235 }
236
237 return json_decode( wp_remote_retrieve_body( $response ), true );
238 }
239
240 public static function refresh_token() {
241 $lock_key = Config::APP_NAME . self::REFRESH_TOKEN_LOCK;
242 $last_token = Data::fetch_option( $lock_key, '' );
243
244 $current_refresh_token = Data::get_refresh_token();
245
246 if ( ! empty( $last_token ) && $last_token === $current_refresh_token ) {
247 sleep( 1 );
248 delete_option( $lock_key );
249 return;
250 }
251
252 delete_option( $lock_key );
253 $locked = Data::insert_option_uniquely( $lock_key, $current_refresh_token );
254 if ( ! $locked ) {
255 sleep( 1 );
256 delete_option( $lock_key );
257 return;
258 }
259
260 self::get_token( GrantTypes::REFRESH_TOKEN, $current_refresh_token );
261 delete_option( $lock_key );
262 }
263
264 /**
265 * @throws Service_Exception
266 */
267 public static function update_redirect_uri(): void {
268 $client_id = Data::get_client_id();
269
270 if ( ! $client_id ) {
271 throw new Service_Exception( 'Missing client ID' );
272 }
273
274 $client_patch_url = Utils::get_clients_patch_url( $client_id );
275
276 [ 'access_token' => $access_token ] = self::get_token(
277 GrantTypes::CLIENT_CREDENTIALS,
278 null,
279 false
280 );
281
282 self::request( $client_patch_url, [
283 'method' => 'PATCH',
284 'headers' => [
285 'Content-Type' => 'application/json',
286 'Authorization' => "Bearer {$access_token}",
287 ],
288 'body' => json_encode( [
289 'redirect_uri' => Utils::get_redirect_uri(),
290 ] ),
291 ] );
292
293 self::refresh_token();
294
295 Data::set_home_url();
296 }
297 }
298