PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / trunk
AI Engine – The Chatbot, AI Framework & MCP for WordPress vtrunk
3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / classes / services / session.php
ai-engine / classes / services Last commit date
image.php 1 day ago message-builder.php 3 weeks ago model-environment.php 7 months ago response-id-manager.php 1 day ago session.php 11 months ago usage-stats.php 1 month ago
session.php
192 lines
1 <?php
2
3 class Meow_MWAI_Services_Session {
4 private $core;
5 private $nonce = null;
6
7 public function __construct( $core ) {
8 $this->core = $core;
9 }
10
11 public function can_start_session() {
12 // Check if session already started
13 if ( session_status() !== PHP_SESSION_NONE ) {
14 return false;
15 }
16
17 // Check if we're in a context where sessions shouldn't be started
18 if ( wp_doing_cron() || defined( 'DOING_AUTOSAVE' ) ) {
19 return false;
20 }
21
22 // For AI Engine REST endpoints only - check if it's actually our endpoint
23 if ( $this->core->is_rest ) {
24 $request_uri = $_SERVER['REQUEST_URI'] ?? '';
25 // Only start sessions for actual AI Engine endpoints
26 if ( strpos( $request_uri, '/mwai/' ) === false && strpos( $request_uri, 'rest_route=/mwai/' ) === false ) {
27 return false;
28 }
29 }
30
31 // Allow developers to override
32 return apply_filters( 'mwai_allow_session', true );
33 }
34
35 public function get_nonce( $force = false ) {
36 // NONCE GENERATION LOGIC:
37 // - For logged-out users (unless forced): Return null - they must use /start_session endpoint
38 // - For logged-in users: Create user-specific nonce tied to their WP session
39 // - With $force=true: Always create nonce (used by /start_session endpoint)
40 //
41 // This ensures logged-in users get a nonce matching their auth context on page load,
42 // preventing rest_cookie_invalid_nonce errors when cookies are present.
43 if ( !$force && !is_user_logged_in() ) {
44 return null;
45 }
46 if ( isset( $this->nonce ) ) {
47 return $this->nonce;
48 }
49 $this->nonce = wp_create_nonce( 'wp_rest' );
50 return $this->nonce;
51 }
52
53 // ChatID
54 public function fix_chat_id( $query, $params ) {
55 if ( isset( $query->chatId ) && $query->chatId !== 'N/A' ) {
56 return $query->chatId;
57 }
58 $chatId = isset( $params['chatId'] ) ? $params['chatId'] : $query->session;
59 if ( $chatId === 'N/A' ) {
60 $chatId = $this->core->get_random_id( 8 );
61 }
62 $query->set_chat_id( $chatId );
63 return $chatId;
64 }
65
66 public function get_session_id() {
67 // Check if we have the session cookie
68 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
69 return $_COOKIE['mwai_session_id'];
70 }
71
72 // If no cookie exists and we can set one, create it now (lazy initialization)
73 if ( !headers_sent() && !wp_doing_cron() ) {
74 $sessionId = uniqid();
75 @setcookie( 'mwai_session_id', $sessionId, [
76 'expires' => 0,
77 'path' => '/',
78 'secure' => is_ssl(),
79 'httponly' => true,
80 ] );
81 return $sessionId;
82 }
83
84 // For cron jobs or when headers are sent, return a temporary session ID
85 return wp_doing_cron() ? 'wp-cron' : 'N/A';
86 }
87
88 public function get_ip_address( $force = false ) {
89 // Get the actual IP address
90 $ip_keys = [ 'HTTP_CF_CONNECTING_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR',
91 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_FORWARDED_FOR',
92 'HTTP_FORWARDED', 'REMOTE_ADDR' ];
93 $actual_ip = null;
94 foreach ( $ip_keys as $key ) {
95 if ( array_key_exists( $key, $_SERVER ) === true ) {
96 $ips = explode( ',', $_SERVER[$key] );
97 foreach ( $ips as $ip ) {
98 $ip = trim( $ip );
99 if ( $this->validate_ip( $ip ) ) {
100 $actual_ip = $ip;
101 break 2;
102 }
103 }
104 }
105 }
106 if ( !$actual_ip ) {
107 $actual_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
108 }
109
110 // If privacy_first is enabled and not forced, return hashed IP
111 if ( !$force && $this->core->get_option( 'privacy_first' ) ) {
112 // Use a salt that's unique per site but consistent
113 $salt = wp_salt( 'auth' );
114 // Create a hash that's consistent for the same IP but anonymized
115 return 'hashed_' . substr( hash( 'sha256', $actual_ip . $salt ), 0, 16 );
116 }
117
118 return $actual_ip;
119 }
120
121 public function get_user_data() {
122 $user = wp_get_current_user();
123 if ( empty( $user ) || empty( $user->ID ) ) {
124 return null;
125 }
126
127 // Return both the new format (for frontend) and placeholder format (for do_placeholders)
128 $userData = [
129 'ID' => $user->ID,
130 'name' => $user->display_name,
131 'email' => $user->user_email,
132 'avatar' => get_avatar_url( $user->ID ),
133 'type' => 'logged-in',
134 // Add placeholder keys for do_placeholders function
135 'FIRST_NAME' => get_user_meta( $user->ID, 'first_name', true ),
136 'LAST_NAME' => get_user_meta( $user->ID, 'last_name', true ),
137 'USER_LOGIN' => isset( $user->data ) && isset( $user->data->user_login ) ?
138 $user->data->user_login : null,
139 'DISPLAY_NAME' => isset( $user->data ) && isset( $user->data->display_name ) ?
140 $user->data->display_name : null,
141 'AVATAR_URL' => get_avatar_url( $user->ID ),
142 ];
143
144 return $userData;
145 }
146
147 public function get_user_id() {
148 // This function has to be re-thinked for all other API endpoints
149 $userId = null;
150 // If there is a current session, we probably know the current user
151 if ( is_user_logged_in() ) {
152 $userId = get_current_user_id();
153 }
154 // For guest users, return null instead of generating a string ID
155 // This allows the database to store NULL for guests, which displays as "Guest" in the UI
156 return $userId;
157 }
158
159 /**
160 * Get session-based user ID for guest users
161 * This creates a unique identifier based on session ID for tracking guest uploads
162 *
163 * @return string|null Session-based user ID or null if no session
164 */
165 public function get_session_user_id() {
166 $sessionId = $this->get_session_id();
167 if ( !$sessionId || $sessionId === 'N/A' ) {
168 return null;
169 }
170 // Create a consistent user ID based on session
171 // Prefix with 'session_' to distinguish from real user IDs
172 return 'session_' . $sessionId;
173 }
174
175 public function get_admin_user() {
176 $users = get_users( [ 'role' => 'administrator' ] );
177 if ( !empty( $users ) ) {
178 return $users[0];
179 }
180 return null;
181 }
182
183 // Private helper methods
184 private function validate_ip( $ip ) {
185 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false ) {
186 return false;
187 }
188 return true;
189 }
190
191 }
192