blocked_table = $wpdb->prefix . 'user_lookup_blocked'; // Initialize plugin $this->init(); // Load settings after init $this->load_settings(); } private function init() { // Register activation hook register_activation_hook(__FILE__, array($this, 'plugin_activate')); // Add menu item add_action('admin_menu', array($this, 'add_admin_menu')); // Register API endpoint add_action('rest_api_init', array($this, 'register_api_endpoint')); // Enforce SSL if enabled add_action('template_redirect', array($this, 'force_ssl_redirect')); } public function plugin_activate() { // Create blocked table $this->create_blocked_table(); // Initialize default settings if they don't exist if (!get_option('user_lookup_api_key')) { $this->generate_api_key(); } if (!get_option('user_lookup_api_secret')) { $this->generate_api_secret(); } if (!get_option('user_lookup_allowed_ips')) { update_option('user_lookup_allowed_ips', array()); } if (!get_option('user_lookup_allowed_domains')) { update_option('user_lookup_allowed_domains', array()); } if (!get_option('user_lookup_force_ssl')) { update_option('user_lookup_force_ssl', true); } if (!get_option('user_lookup_max_failed_attempts')) { update_option('user_lookup_max_failed_attempts', 5); } if (!get_option('user_lookup_lockout_time')) { update_option('user_lookup_lockout_time', 300); // 5 minutes } // Create empty index files $this->create_empty_index_files(); } private function create_empty_index_files() { $plugin_dir = plugin_dir_path(__FILE__); $directories = array( $plugin_dir, $plugin_dir . 'templates/' ); // Use WP_Filesystem for file operations global $wp_filesystem; if (!function_exists('WP_Filesystem')) { require_once(ABSPATH . 'wp-admin/includes/file.php'); } WP_Filesystem(); foreach ($directories as $dir) { if (!$wp_filesystem->exists($dir)) { $wp_filesystem->mkdir($dir, 0755, true); } $wp_filesystem->put_contents($dir . 'index.php', 'get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS $this->blocked_table ( id bigint(20) NOT NULL AUTO_INCREMENT, ip_address varchar(45) NOT NULL, blocked_until datetime NOT NULL, permanent_block tinyint(1) DEFAULT 0, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } private function load_settings() { $this->api_key = get_option('user_lookup_api_key', ''); $this->api_secret = get_option('user_lookup_api_secret', ''); $this->allowed_ips = get_option('user_lookup_allowed_ips', array()); $this->allowed_domains = get_option('user_lookup_allowed_domains', array()); $this->max_failed_attempts = get_option('user_lookup_max_failed_attempts', 5); $this->lockout_time = get_option('user_lookup_lockout_time', 300); // Generate API key and secret if they don't exist if (empty($this->api_key)) { $this->api_key = $this->generate_api_key(); } if (empty($this->api_secret)) { $this->api_secret = $this->generate_api_secret(); } } private function generate_api_key() { $api_key = bin2hex(random_bytes(32)); update_option('user_lookup_api_key', $api_key); return $api_key; } private function generate_api_secret() { $api_secret = bin2hex(random_bytes(32)); update_option('user_lookup_api_secret', $api_secret); return $api_secret; } public function add_admin_menu() { add_menu_page( 'User Lookup API', 'User Lookup API', 'manage_options', 'user-lookup-settings', array($this, 'render_admin_page'), 'dashicons-search' ); } public function render_admin_page() { // Verify admin access if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'secure-user-lookup')); } // Add nonce field to the form wp_nonce_field('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field'); // Handle form submission if (isset($_POST['submit']) && check_admin_referer('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field')) { $this->save_settings(); } // Regenerate API secret if (isset($_POST['regenerate_api_secret']) && check_admin_referer('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field')) { $this->api_secret = $this->generate_api_secret(); update_option('user_lookup_api_secret', $this->api_secret); } // Regenerate API key if (isset($_POST['regenerate_api_key']) && check_admin_referer('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field')) { $this->api_key = $this->generate_api_key(); update_option('user_lookup_api_key', $this->api_key); } // Handle unblock and permanent block actions if (isset($_POST['unblock_ip']) && check_admin_referer('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field')) { $this->unblock_ip(sanitize_text_field(wp_unslash($_POST['unblock_ip']))); } if (isset($_POST['permanent_block_ip']) && check_admin_referer('user_lookup_settings_nonce_action', 'user_lookup_settings_nonce_field')) { $this->permanent_block_ip(sanitize_text_field(wp_unslash($_POST['permanent_block_ip']))); } // Retrieve blocked IPs with caching $blocked_ips = wp_cache_get('blocked_ips', 'secure_user_lookup'); if (false === $blocked_ips) { global $wpdb; $blocked_ips = $wpdb->get_results( $wpdb->prepare("SELECT * FROM " . esc_sql($this->blocked_table)) ); wp_cache_set('blocked_ips', $blocked_ips, 'secure_user_lookup', 3600); // Cache for 1 hour } // Include admin template $template_path = plugin_dir_path(__FILE__) . 'templates/admin-page.php'; if (file_exists($template_path)) { include($template_path); } else { echo esc_html__('Error: Template file not found', 'secure-user-lookup'); } } private function save_settings() { if (isset($_POST['allowed_ips'])) { $ips = array_filter(array_map('trim', explode("\n", sanitize_textarea_field(wp_unslash($_POST['allowed_ips']))))); update_option('user_lookup_allowed_ips', $ips); $this->allowed_ips = $ips; } if (isset($_POST['allowed_domains'])) { $domains = array_filter(array_map('trim', explode("\n", sanitize_textarea_field(wp_unslash($_POST['allowed_domains']))))); update_option('user_lookup_allowed_domains', $domains); $this->allowed_domains = $domains; } if (isset($_POST['max_failed_attempts'])) { $max_failed_attempts = intval(sanitize_text_field(wp_unslash($_POST['max_failed_attempts']))); update_option('user_lookup_max_failed_attempts', $max_failed_attempts); $this->max_failed_attempts = $max_failed_attempts; } if (isset($_POST['lockout_time'])) { $lockout_time = intval(sanitize_text_field(wp_unslash($_POST['lockout_time']))); update_option('user_lookup_lockout_time', $lockout_time); $this->lockout_time = $lockout_time; } // Handle force_ssl checkbox if (isset($_POST['force_ssl'])) { update_option('user_lookup_force_ssl', true); } else { update_option('user_lookup_force_ssl', false); } } private function unblock_ip($ip) { global $wpdb; $wpdb->delete($this->blocked_table, array('ip_address' => $ip)); wp_cache_delete('blocked_ips', 'secure_user_lookup'); // Clear cache after unblocking } private function permanent_block_ip($ip) { global $wpdb; $wpdb->update( $this->blocked_table, array('permanent_block' => 1), array('ip_address' => $ip), array('%d'), array('%s') ); wp_cache_delete('blocked_ips', 'secure_user_lookup'); // Clear cache after blocking } public function register_api_endpoint() { register_rest_route('user-lookup/v1', '/get-username', array( 'methods' => 'POST', 'callback' => array($this, 'get_username'), 'permission_callback' => array($this, 'check_permissions'), )); } public function get_username(WP_REST_Request $request) { // Extract email from the request body $email = $request->get_param('email'); if (empty($email)) { return new WP_Error('missing_email', esc_html__('Email parameter is required', 'secure-user-lookup'), array('status' => 400)); } // Find user by email $user = get_user_by('email', $email); if (!$user) { return new WP_Error('user_not_found', esc_html__('User not found', 'secure-user-lookup'), array('status' => 404)); } // Retrieve membership level via Paid Membership Pro $membership_level = pmpro_getMembershipLevelForUser($user->ID); // Return username and membership level return rest_ensure_response(array( 'data' => array( 'username' => $user->user_login, 'membership_level' => $membership_level ? $membership_level->name : 'None', ), )); } public function check_permissions(WP_REST_Request $request) { $api_key = $request->get_header('X-API-Key'); $api_secret = $request->get_header('X-API-Secret'); if ($api_key !== $this->api_key || $api_secret !== $this->api_secret) { $client_ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; $this->block_ip($client_ip); return new WP_Error('invalid_credentials', esc_html__('Invalid API key or secret', 'secure-user-lookup'), array('status' => 403)); } $client_ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; $server_name = isset($_SERVER['SERVER_NAME']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_NAME'])) : ''; $allowed = in_array($client_ip, $this->allowed_ips) || in_array($server_name, $this->allowed_domains); if (!$allowed) { $this->block_ip($client_ip); return new WP_Error('unauthorized', esc_html__('Access denied for your IP/domain', 'secure-user-lookup'), array('status' => 403)); } // Check if IP is blocked if ($this->is_ip_blocked($client_ip)) { return new WP_Error('blocked_ip', esc_html__('Your IP is blocked', 'secure-user-lookup'), array('status' => 429)); } // Check for failed attempts $failed_attempts = $this->get_failed_attempts($client_ip); if ($failed_attempts >= $this->max_failed_attempts) { $this->block_ip($client_ip); return new WP_Error('too_many_attempts', esc_html__('API locked due to too many failed attempts', 'secure-user-lookup'), array('status' => 429)); } return true; } private function is_ip_blocked($ip) { $blocked_ips = wp_cache_get('blocked_ips', 'secure_user_lookup'); if (false === $blocked_ips) { global $wpdb; $blocked_ips = $wpdb->get_results( $wpdb->prepare("SELECT * FROM " . esc_sql($this->blocked_table) . " WHERE ip_address = %s AND (blocked_until > %s OR permanent_block = 1)", $ip, gmdate('Y-m-d H:i:s')) ); wp_cache_set('blocked_ips', $blocked_ips, 'secure_user_lookup', 3600); // Cache for 1 hour } return !empty($blocked_ips); } private function block_ip($ip) { global $wpdb; $time = gmdate('Y-m-d H:i:s', time() + $this->lockout_time); $wpdb->insert( $this->blocked_table, array( 'ip_address' => $ip, 'blocked_until' => $time, 'permanent_block' => 0, ) ); wp_cache_delete('blocked_ips', 'secure_user_lookup'); // Clear cache after blocking } private function get_failed_attempts($ip) { $failed_attempts = wp_cache_get('failed_attempts_' . $ip, 'secure_user_lookup'); if (false === $failed_attempts) { global $wpdb; $time = gmdate('Y-m-d H:i:s', time() - $this->lockout_time); $failed_attempts = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM " . esc_sql($this->blocked_table) . " WHERE ip_address = %s AND blocked_until > %s", $ip, $time )); wp_cache_set('failed_attempts_' . $ip, $failed_attempts, 'secure_user_lookup', $this->lockout_time); // Cache for lockout time } return intval($failed_attempts); } public function force_ssl_redirect() { if (get_option('user_lookup_force_ssl', false) && !is_ssl()) { $host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : ''; $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; wp_redirect('https://' . $host . $uri); exit; } } } // Initialize plugin $secure_user_lookup = new SecureUserLookupAPI(); ?>