__( 'Security check failed.','admin-chat-box' ) ] ); wp_die(); } // Check user permissions if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( [ 'message' => __( 'Insufficient permissions.','admin-chat-box' ) ] ); wp_die(); } // Validate POST data exists if ( ! isset( $_POST['config'] ) || empty( $_POST['config'] ) ) { wp_send_json_error( [ 'message' => __( 'Configuration data is required.','admin-chat-box' ) ] ); wp_die(); } // 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( [ 'message' => __( 'Invalid configuration format.','admin-chat-box' ) ] ); wp_die(); } if ( ! is_array( $config_array ) ) { wp_send_json_error( [ 'message' => __( 'Configuration must be a valid JSON object.','admin-chat-box' ) ] ); wp_die(); } // Validate required fields $required_fields = [ 'apiKey', 'authDomain', 'projectId' ]; foreach ( $required_fields as $field ) { if ( ! isset( $config_array[ $field ] ) || '' === trim( $config_array[ $field ] ) ) { wp_send_json_error( [ 'message' => sprintf( __( 'Missing or empty required field: %s','admin-chat-box' ), esc_html( $field ) ) ] ); wp_die(); } } // Issue 4.4: Use allowlist instead of sanitize_key() which destroys camelCase keys. $allowed_keys = [ 'apiKey', 'authDomain', 'projectId', 'storageBucket', 'messagingSenderId', 'appId' ]; $sanitized_config = []; foreach ( $allowed_keys as $allowed_key ) { if ( isset( $config_array[ $allowed_key ] ) ) { $sanitized_config[ $allowed_key ] = sanitize_text_field( wp_unslash( $config_array[ $allowed_key ] ) ); } } // 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( [ 'message' => sprintf( __( 'Invalid data for required field: %s','admin-chat-box' ), esc_html( $field ) ) ] ); wp_die(); } } // Save configuration $result = update_option( 'acb_firebase_authentication_value', wp_json_encode( $sanitized_config ) ); if ( $result ) { $this->firebase_config = $sanitized_config; wp_send_json_success( [ 'message' => __( 'Firebase configuration saved successfully.','admin-chat-box' ) ] ); } else { wp_send_json_error( [ 'message' => __( 'Failed to save configuration.','admin-chat-box' ) ] ); } wp_die(); } /** * Handle Firebase authentication * * @since 1.0.0 */ /** * 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) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Table does not exist: ' . esc_attr( $table_users ) ); } return false; } // Check if user exists by Firebase UID first, then by email $existing_user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}acb_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 {$wpdb->prefix}acb_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) { return $existing_user->id; } else { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Failed to update user: ' . esc_attr( $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; // Immediately make this user available to other users by triggering a refresh $this->notify_user_list_update(); return $new_user_id; } else { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Failed to create user: ' . esc_attr( $user_email ) . ' Error: ' . esc_attr( $wpdb->last_error ) ); } return false; } } } /** * Notify that user list should be updated (for real-time updates) */ private function notify_user_list_update() { set_transient( 'acb_user_list_updated', time(), 60 ); } /** * Save message to database * * @since 1.0.0 */ public function save_message() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error( [ 'message' => __( 'Security check failed.','admin-chat-box' ) ] ); wp_die(); } $required_fields = [ 'user_id', 'user_name', 'message' ]; foreach ( $required_fields as $field ) { if ( ! isset( $_POST[ $field ] ) || '' === trim( $_POST[ $field ] ) ) { wp_send_json_error( [ 'message' => sprintf( __( 'Missing required field: %s','admin-chat-box' ), esc_html( $field ) ) ] ); wp_die(); } } $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'] ) ); $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'] ) ) : ''; if ( ! empty( $user_email ) && ! is_email( $user_email ) ) { wp_send_json_error( [ 'message' => __( 'Invalid email format.','admin-chat-box' ) ] ); wp_die(); } if ( empty( $user_id ) || empty( $user_name ) || empty( $message ) ) { wp_send_json_error( [ 'message' => __( 'Invalid data provided.','admin-chat-box' ) ] ); wp_die(); } $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.','admin-chat-box' ), ] ); } else { wp_send_json_error( [ 'message' => __( 'Failed to save message.','admin-chat-box' ) ] ); } wp_die(); } /** * 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) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Table does not exist: ' . esc_attr( $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() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error( [ 'message' => __( 'Security check failed.','admin-chat-box' ) ] ); wp_die(); } $limit = isset( $_POST['limit'] ) ? absint( $_POST['limit'] ) : 50; $offset = isset( $_POST['offset'] ) ? absint( $_POST['offset'] ) : 0; $limit = min( max( $limit, 1 ), 100 ); global $wpdb; $table_messages = $wpdb->prefix . 'acb_messages'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_messages ) ) !== $table_messages ) { wp_send_json_error( [ 'message' => __( 'Messages table does not exist.','admin-chat-box' ) ] ); wp_die(); } $messages = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}acb_messages ORDER BY created_at DESC LIMIT %d OFFSET %d", $limit, $offset ) ); if ( false === $messages ) { wp_send_json_error( [ 'message' => __( 'Failed to retrieve messages.','admin-chat-box' ) ] ); wp_die(); } $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 ), '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( wp_date( 'M d, Y > h:i A', strtotime( $message->created_at ) ) ), ]; } wp_send_json_success( [ 'messages' => array_reverse( $formatted_messages ), 'total' => count( $formatted_messages ), ] ); wp_die(); } /** * Get users from database * * @since 1.0.0 */ public function get_users() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'acb_nonce' ) ) { wp_send_json_error( [ 'message' => __( 'Security check failed.','admin-chat-box' ) ] ); wp_die(); } global $wpdb; $table_users = $wpdb->prefix . 'acb_users'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_users ) ) !== $table_users ) { wp_send_json_error( [ 'message' => __( 'Users table does not exist.','admin-chat-box' ) ] ); wp_die(); } $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 {$wpdb->prefix}acb_users WHERE firebase_uid != %s ORDER BY last_seen DESC", $current_user_uid ) ); } else { $users = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}acb_users ORDER BY last_seen DESC" ); } if ( false === $users ) { wp_send_json_error( [ 'message' => __( 'Failed to retrieve users.','admin-chat-box' ) ] ); wp_die(); } $formatted_users = []; foreach ( $users as $user ) { $last_seen_time = strtotime( $user->last_seen ); $is_online = ( time() - $last_seen_time ) < 120; $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( wp_date( 'M d, Y > h:i A', strtotime( $user->last_seen ) ) ) ]; } wp_send_json_success( [ 'users' => $formatted_users, 'total' => count( $formatted_users ), 'timestamp' => time(), ] ); wp_die(); } /** * 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) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Table does not exist: ' . esc_attr( $table_users ) ); } return null; } return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}acb_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) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log( 'ACB Firebase Service - Table does not exist: ' . esc_attr( $table_users ) ); } return false; } $result = $wpdb->update( $table_users, ['last_seen' => current_time('mysql')], ['firebase_uid' => $firebase_uid], ['%s'], ['%s'] ); return $result !== false; } }