__( 'Security check failed.', 'acb' ), ]); } // Check user permissions if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); } // Validate POST data exists if (!isset($_POST['config']) || empty($_POST['config'])) { wp_send_json_error('Configuration data is required'); } // Sanitize and unslash config data $config = wp_unslash($_POST['config']); $config = sanitize_textarea_field($config); $config_array = json_decode($config, true); // Validate JSON decode if (json_last_error() !== JSON_ERROR_NONE) { wp_send_json_error('Invalid configuration format: ' . json_last_error_msg()); } if (!is_array($config_array)) { wp_send_json_error('Configuration must be a valid JSON object'); } // Validate required fields $required_fields = ['apiKey', 'authDomain', 'projectId']; foreach ($required_fields as $field) { if (!isset($config_array[$field]) || empty(trim($config_array[$field]))) { wp_send_json_error("Missing or empty required field: $field"); } } // Sanitize configuration values $sanitized_config = []; foreach ($config_array as $key => $value) { $sanitized_key = sanitize_key($key); $sanitized_value = sanitize_text_field($value); if (!empty($sanitized_key) && !empty($sanitized_value)) { $sanitized_config[$sanitized_key] = $sanitized_value; } } // Validate sanitized config still has required fields foreach ($required_fields as $field) { if (!isset($sanitized_config[$field]) || empty($sanitized_config[$field])) { wp_send_json_error("Invalid data for required field: $field"); } } // Save configuration $result = update_option('acb_firebase_authentication_value', wp_json_encode($sanitized_config)); if ($result) { // Update internal config $this->firebase_config = $sanitized_config; wp_send_json_success('Firebase configuration saved successfully'); } else { wp_send_json_error('Failed to save configuration'); } } /** * Handle Firebase authentication * * @since 1.0.0 */ public function handle_firebase_auth() { // Verify nonce if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error([ 'message' => __( 'Security check failed.', 'acb' ), ]); } // Validate required fields exist $required_fields = ['firebase_uid', 'user_name', 'user_email']; foreach ($required_fields as $field) { if (!isset($_POST[$field]) || empty(trim($_POST[$field]))) { wp_send_json_error("Missing required field: $field"); } } // Sanitize and validate input data $firebase_uid = sanitize_text_field(wp_unslash($_POST['firebase_uid'])); $user_name = sanitize_text_field(wp_unslash($_POST['user_name'])); $user_email = sanitize_email(wp_unslash($_POST['user_email'])); $user_avatar = isset($_POST['user_avatar']) ? esc_url_raw(wp_unslash($_POST['user_avatar'])) : ''; $auth_provider = isset($_POST['auth_provider']) ? sanitize_text_field(wp_unslash($_POST['auth_provider'])) : 'firebase'; // Validate email format if (!is_email($user_email)) { wp_send_json_error('Invalid email format'); } // Validate sanitized data if (empty($firebase_uid) || empty($user_name) || empty($user_email)) { wp_send_json_error('Invalid data provided'); } $user_id = $this->create_or_update_user($firebase_uid, $user_name, $user_email, $user_avatar, $auth_provider); if ($user_id) { wp_send_json_success([ 'user_id' => absint($user_id), 'message' => 'Authentication successful' ]); } else { wp_send_json_error('Failed to authenticate user'); } } /** * Create or update user in database * * @param string $firebase_uid * @param string $user_name * @param string $user_email * @param string $user_avatar * @param string $auth_provider * @return int|false */ private function create_or_update_user($firebase_uid, $user_name, $user_email, $user_avatar, $auth_provider) { global $wpdb; $table_users = $wpdb->prefix . 'acb_users'; // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_users)) !== $table_users) { error_log('ACB Firebase Service - Table does not exist: ' . $table_users); return false; } // Check if user exists by Firebase UID first, then by email $existing_user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_users WHERE firebase_uid = %s", $firebase_uid ) ); // If not found by Firebase UID, check by email if (!$existing_user) { $existing_user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_users WHERE user_email = %s", $user_email ) ); } if ($existing_user) { // Update existing user with latest information $result = $wpdb->update( $table_users, [ 'firebase_uid' => $firebase_uid, 'user_name' => $user_name, 'user_email' => $user_email, 'user_avatar' => $user_avatar, 'auth_provider' => $auth_provider, 'last_seen' => current_time('mysql'), 'updated_at' => current_time('mysql') ], ['id' => $existing_user->id], ['%s', '%s', '%s', '%s', '%s', '%s', '%s'], ['%d'] ); if ($result !== false) { error_log('ACB Firebase Service - Updated existing user: ' . $user_email . ' (ID: ' . $existing_user->id . ')'); return $existing_user->id; } else { error_log('ACB Firebase Service - Failed to update user: ' . $user_email); return false; } } else { // Create new user - this is where new users should be immediately visible $result = $wpdb->insert( $table_users, [ 'firebase_uid' => $firebase_uid, 'user_name' => $user_name, 'user_email' => $user_email, 'user_avatar' => $user_avatar, 'auth_provider' => $auth_provider, 'is_admin' => 0, 'last_seen' => current_time('mysql'), 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql') ], ['%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s'] ); if ($result !== false) { $new_user_id = $wpdb->insert_id; error_log('ACB Firebase Service - Created new user: ' . $user_email . ' (ID: ' . $new_user_id . ')'); // Immediately make this user available to other users by triggering a refresh $this->notify_user_list_update(); return $new_user_id; } else { error_log('ACB Firebase Service - Failed to create user: ' . $user_email . ' Error: ' . $wpdb->last_error); return false; } } } /** * Notify that user list should be updated (for real-time updates) * This can be extended to use WebSockets or Server-Sent Events in the future */ private function notify_user_list_update() { // For now, we'll use a simple transient to signal that user list should refresh set_transient('acb_user_list_updated', time(), 60); // 1 minute expiry // Log for debugging error_log('ACB Firebase Service - User list update notification sent'); } /** * Save message to database * * @since 1.0.0 */ public function save_message() { // Verify nonce if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error([ 'message' => __( 'Security check failed.', 'acb' ), ]); } // Validate required fields exist $required_fields = ['user_id', 'user_name', 'message']; foreach ($required_fields as $field) { if (!isset($_POST[$field]) || empty(trim($_POST[$field]))) { wp_send_json_error("Missing required field: $field"); } } // Sanitize and validate input data $user_id = sanitize_text_field(wp_unslash($_POST['user_id'])); $user_name = sanitize_text_field(wp_unslash($_POST['user_name'])); $user_email = isset($_POST['user_email']) ? sanitize_email(wp_unslash($_POST['user_email'])) : ''; $user_avatar = isset($_POST['user_avatar']) ? esc_url_raw(wp_unslash($_POST['user_avatar'])) : ''; $message = wp_kses_post(wp_unslash($_POST['message'])); // Allow safe HTML for messages $message_type = isset($_POST['message_type']) ? sanitize_text_field(wp_unslash($_POST['message_type'])) : 'text'; $file_url = isset($_POST['file_url']) ? esc_url_raw(wp_unslash($_POST['file_url'])) : ''; // Validate email if provided if (!empty($user_email) && !is_email($user_email)) { wp_send_json_error('Invalid email format'); } // Validate sanitized data if (empty($user_id) || empty($user_name) || empty($message)) { wp_send_json_error('Invalid data provided'); } $message_id = $this->insert_message($user_id, $user_name, $user_email, $user_avatar, $message, $message_type, $file_url); if ($message_id) { wp_send_json_success([ 'message_id' => absint($message_id), 'message' => 'Message saved successfully' ]); } else { wp_send_json_error('Failed to save message'); } } /** * Insert message into database * * @param string $user_id * @param string $user_name * @param string $user_email * @param string $user_avatar * @param string $message * @param string $message_type * @param string $file_url * @return int|false */ private function insert_message($user_id, $user_name, $user_email, $user_avatar, $message, $message_type, $file_url) { global $wpdb; $table_messages = $wpdb->prefix . 'acb_messages'; // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_messages)) !== $table_messages) { error_log('ACB Firebase Service - Table does not exist: ' . $table_messages); return false; } $result = $wpdb->insert( $table_messages, [ 'user_id' => $user_id, 'user_name' => $user_name, 'user_email' => $user_email, 'user_avatar' => $user_avatar, 'message' => $message, 'message_type' => $message_type, 'file_url' => $file_url, 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql') ], ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'] ); return $result !== false ? $wpdb->insert_id : false; } /** * Get messages from database * * @since 1.0.0 */ public function get_messages() { // Verify nonce if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error([ 'message' => __( 'Security check failed.', 'acb' ), ]); } // Sanitize and validate pagination parameters $limit = isset($_POST['limit']) ? absint($_POST['limit']) : 50; $offset = isset($_POST['offset']) ? absint($_POST['offset']) : 0; // Set reasonable limits $limit = min($limit, 100); // Max 100 messages per request $limit = max($limit, 1); // Min 1 message per request global $wpdb; $table_messages = $wpdb->prefix . 'acb_messages'; // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_messages)) !== $table_messages) { wp_send_json_error('Messages table does not exist'); } $messages = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_messages ORDER BY created_at DESC LIMIT %d OFFSET %d", $limit, $offset ) ); if ($messages === false) { wp_send_json_error('Failed to retrieve messages'); } $formatted_messages = []; foreach ($messages as $message) { $formatted_messages[] = [ 'id' => absint($message->id), 'user_id' => esc_html($message->user_id), 'user_name' => esc_html($message->user_name), 'user_email' => esc_html($message->user_email), 'user_avatar' => esc_url($message->user_avatar), 'message' => wp_kses_post($message->message), // Allow safe HTML for display 'message_type' => esc_html($message->message_type), 'file_url' => esc_url($message->file_url), 'created_at' => esc_html($message->created_at), 'formatted_time' => esc_html(date('M d, Y > h:i A', strtotime($message->created_at))) ]; } wp_send_json_success([ 'messages' => array_reverse($formatted_messages), 'total' => count($formatted_messages) ]); } /** * Get users from database * * @since 1.0.0 */ public function get_users() { // Verify nonce if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error([ 'message' => __( 'Security check failed.', 'acb' ), ]); } global $wpdb; $table_users = $wpdb->prefix . 'acb_users'; // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_users)) !== $table_users) { wp_send_json_error('Users table does not exist'); } // Get all users except current user (if provided) $current_user_uid = isset($_POST['current_user_uid']) ? sanitize_text_field(wp_unslash($_POST['current_user_uid'])) : ''; if (!empty($current_user_uid)) { $users = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_users WHERE firebase_uid != %s ORDER BY last_seen DESC", $current_user_uid ) ); } else { $users = $wpdb->get_results( "SELECT * FROM $table_users ORDER BY last_seen DESC" ); } if ($users === false) { wp_send_json_error('Failed to retrieve users'); } $formatted_users = []; foreach ($users as $user) { // Check if user is online (last seen within 2 minutes) $last_seen_time = strtotime($user->last_seen); $is_online = (time() - $last_seen_time) < 120; // 2 minutes $formatted_users[] = [ 'id' => absint($user->id), 'firebase_uid' => esc_html($user->firebase_uid), 'user_name' => esc_html($user->user_name), 'user_email' => esc_html($user->user_email), 'user_avatar' => esc_url($user->user_avatar), 'auth_provider' => esc_html($user->auth_provider), 'is_admin' => (bool) $user->is_admin, 'is_online' => $is_online, 'last_seen' => esc_html($user->last_seen), 'created_at' => esc_html($user->created_at), 'formatted_last_seen' => esc_html(date('M d, Y > h:i A', strtotime($user->last_seen))) ]; } wp_send_json_success([ 'users' => $formatted_users, 'total' => count($formatted_users), 'timestamp' => time() ]); } /** * Get user by Firebase UID * * @param string $firebase_uid * @return object|null */ public function get_user_by_firebase_uid($firebase_uid) { global $wpdb; $table_users = $wpdb->prefix . 'acb_users'; // Sanitize input $firebase_uid = sanitize_text_field($firebase_uid); if (empty($firebase_uid)) { return null; } // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_users)) !== $table_users) { error_log('ACB Firebase Service - Table does not exist: ' . $table_users); return null; } return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_users WHERE firebase_uid = %s", $firebase_uid ) ); } /** * Update user last seen * * @param string $firebase_uid * @return bool */ public function update_user_last_seen($firebase_uid) { global $wpdb; $table_users = $wpdb->prefix . 'acb_users'; // Sanitize input $firebase_uid = sanitize_text_field($firebase_uid); if (empty($firebase_uid)) { return false; } // Validate table exists if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_users)) !== $table_users) { error_log('ACB Firebase Service - Table does not exist: ' . $table_users); return false; } $result = $wpdb->update( $table_users, ['last_seen' => current_time('mysql')], ['firebase_uid' => $firebase_uid], ['%s'], ['%s'] ); return $result !== false; } }