PluginProbe
WPO365 | MICROSOFT 365 GRAPH MAILER / 6.1
WPO365 | MICROSOFT 365 GRAPH MAILER v6.1
6.1 6.0 5.10 5.9 5.8 5.7 5.6 5.5 2.33 2.34 2.35 2.36 2.37 2.38 2.39 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 All 60 releases
wpo365-msgraphmailer / wpo365-msgraphmailer.php
wpo365-msgraphmailer.php
312 lines 13.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: WPO365 | MICROSOFT 365 GRAPH MAILER
4 * Plugin URI: https://wordpress.org/plugins/wpo365-msgraphmailer
5 * Description: WPO365 | MS GRAPH MAILER re-configures your WordPress website to send transactional emails from one of your Microsoft 365 Exchange Online / Mail enabled accounts using Microsoft Graph instead of - for example - using SMTP.
6 * Version: 6.1
7 * Author: marco@wpo365.com
8 * Author URI: https://www.wpo365.com
9 * License: GPL2+
10 */
11
12 namespace Wpo;
13
14 require __DIR__ . '/vendor/autoload.php';
15
16 use Wpo\Core\Globals;
17 use Wpo\Core\Permissions_Helpers;
18 use Wpo\Services\Dependency_Service;
19 use Wpo\Services\Options_Service;
20 use Wpo\Services\Request_Service;
21 use Wpo\Services\Router_Service;
22
23 // Prevent public access to this script
24 defined( 'ABSPATH' ) || die();
25
26 if ( ! class_exists( '\Wpo\MsGraphMailer' ) ) {
27
28 class MsGraphMailer {
29
30
31 /**
32 *
33 * @var \Wpo\Services\Dependency_Service
34 */
35 private $dependencies;
36
37 private $no_conflict = true;
38
39 public function __construct() {
40 $this->deactivation_hooks();
41 add_action( 'plugins_loaded', array( $this, 'load' ), 1 );
42 add_filter( 'cron_schedules', '\Wpo\Core\Cron_Helpers::add_cron_schedules', 10, 1 ); // phpcs:ignore
43 }
44
45 public function get_plugin_url() {
46 return plugin_dir_url( __FILE__ );
47 }
48
49 public function load() {
50 // If WPO365 | LOGIN exists and is active then do not initialize this plugin.
51 if ( \file_exists( dirname( __DIR__ ) . '/wpo365-login' ) ) {
52 include_once ABSPATH . 'wp-admin/includes/plugin.php';
53
54 if ( is_plugin_active( 'wpo365-login/wpo365-login.php' ) ) {
55 add_action( 'admin_notices', array( $this, 'ensure_wpo365_login' ), 10, 0 );
56 return;
57 }
58 }
59
60 Globals::set_global_vars( __FILE__, __DIR__ );
61 $this->cache_dependencies();
62 Options_Service::ensure_options_cache();
63 $this->update_request_log();
64 $this->add_wp_hooks();
65 Router_Service::has_route();
66 }
67
68 public function ensure_wpo365_login() {
69 echo '<div class="notice notice-error" style="margin-left: 2px;"><p>'
70 . 'The <strong>WPO365 | MS GRAPH MAILER</strong> plugin has detected that you have also installed the <strong>WPO365 | LOGIN</strong> plugin. '
71 . 'Since that plugin offers the same functionality <a href="https://www.wpo365.com/features/" target="_blank">plus a lot more</a> and uses the '
72 . 'same configuration-source, the <em>Microsoft Graph Mailer</em> of the <strong>WPO365 | LOGIN</strong> plugin will be used instead. '
73 . '<br><br>'
74 . 'See the <a href="https://docs.wpo365.com/article/141-send-email-using-microsoft-graph-mailer" target="_blank">online documentation</a> for details.'
75 . '</p></div>';
76 }
77
78 private function cache_dependencies() {
79 $this->dependencies = Dependency_Service::get_instance();
80 $this->dependencies->add( 'Request_Service', Request_Service::get_instance( true ) );
81 }
82
83 private function add_wp_hooks() {
84 // Plugin updater and license checker
85 add_filter( 'pre_set_site_transient_update_plugins', '\Wpo\Core\Plugin_Helpers::check_for_updates', 10, 1 );
86
87 // Do super admin stuff
88 if ( ( is_admin() || is_network_admin() ) && Permissions_Helpers::user_is_admin( \wp_get_current_user() ) ) {
89
90 // Add and hide wizard (page)
91 add_action( 'admin_menu', '\Wpo\Pages\Wizard_Page::add_management_page' );
92 add_action( 'network_admin_menu', '\Wpo\Pages\Wizard_Page::add_management_page' );
93
94 new \Wpo\Pages\License_Page();
95
96 // Show admin notification when WPO365 not properly configured
97 add_action( 'admin_notices', '\Wpo\Services\Notifications_Service::show_admin_notices', 10, 0 );
98 add_action( 'network_admin_notices', '\Wpo\Services\Notifications_Service::show_admin_notices', 10, 0 );
99 add_action( 'admin_init', '\Wpo\Services\Notifications_Service::dismiss_admin_notices', 10, 0 );
100
101 // Wire up AJAX backend services
102 add_action( 'wp_ajax_wpo365_delete_settings', '\Wpo\Services\Ajax_Service::delete_settings' );
103 add_action( 'wp_ajax_wpo365_delete_tokens', '\Wpo\Services\Ajax_Service::delete_tokens' );
104 add_action( 'wp_ajax_wpo365_get_settings', '\Wpo\Services\Ajax_Service::get_settings' );
105 add_action( 'wp_ajax_wpo365_update_settings', '\Wpo\Services\Ajax_Service::update_settings' );
106 add_action( 'wp_ajax_wpo365_get_log', '\Wpo\Services\Ajax_Service::get_log' );
107 add_action( 'wp_ajax_wpo365_dismiss_wpo_health_messages', '\Wpo\Services\Ajax_Service::dismiss_wpo_health_messages' );
108 add_action( 'wp_ajax_wpo365_get_wpo_health_messages', '\Wpo\Services\Ajax_Service::get_wpo_health_messages' );
109 add_action( 'wp_ajax_wpo365_get_parseable_options', '\Wpo\Services\Ajax_Service::get_parseable_options' );
110 add_action( 'wp_ajax_wpo365_get_insights_summary', '\Wpo\Services\Ajax_Service::get_insights_summary' );
111 add_action( 'wp_ajax_wpo365_get_insights', '\Wpo\Services\Ajax_Service::get_insights' );
112 add_action( 'wp_ajax_wpo365_truncate_insights_data', '\Wpo\Services\Ajax_Service::truncate_insights_data' );
113 add_action( 'wp_ajax_wpo365_send_test_alert', '\Wpo\Services\Ajax_Service::send_test_alert' );
114 add_action( 'wp_ajax_wpo365_obfuscate_sensitive_options', '\Wpo\Services\Ajax_Service::obfuscate_sensitive_options' );
115
116 // Graph mailer
117 add_action( 'wp_ajax_wpo365_send_test_mail', '\Wpo\Services\Ajax_Service::send_test_mail' );
118 add_action( 'wp_ajax_wpo365_get_mail_authorization_url', '\Wpo\Services\Ajax_Service::get_mail_authorization_url' );
119 add_action( 'wp_ajax_wpo365_get_mail_auth_configuration', '\Wpo\Services\Ajax_Service::get_mail_auth_configuration' );
120 add_action( 'wp_ajax_wpo365_try_migrate_mail_app_principal_info', '\Wpo\Services\Ajax_Service::try_migrate_mail_app_principal_info' );
121
122 // Graph mailer auditing
123 if ( class_exists( '\Wpo\Mail\Mail_Db' ) ) {
124 // Wire up AJAX backend services
125 add_action( 'wp_ajax_wpo365_get_mail_log', '\Wpo\Mail\Mail_Ajax_Service::get_mail_log' );
126 add_action( 'wp_ajax_wpo365_send_mail_again', '\Wpo\Mail\Mail_Ajax_Service::send_mail_again' );
127 add_action( 'wp_ajax_wpo365_truncate_mail_log', '\Wpo\Mail\Mail_Ajax_Service::truncate_mail_log' );
128
129 if ( method_exists( '\Wpo\Mail\Mail_Ajax_Service', 'mail_auto_retry' ) ) {
130 add_action( 'wp_ajax_wpo365_mail_auto_retry', '\Wpo\Mail\Mail_Ajax_Service::mail_auto_retry' );
131 }
132 }
133
134 // Show settings link
135 add_filter( ( is_network_admin() ? 'network_admin_' : '' ) . 'plugin_action_links_' . $GLOBALS['WPO_CONFIG']['plugin'], '\Wpo\Core\Plugin_Helpers::get_configuration_action_link', 10, 1 );
136
137 // Add license related messages to WP Admin
138 \Wpo\Core\Plugin_Helpers::show_license_notices();
139
140 // Ensure WP Cron job to check for each registered application whether its secret will epxire soon is added.
141
142 if ( class_exists( '\Wpo\Services\Password_Credentials_Service' ) ) {
143 \Wpo\Services\Password_Credentials_Service::ensure_check_password_credentials_expiration();
144 }
145
146 // Ensure WP Cron job to obtain a new mail refresh token once a day is added.
147 \Wpo\Mail\Mail_Authorization_Helpers::ensure_get_mail_refresh_token();
148
149 // To force WordPress to check for plugin updates if requested by an administrator
150 add_action( 'admin_post_wpo365_force_check_for_plugin_updates', '\Wpo\Core\Plugin_Helpers::force_check_for_plugin_updates' );
151 add_filter( 'plugin_row_meta', '\Wpo\Core\Plugin_Helpers::show_old_version_warning', 10, 2 );
152 add_filter( 'plugins_api', '\Wpo\Core\Plugin_Helpers::plugin_info', 20, 3 );
153
154 // Set up the dashboard widget.
155 add_action( 'wp_dashboard_setup', '\Wpo\Insights\Dashboard_Service::insights_widget' );
156 } // End of admin stuff
157
158 if ( Options_Service::get_global_boolean_var( 'insights_alerts_enabled' ) && class_exists( '\Wpo\Insights\Event_Notify_Service' ) ) {
159 add_action(
160 'wpo365/insights/notify',
161 function ( $message, $category = 'N/A', $recipient = '' ) {
162 $nofications = new \Wpo\Insights\Event_Notify_Service();
163 $nofications->notify( $message, $category, $recipient );
164 },
165 10,
166 3
167 );
168
169 add_action(
170 'wpo365_insights_check_failed_notifications',
171 function () {
172 $nofications = new \Wpo\Insights\Event_Notify_Service();
173 $nofications->check_failed_notifications();
174 }
175 );
176 }
177
178 // WP Cron job triggered action to check for each registered application whether its secret will epxire soon.
179 add_action( 'wpo_check_password_credentials_expiration', '\Wpo\Services\Password_Credentials_Service::check_password_credentials_expiration' );
180
181 // WP Cron job triggered action to obtain a new mail refresh token once a day.
182 add_action( 'wpo365_get_mail_refresh_token', '\Wpo\Mail\Mail_Authorization_Helpers::get_mail_refresh_token' );
183
184 // Clean up on shutdown
185 add_action( 'shutdown', '\Wpo\Services\Request_Service::shutdown', PHP_INT_MAX );
186
187 add_action( 'admin_enqueue_scripts', '\Wpo\Core\Script_Helpers::enqueue_wizard', 10, 0 );
188
189 // Replace phpmailer with Graph Mailer (but only if configured)
190 // According to https://developer.wordpress.org/reference/functions/wp_mail/ wp_mail is available after plugins_loaded
191 add_action( 'phpmailer_init', '\Wpo\Mail\Mailer::init', PHP_INT_MAX );
192 add_filter( 'wp_mail_from', '\Wpo\Mail\Mailer::mail_from', 10, 1 );
193
194 if ( Options_Service::get_global_boolean_var( 'mail_log', false ) && method_exists( '\Wpo\Mail\Mail_Db', 'add_mail_log' ) ) {
195 // Log each wp_mail in the wpo365_table
196 add_filter( 'wp_mail', '\Wpo\Mail\Mail_Db::add_mail_log', 10, 1 );
197 }
198
199 if ( Options_Service::get_global_boolean_var( 'mail_throttling_enabled' ) && method_exists( '\Wpo\Mail\Mail_Db', 'check_message_rate_limit' ) ) {
200 add_filter( 'wpo365/mail/before', '\Wpo\Mail\Mail_Db::check_message_rate_limit' );
201 }
202
203 if ( Options_Service::get_global_boolean_var( 'mail_auto_retry' ) && method_exists( '\Wpo\Mail\Mail_Db', 'process_unsent_messages' ) ) {
204 add_action( 'wpo_process_unsent_messages', '\Wpo\Mail\Mail_Db::process_unsent_messages' );
205 add_action(
206 'admin_init',
207 function () {
208 \Wpo\Mail\Mail_Db::ensure_unsent_messages( false );
209 }
210 );
211 }
212
213 // Add safe style css
214 add_filter( 'safe_style_css', '\Wpo\Core\WordPress_Helpers::safe_css', 10, 1 );
215
216 // Admin menu bar notifications
217 if ( Options_Service::get_global_boolean_var( 'mail_staging_mode', false ) && class_exists( '\Wpo\Mail\Mail_Notifications' ) ) {
218 add_action( 'admin_bar_menu', '\Wpo\Mail\Mail_Notifications::staging_mode_active', 100 );
219 add_action( 'wp_enqueue_scripts', '\Wpo\Core\Script_Helpers::add_admin_bar_styles' );
220 add_action( 'admin_enqueue_scripts', '\Wpo\Core\Script_Helpers::add_admin_bar_styles' );
221 }
222
223 // Update WPO365 extensions cache whenever a plugin is added or deleted
224 add_action( 'activated_plugin', '\Wpo\Core\Extensions_Helpers::plugin_activated', 10, 2 );
225 add_action( 'deactivated_plugin', '\Wpo\Core\Extensions_Helpers::plugin_deactivated', 10, 2 );
226
227 // Check again for updates after upgrader process completes to fix "Update available notice"
228 add_action( 'upgrader_process_complete', '\Wpo\Core\Extensions_Helpers::plugin_updated', 10, 2 );
229
230 // To collect Insights
231 if ( Options_Service::get_global_boolean_var( 'insights_enabled', false ) ) {
232 add_action( 'wpo365/mail/sent', '\Wpo\Insights\Event_Service::mail_sent__handler', 10, 1 );
233 add_action( 'wpo365/mail/sent/fail', '\Wpo\Insights\Event_Service::mail_sent_fail__handler', 10, 2 );
234 add_action( 'wpo365/alert/submitted', '\Wpo\Insights\Event_Service::notification_sent__handler', 10, 3 );
235 add_action( 'wpo365/alert/submitted/fail', '\Wpo\Insights\Event_Service::notification_sent_fail__handler', 10, 3 );
236 }
237
238 // To collect cURL logging
239 if ( Options_Service::get_global_boolean_var( 'curl_logging_enabled' ) ) {
240 add_action( 'http_api_curl', '\Wpo\Services\Log_Service::enable_curl_logging', 10, 3 );
241 }
242
243 // To disable ALPN for requests to Microsoft's login / Graph endpoints
244 // (option check happens inside the callback so a runtime option flip below takes effect immediately)
245 add_action( 'http_api_curl', '\Wpo\Core\Url_Helpers::disable_alpn_for_microsoft_hosts', 10, 3 );
246
247 // To auto-detect and self-heal the ALPN/PQ-TLS issue against Microsoft's SSO/token endpoints
248 add_filter( 'http_response', '\Wpo\Core\Url_Helpers::maybe_recover_from_microsoft_tls_404', 10, 3 );
249
250 // Customize script tag.
251 add_filter( 'script_loader_tag', '\Wpo\Core\Script_Helpers::custom_script_loading', 10, 3 );
252 }
253
254 private function update_request_log() {
255 $request_service = Request_Service::get_instance();
256 $request = $request_service->get_request( $GLOBALS['WPO_CONFIG']['request_id'] );
257 $request_log = $request->get_item( 'request_log' );
258 $request_log['debug_log'] = Options_Service::get_global_boolean_var( 'debug_log', false );
259 $request->set_item( 'request_log', $request_log );
260 }
261
262 private function deactivation_hooks() {
263 if ( \class_exists( '\Wpo\Mail\Mail_Db' ) ) {
264 // Delete possible cron jobs
265 register_deactivation_hook(
266 __FILE__,
267 function () {
268 wp_clear_scheduled_hook( 'wpo_process_unsent_messages' );
269 Options_Service::add_update_option( 'mail_auto_retry', false );
270 }
271 );
272 }
273
274 // Delete the mail refresh token cron job
275 register_deactivation_hook(
276 __FILE__,
277 function () {
278 wp_clear_scheduled_hook( 'wpo365_get_mail_refresh_token' );
279 delete_site_transient( 'wpo365_get_mail_refresh_token_hook_ensured' );
280 }
281 );
282
283 register_deactivation_hook(
284 __FILE__,
285 function () {
286 global $wpdb;
287
288 $wpdb->query( // phpcs:ignore
289 $wpdb->prepare(
290 'DELETE FROM %i WHERE `option_name` LIKE %s AND `option_name` != %s AND `option_name` != %s',
291 $wpdb->options,
292 '%wpo365%',
293 'wpo365_options',
294 'wpo365_mail_authorization'
295 )
296 );
297
298 $wpdb->query( // phpcs:ignore
299 $wpdb->prepare(
300 'DELETE FROM %i WHERE `option_name` LIKE %s',
301 $wpdb->options,
302 'wpo_app_only_access_tokens'
303 )
304 );
305 }
306 );
307 }
308 }
309 }
310
311 $wpo365_msgraphmailer = new MsGraphMailer();
312