diff --git a/index.php b/index.php
index ef041bc..ca3a832 100644
--- a/index.php
+++ b/index.php
@@ -1,243 +1,260 @@
- 500) {
- return false;
- }
- return $msg;
-}
-
-/* =======================
- ANTI PROMPT INJECTION
-======================= */
-function isPromptInjection(string $msg): bool {
- // regex solide : détecte toutes les tentatives d'instructions systèmes, "ignore", "révèle", "prompt", etc.
- $pattern = '/\b(ignore|oublie|révèle|prompt|instructions?|system|agis comme|tu es maintenant|roleplay|administrateur)\b/i';
- return preg_match($pattern, $msg) === 1;
-}
-
-/* =======================
- API CALL
-======================= */
-function callDeepSeekAPI(string $userMessage): string {
- $payload = [
- 'model' => 'deepseek-chat',
- 'messages' => [
- ['role' => 'system', 'content' => SYSTEM_PROMPT],
- ['role' => 'user', 'content' => $userMessage]
- ],
- 'max_tokens' => 800,
- 'temperature' => 0,
- 'top_p' => 1
- ];
-
- $ch = curl_init('https://api.deepseek.com/v1/chat/completions');
- curl_setopt_array($ch, [
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_POST => true,
- CURLOPT_POSTFIELDS => json_encode($payload),
- CURLOPT_HTTPHEADER => [
- 'Content-Type: application/json',
- 'Authorization: Bearer ' . API_KEY
- ],
- CURLOPT_TIMEOUT => 15
- ]);
-
- $response = curl_exec($ch);
- $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
-
- if ($http !== 200 || !$response) {
- return 'Erreur du service.';
- }
-
- $json = json_decode($response, true);
- return $json['choices'][0]['message']['content'] ?? 'Erreur de réponse.';
-}
-
-/* =======================
- AJAX HANDLER
-======================= */
-if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
-
- if (!isAjax()) {
- http_response_code(403);
- echo json_encode(['error' => 'Requête interdite']);
- exit;
- }
-
- if (!isset($_POST['csrf']) || $_POST['csrf'] !== $_SESSION['csrf']) {
- http_response_code(403);
- echo json_encode(['error' => 'CSRF invalide']);
- exit;
- }
-
- if ($_SESSION['message_count'] >= 1) {
- echo json_encode(['error' => 'LIMIT_REACHED']);
- exit;
- }
-
- $message = sanitizeMessage($_POST['message']);
- if ($message === false) {
- echo json_encode(['error' => 'Message invalide']);
- exit;
- }
-
- // anti prompt injection
- if (isPromptInjection($message)) {
- echo json_encode(['response' => 'Demande à Bouchra.']);
- exit;
- }
-
- $_SESSION['message_count']++;
-
- $reply = callDeepSeekAPI($message);
-
- echo json_encode([
- 'response' => $reply
- ]);
- exit;
-}
-?>
-
-
-
-
-
-Assistant IA
-
-
-
-
-
-
-
-
-
-
-
- Bonjour, comment puis‑je vous aider ?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ 500) return false;
+ return $msg;
+}
+
+/* =======================
+ VALIDATION CARACTERES
+======================= */
+function hasInvalidCharacters(string $msg): bool {
+ // Bloque TOUS les caractères spéciaux sauf ?, !, . - et '
+ // Accepte : lettres, chiffres, espaces, et {?, !, ., -, '}
+ return preg_match('/[^a-zA-Z0-9À-ÿ\s\?\!\.\-\']/u', $msg) === 1;
+}
+
+/* =======================
+ VERBES D'ACTION INTERDITS
+======================= */
+function hasBlockedVerbs(string $msg): bool {
+ // Bloque les verbes qui demandent une action spécifique à l'IA
+ $blockedVerbs = [
+ 'montre', 'affiche', 'révèle', 'expose',
+ 'donne', 'envoie', 'fournis', 'transmets',
+ 'répète', 'résume', 'reformule', 'paraphrase', 'récite',
+ 'dis-moi', 'dis moi', 'raconte', 'explique', 'CTF', 'CTFM1'
+ ];
+
+ $msg_lower = mb_strtolower($msg);
+
+ foreach ($blockedVerbs as $verb) {
+ if (preg_match('/\b' . preg_quote($verb) . '\b/i', $msg) === 1) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* =======================
+ MOTS SENSIBLES INTERDITS
+======================= */
+function hasBlockedWords(string $msg): bool {
+ // Bloque les mots sensibles qui demandent des infos confidentielles
+ $blockedWords = [
+ 'flag', 'ctf',
+ 'token', 'secret', 'clé', 'key',
+ 'motdepasse', 'mot de passe', 'password',
+ 'prompt', 'instruction', 'système', 'system', 'règle', 'consigne'
+ ];
+
+ $msg_lower = mb_strtolower($msg);
+
+ foreach ($blockedWords as $word) {
+ if (preg_match('/\b' . preg_quote($word) . '\b/i', $msg) === 1) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/* =======================
+ RATE LIMITING
+======================= */
+function checkRateLimit(): bool {
+ $now = time();
+ $window_start = $now - RATE_WINDOW;
+
+ $_SESSION['messages_timestamps'] = array_values(
+ array_filter($_SESSION['messages_timestamps'], fn($ts) => $ts > $window_start)
+ );
+
+ if (count($_SESSION['messages_timestamps']) >= RATE_LIMIT) return false;
+
+ $_SESSION['messages_timestamps'][] = $now;
+ return true;
+}
+
+/* =======================
+ APPEL LLaMA via Ollama
+======================= */
+function callLlamaAPI(string $userMessage): string {
+ // Vérifications de sécurité avec messages explicites
+
+ if (hasInvalidCharacters($userMessage)) {
+ return "Je ne répondrai pas car certains caractères spéciaux sont interdits (sauf ?, !, ., - et '). Demande à Bouchra si tu veux savoir pourquoi.";
+ }
+
+ if (hasBlockedVerbs($userMessage)) {
+ return "Je ne répondrai pas car ce message contient un verbe d'action interdit (montre, donne, répète, etc). Demande à Bouchra si tu veux savoir pourquoi.";
+ }
+
+ if (hasBlockedWords($userMessage)) {
+ return "Je ne répondrai pas car ce message contient un mot sensible (flag, token, prompt, etc). Demande à Bouchra si tu veux savoir pourquoi.";
+ }
+
+ $payload = [
+ 'model' => 'llama2:7b',
+ 'messages' => [
+ ['role'=>'system', 'content'=> SYSTEM_PROMPT],
+ ['role'=>'user', 'content'=> $userMessage],
+ ],
+ 'max_tokens' => 800,
+ 'temperature' => 0.7
+ ];
+
+ $ch = curl_init('http://localhost:11434/v1/chat/completions');
+ curl_setopt_array($ch, [
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => json_encode($payload),
+ CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
+ CURLOPT_TIMEOUT => 300
+ ]);
+
+ $response = curl_exec($ch);
+ $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $error = curl_error($ch);
+ curl_close($ch);
+
+ // DEBUG: Log l'erreur
+ error_log("Ollama API - HTTP: $http, Error: $error, Response: " . substr($response, 0, 200));
+
+ if ($error) {
+ return "Erreur de connexion à Ollama: $error";
+ }
+
+ if ($http !== 200) {
+ return "Erreur Ollama (HTTP $http). Vérifiez que le service tourne sur localhost:11434";
+ }
+
+ if (!$response) {
+ return "Pas de réponse du service LLaMA.";
+ }
+
+ $json = json_decode($response, true);
+
+ if (!$json || !isset($json['choices'][0]['message']['content'])) {
+ error_log("JSON decode error: " . json_last_error_msg());
+ return "Erreur: réponse LLaMA malformée.";
+ }
+
+ return $json['choices'][0]['message']['content'];
+}
+
+/* =======================
+ AJAX HANDLER
+======================= */
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
+
+ if (!isAjax()) { http_response_code(403); echo json_encode(['error'=>'Requête interdite']); exit; }
+ if (!isset($_POST['csrf']) || $_POST['csrf'] !== $_SESSION['csrf']) { http_response_code(403); echo json_encode(['error'=>'CSRF invalide']); exit; }
+ if (!checkRateLimit()) { http_response_code(429); echo json_encode(['error'=>'LIMIT_REACHED']); exit; }
+
+ $message = sanitizeMessage($_POST['message']);
+ if ($message === false) { echo json_encode(['error'=>'Message invalide']); exit; }
+
+ $reply = callLlamaAPI($message);
+ echo json_encode(['response'=>$reply]);
+ exit;
+}
+
+?>
+
+
+
+
+
+
+bobentaz
+
+
+
+
+
+
+
+
+
+
+
Bonjour, comment puis‑je vous aider ?
+
+
+
+
+
+
+
+
+
+