| @@ -49,12 +49,26 @@ | ||
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | - * Add debug menu (developer only - hidden by default) | |
| 53 | + * Whether debug tooling is allowed to run at all right now. | |
| 54 | + * | |
| 55 | + * `manage_options` alone isn't a real restriction — every site admin has | |
| 56 | + * it, so this page and its AJAX handlers were reachable by anyone on any | |
| 57 | + * site. Hard-disabled: the menu item, the page, and every AJAX handler | |
| 58 | + * are unreachable for all users on all sites, no toggle or capability | |
| 59 | + * bypasses this. The class and its methods are left in place; only | |
| 60 | + * access is blocked. | |
| 54 | 61 | */ |
| 62 | + private static function is_debug_tools_enabled() { | |
| 63 | + return false; | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Add debug menu (internal only - hidden on customer production sites) | |
| 68 | + */ | |
| 55 | 69 | public function add_debug_menu() { |
| 56 | - if (!current_user_can('manage_options')) { | |
| 70 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 57 | 71 | return; |
| 58 | 72 | } |
| 59 | 73 | |
| 60 | 74 | $menu_slug = Metasync_Admin::$page_slug; |
| @@ -72,9 +86,9 @@ | ||
| 72 | 86 | /** |
| 73 | 87 | * Create the debug page |
| 74 | 88 | */ |
| 75 | 89 | public function create_debug_page() { |
| 76 | - if (!current_user_can('manage_options')) { | |
| 90 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 77 | 91 | wp_die('Unauthorized'); |
| 78 | 92 | } |
| 79 | 93 | |
| 80 | 94 | $whitelabel_otto_name = Metasync::get_whitelabel_otto_name(); |
| @@ -643,9 +657,9 @@ | ||
| 643 | 657 | */ |
| 644 | 658 | private function get_option_last_updated($option_name) { |
| 645 | 659 | global $wpdb; |
| 646 | 660 | |
| 647 | - $result = $wpdb->get_var($wpdb->prepare( | |
| 661 | + $result = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 648 | 662 | "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", |
| 649 | 663 | $option_name |
| 650 | 664 | )); |
| 651 | 665 | |
| @@ -651,9 +665,9 @@ | ||
| 651 | 665 | |
| 652 | 666 | if ($result) { |
| 653 | 667 | $data = maybe_unserialize($result); |
| 654 | 668 | if (isset($data['last_updated'])) { |
| 655 | - return date('Y-m-d H:i:s', $data['last_updated']); | |
| 669 | + return gmdate('Y-m-d H:i:s', $data['last_updated']); | |
| 656 | 670 | } |
| 657 | 671 | } |
| 658 | 672 | |
| 659 | 673 | return 'Unknown'; |
| @@ -760,9 +774,9 @@ | ||
| 760 | 774 | */ |
| 761 | 775 | public function ajax_test_otto_api() { |
| 762 | 776 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 763 | 777 | |
| 764 | - if (!current_user_can('manage_options')) { | |
| 778 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 765 | 779 | wp_die('Unauthorized'); |
| 766 | 780 | } |
| 767 | 781 | |
| 768 | 782 | $general_options = Metasync::get_option('general'); |
| @@ -816,9 +830,9 @@ | ||
| 816 | 830 | */ |
| 817 | 831 | public function ajax_test_notification_endpoint() { |
| 818 | 832 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 819 | 833 | |
| 820 | - if (!current_user_can('manage_options')) { | |
| 834 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 821 | 835 | wp_die('Unauthorized'); |
| 822 | 836 | } |
| 823 | 837 | |
| 824 | 838 | $endpoint_url = rest_url('metasync/v1/otto_crawl_notify'); |
| @@ -859,9 +873,9 @@ | ||
| 859 | 873 | */ |
| 860 | 874 | public function ajax_clear_otto_cache() { |
| 861 | 875 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 862 | 876 | |
| 863 | - if (!current_user_can('manage_options')) { | |
| 877 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 864 | 878 | wp_die('Unauthorized'); |
| 865 | 879 | } |
| 866 | 880 | |
| 867 | 881 | // Clear crawl data |
| @@ -891,9 +905,9 @@ | ||
| 891 | 905 | */ |
| 892 | 906 | public function ajax_simulate_crawl_notification() { |
| 893 | 907 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 894 | 908 | |
| 895 | - if (!current_user_can('manage_options')) { | |
| 909 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 896 | 910 | wp_die('Unauthorized'); |
| 897 | 911 | } |
| 898 | 912 | |
| 899 | 913 | $general_options = Metasync::get_option('general'); |
| @@ -930,9 +944,9 @@ | ||
| 930 | 944 | public function ajax_test_specific_url() { |
| 931 | 945 | try { |
| 932 | 946 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 933 | 947 | |
| 934 | - if (!current_user_can('manage_options')) { | |
| 948 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 935 | 949 | wp_die('Unauthorized'); |
| 936 | 950 | } |
| 937 | 951 | |
| 938 | 952 | $test_url = sanitize_url($_POST['test_url'] ?? ''); |
| @@ -964,9 +978,9 @@ | ||
| 964 | 978 | |
| 965 | 979 | wp_send_json_success($results); |
| 966 | 980 | |
| 967 | 981 | } catch (Exception $e) { |
| 968 | - error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage()); | |
| 982 | + error_log('MetaSync OTTO Debug: Exception in ajax_test_specific_url: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production | |
| 969 | 983 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 970 | 984 | } |
| 971 | 985 | } |
| 972 | 986 | |
| @@ -975,9 +989,9 @@ | ||
| 975 | 989 | */ |
| 976 | 990 | public function ajax_emulate_otto_changes() { |
| 977 | 991 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 978 | 992 | |
| 979 | - if (!current_user_can('manage_options')) { | |
| 993 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 980 | 994 | wp_die('Unauthorized'); |
| 981 | 995 | } |
| 982 | 996 | |
| 983 | 997 | $test_url = sanitize_url($_POST['test_url'] ?? ''); |
| @@ -1097,9 +1111,9 @@ | ||
| 1097 | 1111 | /** |
| 1098 | 1112 | * Test page type detection |
| 1099 | 1113 | */ |
| 1100 | 1114 | private function test_page_type_detection($url) { |
| 1101 | - $parsed_url = parse_url($url); | |
| 1115 | + $parsed_url = wp_parse_url($url); | |
| 1102 | 1116 | $path = $parsed_url['path'] ?? '/'; |
| 1103 | 1117 | |
| 1104 | 1118 | $detection = array( |
| 1105 | 1119 | 'url' => $url, |
| @@ -1198,9 +1212,9 @@ | ||
| 1198 | 1212 | public function ajax_simple_test() { |
| 1199 | 1213 | try { |
| 1200 | 1214 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1201 | 1215 | |
| 1202 | - if (!current_user_can('manage_options')) { | |
| 1216 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1203 | 1217 | wp_send_json_error('Unauthorized'); |
| 1204 | 1218 | } |
| 1205 | 1219 | |
| 1206 | 1220 | wp_send_json_success(array( |
| @@ -1210,9 +1224,9 @@ | ||
| 1210 | 1224 | 'nonce_verified' => true |
| 1211 | 1225 | )); |
| 1212 | 1226 | |
| 1213 | 1227 | } catch (Exception $e) { |
| 1214 | - error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage()); | |
| 1228 | + error_log('MetaSync OTTO Debug: Exception in ajax_simple_test: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production | |
| 1215 | 1229 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 1216 | 1230 | } |
| 1217 | 1231 | } |
| 1218 | 1232 | |
| @@ -1222,9 +1236,9 @@ | ||
| 1222 | 1236 | public function ajax_test_db_permissions() { |
| 1223 | 1237 | try { |
| 1224 | 1238 | check_ajax_referer('metasync_otto_debug', 'nonce'); |
| 1225 | 1239 | |
| 1226 | - if (!current_user_can('manage_options')) { | |
| 1240 | + if (!current_user_can('manage_options') || !self::is_debug_tools_enabled()) { | |
| 1227 | 1241 | wp_send_json_error('Unauthorized'); |
| 1228 | 1242 | } |
| 1229 | 1243 | |
| 1230 | 1244 | $results = array( |
| @@ -1244,9 +1258,9 @@ | ||
| 1244 | 1258 | |
| 1245 | 1259 | // Test 2: Check if we can access Action Scheduler tables |
| 1246 | 1260 | global $wpdb; |
| 1247 | 1261 | $table_name = $wpdb->prefix . 'actionscheduler_actions'; |
| 1248 | - $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name; | |
| 1262 | + $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table_name))) == $table_name; // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 1249 | 1263 | |
| 1250 | 1264 | $results['tests']['table_access'] = array( |
| 1251 | 1265 | 'table_exists' => $table_exists, |
| 1252 | 1266 | 'table_name' => $table_name, |
| @@ -1254,9 +1268,9 @@ | ||
| 1254 | 1268 | ); |
| 1255 | 1269 | |
| 1256 | 1270 | // Test 3: Try to insert a test record |
| 1257 | 1271 | if ($table_exists) { |
| 1258 | - $insert_result = $wpdb->insert( | |
| 1272 | + $insert_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 1259 | 1273 | $table_name, |
| 1260 | 1274 | array( |
| 1261 | 1275 | 'hook' => 'metasync_debug_test', |
| 1262 | 1276 | 'status' => 'pending', |
| @@ -1275,9 +1289,9 @@ | ||
| 1275 | 1289 | ); |
| 1276 | 1290 | |
| 1277 | 1291 | // Clean up test record |
| 1278 | 1292 | if ($insert_result !== false && $wpdb->insert_id) { |
| 1279 | - $wpdb->delete($table_name, array('ID' => $wpdb->insert_id)); | |
| 1293 | + $wpdb->delete($table_name, array('ID' => $wpdb->insert_id)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- admin debug tool — scratch diagnostics storage outside any WordPress API | |
| 1280 | 1294 | } |
| 1281 | 1295 | } |
| 1282 | 1296 | |
| 1283 | 1297 | // Test 4: Check WordPress cron functionality |
| @@ -1289,9 +1303,9 @@ | ||
| 1289 | 1303 | |
| 1290 | 1304 | wp_send_json_success($results); |
| 1291 | 1305 | |
| 1292 | 1306 | } catch (Exception $e) { |
| 1293 | - error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage()); | |
| 1307 | + error_log('MetaSync OTTO Debug: Exception in ajax_test_db_permissions: ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- unreachable in production | |
| 1294 | 1308 | wp_send_json_error('Exception: ' . $e->getMessage()); |
| 1295 | 1309 | } |
| 1296 | 1310 | } |
| 1297 | 1311 | } |