PluginProbe ʕ •ᴥ•ʔ
Check & Log Email – Easy Email Testing & Mail logging / 2.0.13
Check & Log Email – Easy Email Testing & Mail logging v2.0.13
1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 2.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.13.1 2.0.13.2 2.0.14 2.0.2 2.0.3 2.0.4 2.0.5 2.0.5.1 2.0.6 2.0.7 2.0.8 2.0.9 trunk 0.5.7 0.6.0 0.6.1 0.6.2 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.12.1 1.0.13 1.0.13.1 1.0.2 1.0.3
check-email / include / Core / Auth.php
check-email / include / Core Last commit date
DB 2 months ago Request 2 months ago UI 2 months ago Auth.php 2 months ago Check_Email_Admin_Capability_Giver.php 2 months ago Check_Email_Export_Log.php 2 months ago Check_Email_From_Handler.php 2 months ago Check_Email_Log.php 2 months ago Check_Email_Logger.php 2 months ago Check_Email_Multisite.php 2 months ago Check_Email_Review.php 2 months ago Loadie.php 2 months ago
Auth.php
515 lines
1 <?php
2
3
4 namespace CheckEmail\Core;
5 // Exit if accessed directly
6 if( !defined( 'ABSPATH' ) )
7 exit;
8 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
9 $check_email = wpchill_check_email();
10 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
11 $plugin_path = plugin_dir_path($check_email->get_plugin_file());
12 require_once $plugin_path . '/vendor/autoload.php';
13
14 use Exception;
15 use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
16 use League\OAuth2\Client\Provider\GenericProvider;
17 use League\OAuth2\Client\Token\AccessToken;
18 use League\OAuth2\Client\Token\AccessTokenInterface;
19
20 class Auth
21 {
22
23 /**
24 * Scopes that we need to send emails.
25 *
26 * @since 1.5.0
27 */
28 const SCOPES = [
29 'https://graph.microsoft.com/mail.send',
30 'https://graph.microsoft.com/mail.send.shared',
31 'https://graph.microsoft.com/mail.readwrite',
32 'https://graph.microsoft.com/user.read',
33 'offline_access',
34 ];
35 public $mailer = null;
36 public $options = [];
37 public $client = null;
38
39
40 public function __construct($mailer_type = null)
41 {
42 $this->mailer = $mailer_type;
43 $this->options = $this->get_mailer_option();
44 $this->get_client();
45 }
46
47
48 public function get_mailer_option()
49 {
50 $smtp_options = get_site_option('check-email-log-global-smtp');
51 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
52 return get_site_option('check-email-log-' . $this->mailer . '-options');
53 } else {
54 return get_option('check-email-log-' . $this->mailer . '-options');
55 }
56 }
57 public function update_mailer_option($options_to_update)
58 {
59
60 $smtp_options = get_site_option('check-email-log-global-smtp');
61 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
62 $site_option = get_site_option('check-email-log-' . $this->mailer . '-options');
63 $mailer_options = array_merge((array)$site_option, (array)$options_to_update);
64 update_site_option('check-email-log-' . $this->mailer . '-options', $mailer_options);
65 } else {
66 $site_option = empty(get_option('check-email-log-' . $this->mailer . '-options')) ? [] : get_option('check-email-log-' . $this->mailer . '-options');
67 $mailer_options = array_merge((array)$site_option, (array)$options_to_update);
68 update_option('check-email-log-' . $this->mailer . '-options', $mailer_options);
69 }
70 $this->options = $this->get_mailer_option();
71 }
72 public function get_client() {
73
74 // Doesn't load client twice + gives ability to overwrite.
75 if (! empty($this->client)) {
76 return $this->client;
77 }
78
79 $authorize_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
80
81
82 $access_token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
83
84
85 $resource_owner_details_url = 'https://graph.microsoft.com/v1.0/me';
86 if (! isset($this->options['client_id']) && ! isset($this->options['client_secret'])) {
87 return null;
88 }
89
90 $this->client = new GenericProvider(
91 // $provider = new GenericProvider(
92 [
93 'clientId' => base64_decode($this->options['client_id']),
94 'clientSecret' => base64_decode($this->options['client_secret']),
95 'redirectUri' => self::get_plugin_auth_url(),
96 'urlAuthorize' => $authorize_url,
97 'urlAccessToken' => $access_token_url,
98 'urlResourceOwnerDetails' => $resource_owner_details_url,
99 'scopes' => 'openid profile User.Read Mail.Read Mail.Send',
100 'scopeSeparator' => ' ',
101 ]
102 );
103
104
105 // Do not process if we don't have both App ID & Password.
106 if (! $this->is_clients_saved()) {
107 return $this->client;
108 }
109
110 if (! empty($this->options['access_token'])) {
111 $access_token = new AccessToken((array) $this->options['access_token']);
112 }
113
114 // We don't have tokens but have auth code.
115 if (
116 $this->is_auth_required() &&
117 ! empty($this->options['auth_code'])
118 ) {
119
120 // Try to get an access token using the authorization code grant.
121 $this->obtain_access_token();
122 } else { // We have tokens.
123
124 // Update the old token if needed.
125 if (! empty($access_token) && $access_token->hasExpired()) {
126 $this->refresh_access_token($access_token);
127 }
128 }
129
130 return $this->client;
131 }
132
133 /**
134 * Try to get an access token using the authorization code grant.
135 *
136 * @since 3.4.0
137 */
138 public function obtain_access_token() {
139
140 if (empty($this->options['auth_code'])) {
141 return;
142 }
143
144 try {
145 $access_token = $this->client->getAccessToken(
146 'authorization_code',
147 ['code' => $this->options['auth_code']]
148 );
149
150 $this->update_access_token($access_token->jsonSerialize());
151 // $this->update_refresh_token( $access_token->getRefreshToken() );
152 $this->update_user_details($access_token);
153 // $this->update_scopes( $this->get_scopes() );
154
155 // Reset Auth code. It's valid for 5 minutes anyway.
156 $this->update_auth_code('');
157
158 // Debug::clear();
159 } catch (IdentityProviderException $e) {
160 $response = $e->getResponseBody();
161
162 // error_log(print_r($response, true));
163
164
165 $this->update_auth_code('');
166 } catch (Exception $e) { // Catch any other general exceptions just in case.
167 // error_log(print_r($e->getMessage(), true));
168 $this->update_auth_code('');
169 }
170 }
171
172 private function refresh_access_token($access_token)
173 {
174 try {
175 $new_access_token = $this->client->getAccessToken(
176 'refresh_token',
177 ['refresh_token' => $access_token->getRefreshToken()]
178 );
179
180 $this->update_access_token($new_access_token->jsonSerialize());
181 $this->update_refresh_token($new_access_token->getRefreshToken());
182 $this->update_user_details($new_access_token);
183 } catch (IdentityProviderException $e) {
184 $response = $e->getResponseBody();
185
186
187 } catch (Exception $e) { // Catch any other general exception just in case.
188
189 // $e->getMessage()
190 }
191 }
192
193
194 public static function get_plugin_auth_url()
195 {
196 $smtp_options = get_site_option('check-email-log-global-smtp');
197 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
198 return network_admin_url();
199 } else {
200 return admin_url();
201 }
202 }
203
204
205 public function process_auth($code)
206 {
207
208 $this->update_auth_code($code);
209
210 // Remove old errors.
211 Debug::clear();
212
213 // Retrieve the token and user details, save errors if any.
214 $this->get_client();
215 }
216
217
218 public function get_auth_url() {
219 $client = $this->get_client();
220 if (
221 ! empty($client) &&
222 class_exists('\League\OAuth2\Client\Provider\GenericProvider', false) &&
223 $client instanceof GenericProvider
224 ) {
225 $url_options = [
226 'state' => $this->get_state(),
227 'scope' => $this->get_scopes(),
228 ];
229
230 $auth_url = $client->getAuthorizationUrl($url_options);
231
232 return $auth_url;
233 }
234
235 return '#';
236 }
237
238 /**
239 * Get auth scopes.
240 *
241 * @since 2.8.0
242 *
243 * @return array
244 */
245 protected function get_scopes()
246 {
247
248 return self::SCOPES;
249 }
250
251
252 public function update_user_details($access_token)
253 {
254 $user = [
255 'display_name' => '',
256 'email' => '',
257 ];
258
259 try {
260 $resource_owner = $this->get_client()->getResourceOwner($access_token);
261 $resource_data = $resource_owner->toArray();
262
263 $user = [
264 'display_name' => $resource_data['displayName'],
265 'email' => $resource_data['userPrincipalName'],
266 ];
267 } catch (IdentityProviderException $e) {
268 $response = $e->getResponseBody();
269
270
271 // Reset Auth code. It's valid for 5 minutes anyway.
272 $this->update_auth_code( '' );
273 } catch (Exception $e) {
274 return $e->getMessage();
275 // Catch general any other exception just in case.
276 // Debug::set(
277 // 'Mailer: Outlook (requesting user details)' . WP::EOL .
278 // $e->getMessage()
279 // );
280 }
281
282
283 $site_option['user_details'] = $user;
284
285 $this->update_mailer_option($site_option);
286 }
287
288
289 protected function get_state()
290 {
291 return 'check-email-nonce_'.wp_create_nonce('ck_mail_outlook_check_nonce');
292 }
293
294 public function is_clients_saved()
295 {
296 return ! empty($this->options['client_id']) && ! empty($this->options['client_secret']);
297 }
298
299 public function is_auth_required()
300 {
301 return empty($this->options['access_token']);
302 }
303 public function update_access_token($access_token)
304 {
305 $smtp_options = get_site_option('check-email-log-global-smtp');
306 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
307 $site_option = get_site_option('check-email-log-' . $this->mailer . '-options');
308 $site_option['access_token'] = $access_token;
309 update_site_option('check-email-log-' . $this->mailer . '-options', $site_option);
310 } else {
311 $site_option = get_option('check-email-log-' . $this->mailer . '-options');
312 $site_option['access_token'] = $access_token;
313 update_option('check-email-log-' . $this->mailer . '-options', $site_option);
314 }
315 $this->options = $this->get_mailer_option();
316 }
317
318 public function update_refresh_token($access_token)
319 {
320 $smtp_options = get_site_option('check-email-log-global-smtp');
321 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
322 $site_option = get_site_option('check-email-log-' . $this->mailer . '-options');
323 $site_option['refresh_token'] = $access_token;
324 update_site_option('check-email-log-' . $this->mailer . '-options', $site_option);
325 } else {
326 $site_option = get_option('check-email-log-' . $this->mailer . '-options');
327 $site_option['refresh_token'] = $access_token;
328 update_option('check-email-log-' . $this->mailer . '-options', $site_option);
329 }
330 $this->options = $this->get_mailer_option();
331 }
332
333 public function update_auth_code($code) {
334 $smtp_options = get_site_option('check-email-log-global-smtp');
335 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
336 $site_option = get_site_option('check-email-log-' . $this->mailer . '-options');
337 $site_option['auth_code'] = $code;
338 update_site_option('check-email-log-' . $this->mailer . '-options', $site_option);
339 } else {
340 $site_option = get_option('check-email-log-' . $this->mailer . '-options');
341 $site_option['auth_code'] = $code;
342 update_option('check-email-log-' . $this->mailer . '-options', $site_option);
343 }
344 $this->options = $this->get_mailer_option();
345
346 // We don't have tokens but have auth code.
347 if ($this->is_auth_required() && ! empty($this->options['auth_code'])) {
348 // Try to get an access token using the authorization code grant.
349 $this->obtain_access_token();
350 }
351 }
352
353 function sendEmailByMailer($from_email, $to_email, $subject, $body) {
354
355 // Get the access token from options
356 $access_token_array = $this->options['access_token'];
357 $access_token = $access_token_array['access_token'];
358
359 // Graph API URL for sending mail
360 $url = "https://graph.microsoft.com/v1.0/me/sendMail";
361
362 // Email message structure
363 $message = [
364 "message" => [
365 "subject" => $subject,
366 "body" => [
367 "contentType" => "HTML",
368 "content" => $body,
369 ],
370 "toRecipients" => [
371 [
372 "emailAddress" => [
373 "address" => $to_email,
374 ],
375 ],
376 ],
377 ],
378 "saveToSentItems" => "true", // Save a copy to Sent Items folder
379 ];
380
381 // Request arguments
382 $args = [
383 'headers' => [
384 "Authorization" => "Bearer $access_token", // Authorization header
385 'Content-Type' => 'application/json', // JSON content type
386 ],
387 'body' => wp_json_encode($message), // JSON encode the message
388 'timeout' => 45, // Optional timeout, increase if necessary
389 'sslverify' => true, // Verify SSL (set to false only if you're sure)
390 ];
391
392 // Make the API request using wp_remote_post
393 $response = wp_remote_post($url, $args);
394
395 // Check for errors in the response
396 if (is_wp_error($response)) {
397 return [
398 'error' => 1,
399 'message' => $response->get_error_message(), // Return the error message
400 ];
401 }
402
403 // Optional: Check the email log and forward if necessary
404 $setting_options = get_option('check-email-log-core');
405 if (isset($setting_options['forward_email']) && !empty($setting_options['forward_email'])) {
406 $this->forward_email_by_mailer($to_email, $subject, $body);
407 }
408
409 // If everything is fine, return success
410 return [
411 'error' => 0,
412 'message' => "", // Empty message means no errors
413 ];
414 }
415
416
417 function forward_email_by_mailer($to_email, $subject, $body) {
418 // Get the access token
419 $access_token_array = $this->options['access_token'];
420 $access_token = $access_token_array['access_token'];
421
422
423 // Graph API URL
424 $url = "https://graph.microsoft.com/v1.0/me/sendMail";
425 $toRecipients = [];
426 $ccRecipients = [];
427 $bccRecipients = [];
428 if (isset($setting_options['forward_email']) && !empty($setting_options['forward_email'])) {
429 if (isset($setting_options['forward_to']) && !empty($setting_options['forward_to'])) {
430 $to_email = explode(',', $setting_options['forward_to']);
431
432
433 foreach ((array) $to_email as $email) {
434 $toRecipients[] = [
435 "emailAddress" => [
436 "address" => $email,
437 ],
438 ];
439 }
440 }
441
442
443 if (isset($setting_options['forward_cc']) && !empty($setting_options['forward_cc'])) {
444 $copy_to = explode(',', $setting_options['forward_cc']);
445 foreach ((array) $copy_to as $email) {
446 $ccRecipients[] = [
447 "emailAddress" => [
448 "address" => $email,
449 ],
450 ];
451 }
452 }
453
454 if (isset($setting_options['forward_bcc']) && !empty($setting_options['forward_bcc'])) {
455 $bcc_to = explode(',', $setting_options['forward_bcc']);
456 foreach ((array) $bcc_to as $email) {
457 $bccRecipients[] = [
458 "emailAddress" => [
459 "address" => $email,
460 ],
461 ];
462 }
463 }
464 }
465
466 $message = [
467 "message" => [
468 "subject" => $subject,
469 "body" => [
470 "contentType" => "HTML",
471 "content" => $body,
472 ],
473 "toRecipients" => $toRecipients,
474 "ccRecipients" => $ccRecipients,
475 "bccRecipients" => $bccRecipients,
476 ],
477 "saveToSentItems" => "true",
478 ];
479
480 // Arguments for the request
481 $args = [
482 'headers' => [
483 "Authorization" => "Bearer $access_token",
484 'Content-Type' => 'application/json',
485 ],
486 'body' => wp_json_encode($message),
487 ];
488
489 $response = wp_remote_post($url, $args);
490
491 // Check for errors
492 if (is_wp_error($response)) {
493 return [
494 'error' => 1,
495 'message' => $response->get_error_message(),
496 ];
497 }
498
499 return [
500 'error' => 0,
501 'message' => "",
502 ];
503 }
504
505 public function delete_outlook_options() {
506 $smtp_options = get_site_option('check-email-log-global-smtp');
507 if (isset($smtp_options['enable_global']) && ! empty($smtp_options['enable_global']) && is_multisite()) {
508 delete_site_option('check-email-log-' . $this->mailer . '-options');
509 } else {
510 delete_option('check-email-log-' . $this->mailer . '-options');
511 }
512 $this->options = $this->get_mailer_option();
513 }
514 }
515