PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | includes/class-metasync-connect-manager.php +26 -38 2.7.0 → 2.7.1 View file →
@@ -88,9 +88,9 @@
88 88 $general_options = Metasync::get_option('general') ?? [];
89 89 $plugin_auth_token = $general_options['apikey'] ?? '';
90 90
91 91 if (empty($plugin_auth_token)) {
92 - error_log('MetaSync ERROR: Plugin Auth Token missing from options - should have been generated during activation');
92 + error_log('MetaSync ERROR: Plugin Auth Token missing from options - should have been generated during activation'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production
93 93 return false;
94 94 }
95 95
96 96 return $plugin_auth_token;
@@ -188,9 +188,9 @@
188 188 wp_send_json_error(array('message' => 'Failed to save new token'));
189 189 }
190 190
191 191 } catch (Exception $e) {
192 - error_log('Plugin Auth Token Refresh Error: ' . $e->getMessage());
192 + error_log('Plugin Auth Token Refresh Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
193 193 wp_send_json_error(array('message' => 'Error generating new token'));
194 194 }
195 195 }
196 196
@@ -222,9 +222,9 @@
222 222 wp_send_json_error(array('message' => 'Plugin Auth Token not found'));
223 223 }
224 224
225 225 } catch (Exception $e) {
226 - error_log('Get Plugin Auth Token Error: ' . $e->getMessage());
226 + error_log('Get Plugin Auth Token Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
227 227 wp_send_json_error(array('message' => 'Error retrieving Plugin Auth Token'));
228 228 }
229 229 }
230 230
@@ -329,9 +329,9 @@
329 329 if (!$this_auth_completed && wp_using_ext_object_cache()) {
330 330 global $wpdb;
331 331
332 332 // Check expiry first
333 - $timeout = $wpdb->get_var(
333 + $timeout = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
334 334 $wpdb->prepare(
335 335 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
336 336 '_transient_timeout_' . $success_key
337 337 )
@@ -338,12 +338,12 @@
338 338 );
339 339
340 340 if ($timeout && (int) $timeout < time()) {
341 341 // Expired — clean up
342 - $wpdb->delete($wpdb->options, array('option_name' => '_transient_' . $success_key));
343 - $wpdb->delete($wpdb->options, array('option_name' => '_transient_timeout_' . $success_key));
342 + $wpdb->delete($wpdb->options, array('option_name' => '_transient_' . $success_key)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
343 + $wpdb->delete($wpdb->options, array('option_name' => '_transient_timeout_' . $success_key)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
344 344 } else {
345 - $db_value = $wpdb->get_var(
345 + $db_value = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
346 346 $wpdb->prepare(
347 347 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
348 348 '_transient_' . $success_key
349 349 )
@@ -359,10 +359,10 @@
359 359 delete_transient($success_key);
360 360 // Also clean up DB fallback rows
361 361 if (wp_using_ext_object_cache()) {
362 362 global $wpdb;
363 - $wpdb->delete($wpdb->options, array('option_name' => '_transient_' . $success_key));
364 - $wpdb->delete($wpdb->options, array('option_name' => '_transient_timeout_' . $success_key));
363 + $wpdb->delete($wpdb->options, array('option_name' => '_transient_' . $success_key)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
364 + $wpdb->delete($wpdb->options, array('option_name' => '_transient_timeout_' . $success_key)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
365 365 }
366 366
367 367 // Get current settings to return connection status
368 368 $general_settings = Metasync::get_option('general') ?? [];
@@ -563,9 +563,9 @@
563 563 $general_options = Metasync::get_option('general') ?? [];
564 564 $plugin_auth_token = $general_options['apikey'] ?? '';
565 565
566 566 if (empty($plugin_auth_token)) {
567 - error_log('MetaSync ERROR: Plugin Auth Token missing from options');
567 + error_log('MetaSync ERROR: Plugin Auth Token missing from options'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
568 568 return false;
569 569 }
570 570
571 571 $random_bytes = wp_generate_password(32, false, false);
@@ -603,12 +603,12 @@
603 603 $timeout_active = '_transient_timeout_metasync_sa_connect_active_' . $sa_connect_token;
604 604 $timeout_metadata = '_transient_timeout_' . $transient_key;
605 605 $expires = time() + 900;
606 606
607 - $wpdb->replace($wpdb->options, array('option_name' => $active_option, 'option_value' => $transient_key, 'autoload' => 'no'));
608 - $wpdb->replace($wpdb->options, array('option_name' => $timeout_active, 'option_value' => $expires, 'autoload' => 'no'));
609 - $wpdb->replace($wpdb->options, array('option_name' => $metadata_option, 'option_value' => maybe_serialize($token_metadata), 'autoload' => 'no'));
610 - $wpdb->replace($wpdb->options, array('option_name' => $timeout_metadata, 'option_value' => $expires, 'autoload' => 'no'));
607 + $wpdb->replace($wpdb->options, array('option_name' => $active_option, 'option_value' => $transient_key, 'autoload' => 'no')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
608 + $wpdb->replace($wpdb->options, array('option_name' => $timeout_active, 'option_value' => $expires, 'autoload' => 'no')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
609 + $wpdb->replace($wpdb->options, array('option_name' => $metadata_option, 'option_value' => maybe_serialize($token_metadata), 'autoload' => 'no')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
610 + $wpdb->replace($wpdb->options, array('option_name' => $timeout_metadata, 'option_value' => $expires, 'autoload' => 'no')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
611 611 }
612 612
613 613 return $sa_connect_token;
614 614 }
@@ -742,9 +742,9 @@
742 742 {
743 743 global $wpdb;
744 744
745 745 try {
746 - $rate_limit_transients = $wpdb->get_results(
746 + $rate_limit_transients = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient enumeration/cleanup on the options table — no API to scan or bulk-delete transient rows
747 747 "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_sa_connect_rate_limit_%'",
748 748 ARRAY_A
749 749 );
750 750
@@ -769,9 +769,9 @@
769 769 public function clear_jwt_token_cache()
770 770 {
771 771 global $wpdb;
772 772
773 - $deleted = $wpdb->query(
773 + $deleted = $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
774 774 $wpdb->prepare(
775 775 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
776 776 '_transient_metasync_jwt_token_%'
777 777 )
@@ -776,9 +776,9 @@
776 776 '_transient_metasync_jwt_token_%'
777 777 )
778 778 );
779 779
780 - $wpdb->query(
780 + $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- manual transient rows on the options table (autoload=no) — mirrors core transient storage; TTL reads need the paired timeout row
781 781 $wpdb->prepare(
782 782 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
783 783 '_transient_timeout_metasync_jwt_token_%'
784 784 )
@@ -902,9 +902,9 @@
902 902 try {
903 903 $response = wp_remote_post($url, $args);
904 904
905 905 if (is_wp_error($response)) {
906 - error_log('MetaSync: JWT token API request failed - ' . $response->get_error_message());
906 + error_log('MetaSync: JWT token API request failed - ' . $response->get_error_message()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
907 907 return false;
908 908 }
909 909
910 910 $response_code = wp_remote_retrieve_response_code($response);
@@ -910,9 +910,9 @@
910 910 $response_code = wp_remote_retrieve_response_code($response);
911 911 $response_body = wp_remote_retrieve_body($response);
912 912
913 913 if ($response_code !== 200) {
914 - error_log('MetaSync: JWT token API returned error code ' . $response_code);
914 + error_log('MetaSync: JWT token API returned error code ' . $response_code); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
915 915 return false;
916 916 }
917 917
918 918 $data = json_decode($response_body, true);
@@ -917,9 +917,9 @@
917 917
918 918 $data = json_decode($response_body, true);
919 919
920 920 if (!$data || !isset($data['token'], $data['expires'])) {
921 - error_log('MetaSync: Invalid JWT token API response format');
921 + error_log('MetaSync: Invalid JWT token API response format'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
922 922 return false;
923 923 }
924 924
925 925 $token_data = array(
@@ -933,9 +933,9 @@
933 933
934 934 return $data['token'];
935 935
936 936 } catch (Exception $e) {
937 - error_log('MetaSync: Exception during JWT generation - ' . $e->getMessage());
937 + error_log('MetaSync: Exception during JWT generation - ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
938 938 return false;
939 939 }
940 940 }
941 941
@@ -1118,9 +1118,9 @@
1118 1118 'timestamp' => current_time('mysql', true)
1119 1119 ));
1120 1120
1121 1121 } catch (Exception $e) {
1122 - error_log('Authentication Reset Error: ' . $e->getMessage());
1122 + error_log('Authentication Reset Error: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
1123 1123 wp_send_json_error(array(
1124 1124 'message' => 'An error occurred while resetting authentication. Please try again or contact support.',
1125 1125 'code' => 'reset_failed',
1126 1126 'error' => $e->getMessage()
@@ -1186,20 +1186,8 @@
1186 1186 ));
1187 1187 }
1188 1188
1189 1189 /**
1190 - * Simple AJAX test without nonce (for debugging connectivity)
1191 - */
1192 - public function simple_ajax_test()
1193 - {
1194 - wp_send_json_success(array(
1195 - 'message' => 'Basic AJAX connectivity works',
1196 - 'timestamp' => time(),
1197 - 'no_nonce_required' => true
1198 - ));
1199 - }
1200 -
1201 - /**
1202 1190 * Test whitelabel domain configuration (development/debugging)
1203 1191 */
1204 1192 public function test_whitelabel_domain()
1205 1193 {
@@ -1247,10 +1235,10 @@
1247 1235 if (!is_admin()) {
1248 1236 return;
1249 1237 }
1250 1238
1251 - $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
1252 - $current_page = isset($_GET['page']) ? $_GET['page'] : '';
1239 + $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing, each action verifies its own nonce
1240 + $current_page = isset($_GET['page']) ? $_GET['page'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing, each action verifies its own nonce
1253 1241
1254 1242 $whitelabel_settings = Metasync::get_whitelabel_settings();
1255 1243 $user_password = $whitelabel_settings['settings_password'] ?? '';
1256 1244 $hide_settings_enabled = !empty($whitelabel_settings['hide_settings']);
@@ -1285,11 +1273,11 @@
1285 1273 if (isset($_POST['whitelabel_logout'])) {
1286 1274 if (wp_verify_nonce($_POST['whitelabel_logout_nonce'] ?? '', 'whitelabel_logout_nonce')) {
1287 1275 $auth->revoke_access();
1288 1276
1289 - $redirect_tab = $_GET['tab'] ?? 'whitelabel';
1277 + $redirect_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'whitelabel';
1290 1278 $redirect_url = admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '&tab=' . $redirect_tab);
1291 - wp_redirect($redirect_url);
1279 + wp_safe_redirect($redirect_url);
1292 1280 exit;
1293 1281 }
1294 1282 }
1295 1283