PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.4.0
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.4.0
1.7.7 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 All 33 releases
image-optimization / modules / connect / classes / service.php

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

256 lines 6.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
47 return $client_id;
48 }
49
50 /**
51 * Deactivate license
52 *
53 * @return void
54 * @throws Service_Exception
55 */
56 public static function deactivate_license(): void {
57 $client_id = Data::get_client_id();
58
59 if ( ! $client_id ) {
60 throw new Service_Exception( 'Missing client ID' );
61 }
62
63 $deactivation_url = Utils::get_deactivation_url( $client_id );
64
65 if ( ! $deactivation_url ) {
66 throw new Service_Exception( 'Missing deactivation URL' );
67 }
68
69 $access_token = Data::get_access_token();
70
71 if ( ! $access_token ) {
72 throw new Service_Exception( 'Missing access token' );
73 }
74
75 $refresh_token = Data::get_refresh_token();
76
77 if ( ! $refresh_token ) {
78 throw new Service_Exception( 'Missing refresh token' );
79 }
80
81 self::request( $deactivation_url, [
82 'method' => 'DELETE',
83 'headers' => [
84 'Authorization' => "Bearer {$access_token}",
85 ],
86 ], 204 );
87
88 self::get_token( 'refresh_token', $refresh_token );
89 }
90
91 /**
92 * disconnect
93 *
94 * @return void
95 * @throws Service_Exception
96 */
97 public static function disconnect(): void {
98 $sessions_url = Utils::get_sessions_url();
99
100 if ( ! $sessions_url ) {
101 throw new Service_Exception( 'Missing sessions URL' );
102 }
103
104 $access_token = Data::get_access_token();
105
106 if ( ! $access_token ) {
107 throw new Service_Exception( 'Missing access token' );
108 }
109
110 self::request( $sessions_url, [
111 'method' => 'DELETE',
112 'headers' => [
113 'Content-Type' => 'application/json',
114 'Authorization' => "Bearer {$access_token}",
115 ],
116 ], 204 );
117
118 Data::clear_session();
119 }
120
121 /**
122 * Get token & optionally save to user
123 *
124 * @param string $grant_type
125 *
126 * @param string|null $credential
127 *
128 * @return array
129 * @throws Service_Exception
130 */
131 public static function get_token( string $grant_type, ?string $credential = null ): array {
132 $token_url = Utils::get_token_url();
133
134 if ( ! $token_url ) {
135 throw new Service_Exception( 'Missing token URL' );
136 }
137
138 $client_id = Data::get_client_id();
139 $client_secret = Data::get_client_secret();
140
141 if ( empty( $client_id ) || empty( $client_secret ) ) {
142 throw new Service_Exception( 'Missing client ID or secret' );
143 }
144
145 $body = [
146 'grant_type' => $grant_type,
147 'redirect_uri' => Utils::get_redirect_uri(),
148 ];
149
150 switch ( $grant_type ) {
151 case GrantTypes::AUTHORIZATION_CODE:
152 $body['code'] = $credential;
153 break;
154 case GrantTypes::REFRESH_TOKEN:
155 $body[ GrantTypes::REFRESH_TOKEN ] = $credential;
156 break;
157 case GrantTypes::CLIENT_CREDENTIALS:
158 // nothing to do
159 break;
160 default:
161 throw new Service_Exception( 'Invalid grant type' );
162 }
163
164 $data = self::request( $token_url, [
165 'method' => 'POST',
166 'headers' => [
167 'x-elementor-apps' => Config::APP_NAME,
168 'Authorization' => 'Basic ' . base64_encode( "{$client_id}:{$client_secret}" ),
169 ],
170 'body' => $body,
171 ] );
172
173 Data::set_connect_mode_data( Data::TOKEN_ID, $data['id_token'] ?? null );
174 Data::set_connect_mode_data( Data::ACCESS_TOKEN, $data['access_token'] ?? null );
175 Data::set_connect_mode_data( Data::REFRESH_TOKEN, $data['refresh_token'] ?? null );
176 Data::set_connect_mode_data( Data::OPTION_OWNER_USER_ID, get_current_user_id() ?? null );
177
178 return $data;
179 }
180
181 public static function jwt_decode( $payload ): string {
182 static $jwks = null;
183
184 $jwks_url = Utils::get_jwks_url();
185 if ( ! $jwks_url ) {
186 return __( 'Missing JWKS URL' );
187 }
188
189 if ( ! $jwks ) {
190 $jwks = self::request( $jwks_url, [
191 'method' => 'GET',
192 ] );
193 }
194 if ( ! class_exists( 'JWT' ) ) {
195 require_once IMAGE_OPTIMIZATION_PATH . 'vendor/autoload.php';
196 }
197
198 try {
199 $decoded = \Firebase\JWT\JWT::decode( $payload, \Firebase\JWT\JWK::parseKeySet( $jwks ) );
200 return json_encode( $decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
201 } catch ( \Throwable $th ) {
202 if ( $th instanceof \Firebase\JWT\ExpiredException ) {
203 self::get_token( GrantTypes::REFRESH_TOKEN, Data::get_refresh_token() );
204 return self::jwt_decode( $payload );
205 }
206 return $th->getMessage();
207 }
208 }
209
210 /**
211 * @param string $url
212 * @param array $args
213 * @param int $valid_response_code
214 *
215 * @return array|null
216 */
217 public static function request( string $url, array $args, int $valid_response_code = 200 ): ?array {
218 $args['timeout'] = 30;
219
220 $response = wp_remote_request( $url, $args );
221
222 if ( is_wp_error( $response ) ) {
223 error_log( '[Connect Service]: ' . $response->get_error_message() );
224 throw new Service_Exception( $response->get_error_message() );
225 }
226
227 if ( $valid_response_code !== wp_remote_retrieve_response_code( $response ) ) {
228 error_log( '[Connect Service]: invalid status code' . wp_remote_retrieve_response_code( $response ) );
229 throw new Service_Exception( wp_remote_retrieve_body( $response ) );
230 }
231
232 return json_decode( wp_remote_retrieve_body( $response ), true );
233 }
234
235 public static function refresh_token() {
236 $lock_key = Config::APP_NAME . self::REFRESH_TOKEN_LOCK;
237 $last_token = Data::fetch_option( $lock_key, '' );
238
239 $current_refresh_token = Data::get_refresh_token();
240
241 if ( ! empty( $last_token ) && $last_token === $current_refresh_token ) {
242 sleep( 1 );
243 return;
244 }
245
246 delete_option( $lock_key );
247 $locked = Data::insert_option_uniquely( $lock_key, $current_refresh_token );
248 if ( ! $locked ) {
249 sleep( 1 );
250 return;
251 }
252
253 self::get_token( GrantTypes::REFRESH_TOKEN, $current_refresh_token );
254 }
255 }
256