| @@ -25,8 +25,9 @@ | ||
| 25 | 25 | const ACTION_BOT_REPLY = 'bot_reply'; |
| 26 | 26 | const ACTION_SUGGEST_REPLY = 'suggest_reply'; |
| 27 | 27 | const ACTION_ANALYTICS_INSIGHTS = 'analytics_insights'; |
| 28 | 28 | const ACTION_CONTENT_INDEXING = 'content_indexing'; |
| 29 | + const ACTION_KNOWLEDGE_INDEXING = 'knowledge_indexing'; | |
| 29 | 30 | const ACTION_BATCH_EMBEDDING = 'batch_embedding'; |
| 30 | 31 | const ACTION_QUEUE_PROCESSING = 'queue_processing'; |
| 31 | 32 | const ACTION_SPAM_DETECTION = 'spam_detection'; |
| 32 | 33 | const ACTION_MODERATION = 'moderation'; |
| @@ -97,9 +98,9 @@ | ||
| 97 | 98 | 'error_message' => null, |
| 98 | 99 | 'duration_ms' => 0, |
| 99 | 100 | 'ip_address' => $this->get_client_ip(), |
| 100 | 101 | 'extra_data' => null, |
| 101 | - 'created' => current_time( 'mysql' ), | |
| 102 | + 'created' => current_time( 'mysql', true ), // UTC for timezone conversion | |
| 102 | 103 | ]; |
| 103 | 104 | |
| 104 | 105 | $data = wp_parse_args( $data, $defaults ); |
| 105 | 106 | |
| @@ -1492,36 +1493,15 @@ | ||
| 1492 | 1493 | |
| 1493 | 1494 | /** |
| 1494 | 1495 | * Get client IP address |
| 1495 | 1496 | * |
| 1497 | + * Uses REMOTE_ADDR only to prevent IP spoofing via X-Forwarded-For headers. | |
| 1498 | + * | |
| 1496 | 1499 | * @return string|null |
| 1497 | 1500 | */ |
| 1498 | 1501 | private function get_client_ip() { |
| 1499 | - $ip_keys = [ | |
| 1500 | - 'HTTP_CF_CONNECTING_IP', | |
| 1501 | - 'HTTP_CLIENT_IP', | |
| 1502 | - 'HTTP_X_FORWARDED_FOR', | |
| 1503 | - 'HTTP_X_FORWARDED', | |
| 1504 | - 'HTTP_X_CLUSTER_CLIENT_IP', | |
| 1505 | - 'HTTP_FORWARDED_FOR', | |
| 1506 | - 'HTTP_FORWARDED', | |
| 1507 | - 'REMOTE_ADDR', | |
| 1508 | - ]; | |
| 1509 | - | |
| 1510 | - foreach ( $ip_keys as $key ) { | |
| 1511 | - if ( ! empty( $_SERVER[ $key ] ) ) { | |
| 1512 | - $ip = sanitize_text_field( $_SERVER[ $key ] ); | |
| 1513 | - // Handle comma-separated list (X-Forwarded-For) | |
| 1514 | - if ( strpos( $ip, ',' ) !== false ) { | |
| 1515 | - $ip = trim( explode( ',', $ip )[0] ); | |
| 1516 | - } | |
| 1517 | - if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) { | |
| 1518 | - return $ip; | |
| 1519 | - } | |
| 1520 | - } | |
| 1521 | - } | |
| 1522 | - | |
| 1523 | - return null; | |
| 1502 | + $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? '' ) ); | |
| 1503 | + return filter_var( $ip, FILTER_VALIDATE_IP ) ? $ip : null; | |
| 1524 | 1504 | } |
| 1525 | 1505 | |
| 1526 | 1506 | /** |
| 1527 | 1507 | * Get action type display label |
| @@ -1540,8 +1520,9 @@ | ||
| 1540 | 1520 | self::ACTION_BOT_REPLY => __( 'Bot Reply', 'wpforo' ), |
| 1541 | 1521 | self::ACTION_SUGGEST_REPLY => __( 'Suggest Reply', 'wpforo' ), |
| 1542 | 1522 | self::ACTION_ANALYTICS_INSIGHTS => __( 'Analytics Insights', 'wpforo' ), |
| 1543 | 1523 | self::ACTION_CONTENT_INDEXING => __( 'Content Indexing', 'wpforo' ), |
| 1524 | + self::ACTION_KNOWLEDGE_INDEXING => __( 'Knowledge Indexing', 'wpforo' ), | |
| 1544 | 1525 | self::ACTION_BATCH_EMBEDDING => __( 'Batch Embedding', 'wpforo' ), |
| 1545 | 1526 | self::ACTION_QUEUE_PROCESSING => __( 'Queue Processing', 'wpforo' ), |
| 1546 | 1527 | self::ACTION_SPAM_DETECTION => __( 'Spam Detection', 'wpforo' ), |
| 1547 | 1528 | self::ACTION_MODERATION => __( 'Moderation', 'wpforo' ), |
| @@ -1569,8 +1550,9 @@ | ||
| 1569 | 1550 | self::ACTION_BOT_REPLY => __( 'Bot Reply', 'wpforo' ), |
| 1570 | 1551 | self::ACTION_SUGGEST_REPLY => __( 'Suggest Reply', 'wpforo' ), |
| 1571 | 1552 | self::ACTION_ANALYTICS_INSIGHTS => __( 'Analytics Insights', 'wpforo' ), |
| 1572 | 1553 | self::ACTION_CONTENT_INDEXING => __( 'Content Indexing', 'wpforo' ), |
| 1554 | + self::ACTION_KNOWLEDGE_INDEXING => __( 'Knowledge Indexing', 'wpforo' ), | |
| 1573 | 1555 | self::ACTION_SPAM_DETECTION => __( 'Spam Detection', 'wpforo' ), |
| 1574 | 1556 | self::ACTION_MODERATION => __( 'Moderation', 'wpforo' ), |
| 1575 | 1557 | self::ACTION_TASK_EXECUTION => __( 'Task Execution', 'wpforo' ), |
| 1576 | 1558 | ]; |