]> git.nothing2do.fr Git - diary-web.git/commitdiff
mistral vibe
authorgaby <gaby@nothing2do.fr>
Sun, 19 Apr 2026 21:33:03 +0000 (23:33 +0200)
committergaby <gaby@nothing2do.fr>
Sun, 19 Apr 2026 21:33:03 +0000 (23:33 +0200)
include/Database.php
include/WebAuthnManager.php
public/index.php
public/login.php
public/register.php

index e02607204cd162e98ee883b1024b970b250836d8..e63c0e3662e7ec2d4db479b8a2d187731af50eb5 100644 (file)
@@ -1,35 +1,25 @@
 <?php
-// includes/Database.php
+// include/Database.php
 
 class Database {
-    private $host;
-    private $db_name;
-    private $username;
-    private $password;
     private $conn;
 
     public function __construct() {
-        // Remplace ces valeurs par celles de ta configuration
-        $this->host = 'localhost';
-        $this->db_name = 'ton_nom_de_base';
-        $this->username = 'ton_utilisateur';
-        $this->password = 'ton_mot_de_passe';
+        $this->conn = null;
     }
 
     public function connect() {
-        $this->conn = null;
-
+        // Include configuration
+        require_once __DIR__ . '/../config/config.php';
+        
         try {
-            $dsn = "pgsql:host={$this->host};dbname={$this->db_name}";
-            $this->conn = new PDO($dsn, $this->username, $this->password);
-            $this->conn->exec("set names utf8");
-            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-        } catch(PDOException $exception) {
+            // Use the global $db connection from config.php
+            global $db;
+            return $db;
+        } catch(Exception $exception) {
             echo "Erreur de connexion à la base de données : " . $exception->getMessage();
             exit;
         }
-
-        return $this->conn;
     }
 }
 ?>
index 8c46dcefa5931cbb2437f7d99f0542140ada7844..3db0d5becd1115b306cd2a863c75b7d40ec2d704 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-// includes/WebAuthnManager.php
+// include/WebAuthnManager.php
 
 require_once __DIR__ . '/../vendor/autoload.php';
 
@@ -12,7 +12,8 @@ use Webauthn\{
     PublicKeyCredentialUserEntity,
     PublicKeyCredentialSource,
     AuthenticatorAttestationResponse,
-    AuthenticatorAssertionResponse
+    AuthenticatorAssertionResponse,
+    PublicKeyCredentialRpEntity
 };
 
 class WebAuthnManager {
@@ -21,49 +22,79 @@ class WebAuthnManager {
     private $origin;
 
     public function __construct() {
-        $this->rpName = "Mon Application";
-        $this->rpId = parse_url($_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST);
-        $this->origin = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
+        $this->rpName = WEBAUTHN_RP_NAME;
+        $this->rpId = WEBAUTHN_RP_ID;
+        $this->origin = WEBAUTHN_ORIGIN;
+    }
+
+    public function getRpName() {
+        return $this->rpName;
+    }
+
+    public function getRpId() {
+        return $this->rpId;
+    }
+
+    public function getOrigin() {
+        return $this->origin;
     }
 
     public function generateRegistrationOptions($username) {
+        $rpEntity = new PublicKeyCredentialRpEntity($this->rpName, $this->rpId);
         $userEntity = new PublicKeyCredentialUserEntity(
             $username,
-            random_bytes(16),
+            $username,
             $username
         );
 
         $challenge = random_bytes(32);
 
         $_SESSION['challenge'] = base64_encode($challenge);
+        $_SESSION['username'] = $username;
 
-        return PublicKeyCredentialCreationOptions::create(
-            $this->rpName,
+        $creationOptions = PublicKeyCredentialCreationOptions::create(
+            $rpEntity,
             $userEntity,
             $challenge,
-            [new PublicKeyCredentialDescriptor('public-key', AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_NO_PREFERENCE)]
+            []
+        );
+
+        $creationOptions->authenticatorSelection = new AuthenticatorSelectionCriteria(
+            AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_NO_PREFERENCE,
+            false,
+            AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_PREFERRED
         );
+
+        return $creationOptions;
     }
 
-    public function register($attestationResponse, $username) {
-        if (!isset($_SESSION['challenge'])) {
+    public function register($attestationResponse) {
+        if (!isset($_SESSION['challenge']) || !isset($_SESSION['username'])) {
             return false;
         }
 
         $challenge = base64_decode($_SESSION['challenge']);
+        $username = $_SESSION['username'];
         unset($_SESSION['challenge']);
-
-        $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString($attestationResponse);
-        $publicKeyCredential = $publicKeyCredentialSource->getPublicKeyCredential();
-
-        if (!$publicKeyCredential->verify($challenge, $this->origin)) {
+        unset($_SESSION['username']);
+
+        try {
+            $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString($attestationResponse);
+            $publicKeyCredential = $publicKeyCredentialSource->getPublicKeyCredential();
+
+            if (!$publicKeyCredential->verify($challenge, $this->origin)) {
+                return false;
+            }
+
+            return [
+                'credentialId' => base64_encode($publicKeyCredentialSource->getPublicKeyCredentialId()),
+                'publicKey' => base64_encode($publicKeyCredentialSource->getPublicKey()),
+                'counter' => $publicKeyCredentialSource->getCounter()
+            ];
+        } catch (Exception $e) {
+            error_log("WebAuthn registration error: " . $e->getMessage());
             return false;
         }
-
-        return [
-            'credentialId' => base64_encode($publicKeyCredential->getId()),
-            'publicKey' => base64_encode($publicKeyCredential->getPublicKey())
-        ];
     }
 
     public function generateAuthenticationOptions() {
@@ -71,7 +102,9 @@ class WebAuthnManager {
 
         $_SESSION['challenge'] = base64_encode($challenge);
 
-        return PublicKeyCredentialRequestOptions::create($challenge);
+        $rpEntity = new PublicKeyCredentialRpEntity($this->rpName, $this->rpId);
+        
+        return PublicKeyCredentialRequestOptions::create($rpEntity, $challenge);
     }
 
     public function authenticate($assertionResponse, $storedPublicKey) {
@@ -82,14 +115,20 @@ class WebAuthnManager {
         $challenge = base64_decode($_SESSION['challenge']);
         unset($_SESSION['challenge']);
 
-        $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString($assertionResponse);
-        $publicKeyCredential = $publicKeyCredentialSource->getPublicKeyCredential();
+        try {
+            $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString($assertionResponse);
+            $publicKeyCredential = $publicKeyCredentialSource->getPublicKeyCredential();
+
+            $storedPublicKeyDecoded = base64_decode($storedPublicKey);
 
-        if (!$publicKeyCredential->verify($challenge, $this->origin, base64_decode($storedPublicKey))) {
+            if (!$publicKeyCredential->verify($challenge, $this->origin, $storedPublicKeyDecoded)) {
+                return false;
+            }
+
+            return true;
+        } catch (Exception $e) {
+            error_log("WebAuthn authentication error: " . $e->getMessage());
             return false;
         }
-
-        return true;
     }
-}
-?>
+}
\ No newline at end of file
index 9d2297b7189c71dd00a98bf8b1db590c0e1558bc..1f4686f1f2eeed5868ad4acb4f2d45caa495b584 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 // index.php
 session_start();
-require_once __DIR__ . '/includes/Database.php';
-require_once __DIR__ . '/includes/TripletManager.php';
+require_once __DIR__ . '/../include/Database.php';
+require_once __DIR__ . '/../include/TripletManager.php';
 
 // Initialisation de la base de données
 $db = new Database();
@@ -19,33 +19,111 @@ if (!isset($_SESSION['user_id'])) {
 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
     $action = $_POST['action'];
     $_SESSION['status'] = $action;
+    
+    // Parse action with possible parameters
+    $actionParts = explode(' ', $action, 2);
+    $baseAction = $actionParts[0];
+    $actionParam = $actionParts[1] ?? '';
+    
     // Logique pour chaque type d'action
-    switch ($action) {
+    switch ($baseAction) {
         case "new":
             // Afficher le formulaire pour créer un nouveau triplet
+            $_SESSION['action_mode'] = 'new';
             break;
-        case "input text":
+        case "input":
             // Afficher une boîte de dialogue pour entrer du texte
+            $_SESSION['action_mode'] = 'input';
+            $_SESSION['input_help'] = str_replace('"', '', $actionParam); // Remove quotes
             break;
-        case "box texte":
+        case "box":
             // Afficher une boîte de dialogue avec du texte
+            $_SESSION['action_mode'] = 'box';
+            $_SESSION['box_text'] = $actionParam;
             break;
-        case "set name":
+        case "set":
             // Mettre à jour le nom du triplet
+            $_SESSION['action_mode'] = 'set';
+            $_SESSION['set_name'] = $actionParam;
             break;
-        case "choose keyw":
+        case "choose":
             // Choisir un mot-clé pour le triplet
+            $_SESSION['action_mode'] = 'choose';
+            $_SESSION['choose_keyword'] = $actionParam;
             break;
-        case "edit ID":
+        case "edit":
             // Ouvrir l'éditeur pour le triplet avec l'ID
+            $_SESSION['action_mode'] = 'edit';
+            $_SESSION['edit_id'] = $actionParam;
             break;
         case "configuration":
             // Ouvrir la page de configuration
+            $_SESSION['action_mode'] = 'configuration';
             break;
         default:
-            // Gérer l'action inconnue
+            // Rechercher les triplets contenant le mot-clé
+            if (!empty($action)) {
+                $_SESSION['search_keyword'] = $action;
+                // Filtrer les triplets
+                $filteredTriplets = array_filter($triplets, function($triplet) use ($action) {
+                    return strpos($triplet['keyword'], $action) !== false;
+                });
+                
+                if (!empty($filteredTriplets)) {
+                    $triplets = $filteredTriplets;
+                }
+            }
             break;
     }
+    
+    // Redirection pour éviter le re-post
+    header("Location: index.php");
+    exit();
+}
+
+// Gestion de la création de triplet
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_triplet'])) {
+    $label = trim($_POST['label']);
+    $keyword = trim($_POST['keyword']);
+    $action = trim($_POST['action']);
+    
+    if (!empty($label) && !empty($keyword) && !empty($action)) {
+        $tripletManager->createTriplet($_SESSION['user_id'], $label, $keyword, $action);
+        $_SESSION['status'] = "Triplet créé avec succès!";
+    } else {
+        $_SESSION['status'] = "Tous les champs sont requis!";
+    }
+    
+    header("Location: index.php");
+    exit();
+}
+
+// Gestion de la mise à jour de triplet
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_triplet'])) {
+    $tripletId = intval($_POST['triplet_id']);
+    $label = trim($_POST['label']);
+    $keyword = trim($_POST['keyword']);
+    $action = trim($_POST['action']);
+    
+    if (!empty($label) && !empty($keyword) && !empty($action)) {
+        $tripletManager->updateTriplet($tripletId, $label, $keyword, $action);
+        $_SESSION['status'] = "Triplet mis à jour avec succès!";
+    } else {
+        $_SESSION['status'] = "Tous les champs sont requis!";
+    }
+    
+    header("Location: index.php");
+    exit();
+}
+
+// Gestion de la suppression de triplet
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_triplet'])) {
+    $tripletId = intval($_POST['triplet_id']);
+    $tripletManager->deleteTriplet($tripletId);
+    $_SESSION['status'] = "Triplet supprimé avec succès!";
+    
+    header("Location: index.php");
+    exit();
 }
 
 // Récupération des triplets de l'utilisateur
@@ -99,6 +177,26 @@ if (empty($triplets)) {
             border-radius: 5px;
             box-shadow: 0 2px 5px rgba(0,0,0,0.1);
         }
+        .triplet-actions {
+            margin-top: 10px;
+            padding-top: 10px;
+            border-top: 1px solid #eee;
+        }
+        .triplet-actions button {
+            padding: 5px 10px;
+            margin-left: 5px;
+        }
+        form div {
+            margin-bottom: 10px;
+        }
+        form label {
+            display: inline-block;
+            width: 80px;
+        }
+        form input[type="text"] {
+            padding: 5px;
+            width: 200px;
+        }
         .triplet h3 {
             margin-top: 0;
         }
@@ -126,23 +224,129 @@ if (empty($triplets)) {
     </header>
 
     <div id="status-bar">
-        <?php echo isset($_SESSION['status']) ? htmlspecialchars($_SESSION['status']) : 'Prêt'; ?>
+        <?php 
+        $status = isset($_SESSION['status']) ? $_SESSION['status'] : 'Prêt';
+        unset($_SESSION['status']); // Clear status after showing
+        echo htmlspecialchars($status); 
+        ?>
     </div>
 
+    <!-- Affichage des modes d'action -->
+    <?php if (isset($_SESSION['action_mode'])): ?>
+        <?php 
+        $actionMode = $_SESSION['action_mode'];
+        unset($_SESSION['action_mode']); // Clear after use
+        
+        switch ($actionMode) {
+            case 'new':
+                echo '<section id="newTripletSection">';
+                echo '<h2>Créer un nouveau triplet</h2>';
+                echo '<form method="post">';
+                echo '<div><label>Label:</label><input type="text" name="label" required></div>';
+                echo '<div><label>Mot-clé:</label><input type="text" name="keyword" required></div>';
+                echo '<div><label>Action:</label><input type="text" name="action" required></div>';
+                echo '<button type="submit" name="create_triplet">Créer</button>';
+                echo '<button type="button" onclick="window.location.href=\"index.php\"">Annuler</button>';
+                echo '</form>';
+                echo '</section>';
+                break;
+                
+            case 'input':
+                $helpText = $_SESSION['input_help'] ?? '';
+                unset($_SESSION['input_help']);
+                echo '<section id="inputSection">';
+                echo '<h2>Entrée de texte</h2>';
+                if ($helpText) {
+                    echo '<p>' . htmlspecialchars($helpText) . '</p>';
+                }
+                echo '<form method="post">';
+                echo '<div><input type="text" name="action" required></div>';
+                echo '<button type="submit">Envoyer</button>';
+                echo '<button type="button" onclick="window.location.href=\"index.php\"">Annuler</button>';
+                echo '</form>';
+                echo '</section>';
+                break;
+                
+            case 'box':
+                $boxText = $_SESSION['box_text'] ?? '';
+                unset($_SESSION['box_text']);
+                echo '<section id="boxSection">';
+                echo '<h2>Boîte de dialogue</h2>';
+                echo '<p>' . htmlspecialchars($boxText) . '</p>';
+                echo '<button onclick="window.location.href=\"index.php\"">OK</button>';
+                echo '</section>';
+                break;
+                
+            case 'edit':
+                $tripletId = $_SESSION['edit_id'] ?? 0;
+                unset($_SESSION['edit_id']);
+                $tripletToEdit = null;
+                foreach ($triplets as $triplet) {
+                    if ($triplet['triplet_id'] == $tripletId) {
+                        $tripletToEdit = $triplet;
+                        break;
+                    }
+                }
+                
+                if ($tripletToEdit):
+                    echo '<section id="editTripletSection">';
+                    echo '<h2>Modifier le triplet</h2>';
+                    echo '<form method="post">';
+                    echo '<input type="hidden" name="triplet_id" value="' . $tripletId . '">';
+                    echo '<div><label>Label:</label><input type="text" name="label" value="' . htmlspecialchars($tripletToEdit['label']) . '" required></div>';
+                    echo '<div><label>Mot-clé:</label><input type="text" name="keyword" value="' . htmlspecialchars($tripletToEdit['keyword']) . '" required></div>';
+                    echo '<div><label>Action:</label><input type="text" name="action" value="' . htmlspecialchars($tripletToEdit['action']) . '" required></div>';
+                    echo '<button type="submit" name="update_triplet">Mettre à jour</button>';
+                    echo '<button type="button" onclick="window.location.href=\"index.php\"">Annuler</button>';
+                    echo '</form>';
+                    echo '</section>';
+                else:
+                    echo '<section><p>Triplet non trouvé.</p></section>';
+                endif;
+                break;
+                
+            case 'configuration':
+                echo '<section id="configurationSection">';
+                echo '<h2>Configuration</h2>';
+                echo '<p>Page de configuration (à implémenter)</p>';
+                echo '<button onclick="window.location.href=\"index.php\"">Retour</button>';
+                echo '</section>';
+                break;
+        }
+        ?>
+    <?php else: ?>
+
     <section>
         <h2>Vos Triplets</h2>
-        <?php foreach ($triplets as $triplet): ?>
-            <div class="triplet">
-                <h3><?php echo htmlspecialchars($triplet['label']); ?></h3>
-                <p><strong>Mot-clé :</strong> <?php echo htmlspecialchars($triplet['keyword']); ?></p>
-                <p><strong>Action :</strong> <?php echo htmlspecialchars($triplet['action']); ?></p>
-                <form method="post" style="display: inline;">
-                    <input type="hidden" name="action" value="edit ID">
-                    <input type="hidden" name="triplet_id" value="<?php echo $triplet['triplet_id']; ?>">
-                    <button type="submit">Modifier</button>
-                </form>
-            </div>
-        <?php endforeach; ?>
+        <?php 
+        // Afficher le message de recherche si applicable
+        if (isset($_SESSION['search_keyword'])):
+            echo '<p>Résultats de recherche pour: <strong>' . htmlspecialchars($_SESSION['search_keyword']) . '</strong></p>';
+            unset($_SESSION['search_keyword']);
+        endif;
+        ?>
+        
+        <?php if (empty($triplets)): ?>
+            <p>Aucun triplet trouvé. Créez un nouveau triplet avec l'action "new".</p>
+        <?php else: ?>
+            <?php foreach ($triplets as $triplet): ?>
+                <div class="triplet">
+                    <h3><?php echo htmlspecialchars($triplet['label']); ?></h3>
+                    <p><strong>Mot-clé :</strong> <?php echo htmlspecialchars($triplet['keyword']); ?></p>
+                    <p><strong>Action :</strong> <?php echo htmlspecialchars($triplet['action']); ?></p>
+                    <div class="triplet-actions">
+                        <form method="post" style="display: inline;">
+                            <input type="hidden" name="action" value="edit <?php echo $triplet['triplet_id']; ?>">
+                            <button type="submit">Modifier</button>
+                        </form>
+                        <form method="post" style="display: inline; margin-left: 10px;">
+                            <input type="hidden" name="triplet_id" value="<?php echo $triplet['triplet_id']; ?>">
+                            <button type="submit" name="delete_triplet" onclick="return confirm('Êtes-vous sûr de vouloir supprimer ce triplet ?')">Supprimer</button>
+                        </form>
+                    </div>
+                </div>
+            <?php endforeach; ?>
+        <?php endif; ?>
     </section>
 
     <section>
@@ -151,8 +355,9 @@ if (empty($triplets)) {
             <input type="text" name="action" placeholder="Entrez une action" required>
             <button type="submit">Envoyer</button>
         </form>
-        <p>Exemples d'actions : "new", "input text", "box texte", "set name", "choose keyw", "edit ID", "configuration"</p>
+        <p>Exemples d'actions : "new", "input texte", "box texte", "set name", "choose motcle", "edit ID", "configuration", ou un mot-clé pour rechercher</p>
     </section>
+    <?php endif; // End of action mode check ?>
 
     <footer>
         <p>© 2026 - Application PHP avec YubiKey WebAuthn et PostgreSQL</p>
index 307bf440385daa5f102cf923518fb7edc0cc701e..95fd185854caf92de9cbde8028c3123c04ecc717 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 // login.php (version modernisée)
 session_start();
-require_once __DIR__ . '/../includes/Database.php';
-require_once __DIR__ . '/../includes/WebAuthnManager.php';
+require_once __DIR__ . '/../include/Database.php';
+require_once __DIR__ . '/../include/WebAuthnManager.php';
 
 $db = new Database();
 $pdo = $db->connect();
@@ -16,31 +16,70 @@ if (isset($_SESSION['user_id'])) {
 
 // Traitement du formulaire de connexion
 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-    $username = trim($_POST['username'] ?? '');
-    $yubikeyResponse = trim($_POST['yubikey'] ?? '');
-
-    if (!empty($username) && !empty($yubikeyResponse)) {
-        $stmt = $pdo->prepare("SELECT user_id, yubikey_id FROM users WHERE username = ?");
-        $stmt->execute([$username]);
-        $user = $stmt->fetch(PDO::FETCH_ASSOC);
-
-        if ($user) {
-            $stmt = $pdo->prepare("SELECT key_data, public_key FROM yubikeys WHERE yubikey_id = ?");
-            $stmt->execute([$user['yubikey_id']]);
-            $yubikey = $stmt->fetch(PDO::FETCH_ASSOC);
-
-            if ($yubikey) {
-                $authenticated = $webAuthnManager->authenticate($yubikeyResponse, $yubikey['public_key']);
-                if ($authenticated) {
-                    $_SESSION['user_id'] = $user['user_id'];
-                    $_SESSION['username'] = $username;
-                    $_SESSION['status'] = "Connexion réussie !";
-                    header("Location: index.php");
+    if (isset($_POST['username'])) {
+        // Step 1: Generate authentication options
+        $username = trim($_POST['username']);
+        
+        if (!empty($username)) {
+            $stmt = $pdo->prepare("SELECT user_id, yubikey_id FROM users WHERE username = ?");
+            $stmt->execute([$username]);
+            $user = $stmt->fetch(PDO::FETCH_ASSOC);
+
+            if ($user) {
+                $stmt = $pdo->prepare("SELECT key_data, public_key FROM yubikeys WHERE yubikey_id = ?");
+                $stmt->execute([$user['yubikey_id']]);
+                $yubikey = $stmt->fetch(PDO::FETCH_ASSOC);
+
+                if ($yubikey) {
+                    // Generate authentication options
+                    $authenticationOptions = $webAuthnManager->generateAuthenticationOptions();
+                    $_SESSION['authentication_username'] = $username;
+                    $_SESSION['authentication_user_id'] = $user['user_id'];
+                    $_SESSION['authentication_public_key'] = $yubikey['public_key'];
+                    
+                    header('Content-Type: application/json');
+                    echo json_encode([
+                        'success' => true,
+                        'options' => $authenticationOptions->jsonSerialize()
+                    ]);
                     exit();
                 }
             }
+            
+            header('Content-Type: application/json');
+            echo json_encode(['success' => false, 'error' => 'Nom d\'utilisateur ou YubiKey invalide.']);
+            exit();
         }
-        $error = "Nom d'utilisateur ou réponse YubiKey invalide.";
+    } elseif (isset($_POST['assertionResponse'])) {
+        // Step 2: Process the assertion response
+        $assertionResponse = trim($_POST['assertionResponse']);
+        
+        if (!empty($assertionResponse) && isset($_SESSION['authentication_public_key'])) {
+            $publicKey = $_SESSION['authentication_public_key'];
+            $username = $_SESSION['authentication_username'];
+            $userId = $_SESSION['authentication_user_id'];
+            
+            unset($_SESSION['authentication_public_key']);
+            unset($_SESSION['authentication_username']);
+            unset($_SESSION['authentication_user_id']);
+            
+            // Authenticate the WebAuthn credential
+            $authenticated = $webAuthnManager->authenticate($assertionResponse, $publicKey);
+            
+            if ($authenticated) {
+                $_SESSION['user_id'] = $userId;
+                $_SESSION['username'] = $username;
+                $_SESSION['status'] = "Connexion réussie !";
+                
+                header('Content-Type: application/json');
+                echo json_encode(['success' => true, 'redirect' => 'index.php']);
+                exit();
+            }
+        }
+        
+        header('Content-Type: application/json');
+        echo json_encode(['success' => false, 'error' => 'Échec de l\'authentification YubiKey.']);
+        exit();
     }
 }
 ?>
@@ -190,19 +229,117 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             <div class="error-message"><?php echo htmlspecialchars($error); ?></div>
         <?php endif; ?>
 
-        <form method="post">
+        <form method="post" id="loginForm">
             <div class="form-group">
                 <label for="username">Nom d'utilisateur</label>
                 <input type="text" id="username" name="username" placeholder="Entrez votre nom d'utilisateur" required>
             </div>
 
-            <div class="form-group">
-                <label for="yubikey">Réponse YubiKey</label>
-                <input type="text" id="yubikey" name="yubikey" placeholder="Touchez votre YubiKey" required>
+            <div class="form-group" id="yubikeySection" style="display: none;">
+                <label>Authentification YubiKey</label>
+                <p>Veuillez toucher votre YubiKey pour vous connecter.</p>
+                <div id="webauthnMessage"></div>
             </div>
 
-            <button type="submit" class="login-button">Se connecter</button>
+            <button type="submit" class="login-button" id="loginButton">Se connecter</button>
         </form>
+        
+        <script>
+        document.addEventListener('DOMContentLoaded', function() {
+            const form = document.getElementById('loginForm');
+            const usernameInput = document.getElementById('username');
+            const yubikeySection = document.getElementById('yubikeySection');
+            const loginButton = document.getElementById('loginButton');
+            const webauthnMessage = document.getElementById('webauthnMessage');
+
+            let authenticationOptions = null;
+
+            form.addEventListener('submit', async function(e) {
+                e.preventDefault();
+                
+                if (!usernameInput.value.trim()) {
+                    alert('Veuillez entrer un nom d\'utilisateur');
+                    return;
+                }
+
+                if (authenticationOptions === null) {
+                    // Step 1: Get authentication options
+                    try {
+                        const response = await fetch('login.php', {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/x-www-form-urlencoded',
+                            },
+                            body: `username=${encodeURIComponent(usernameInput.value)}`
+                        });
+
+                        const data = await response.json();
+
+                        if (data.success) {
+                            authenticationOptions = data.options;
+                            usernameInput.disabled = true;
+                            loginButton.disabled = true;
+                            yubikeySection.style.display = 'block';
+                            webauthnMessage.textContent = 'Prêt pour l\'authentification YubiKey...';
+                            
+                            // Step 2: Call WebAuthn API
+                            await startWebAuthnAuthentication();
+                        } else {
+                            alert(data.error || 'Erreur lors de la préparation de la connexion');
+                        }
+                    } catch (error) {
+                        console.error('Error:', error);
+                        alert('Erreur lors de la communication avec le serveur');
+                    }
+                }
+            });
+
+            async function startWebAuthnAuthentication() {
+                try {
+                    webauthnMessage.textContent = 'Veuillez toucher votre YubiKey...';
+                    
+                    // Convert the authentication options to the format expected by the browser
+                    const publicKey = {
+                        challenge: Uint8Array.from(atob(authenticationOptions.challenge), c => c.charCodeAt(0)),
+                        rpId: authenticationOptions.rpId,
+                        timeout: authenticationOptions.timeout,
+                        userVerification: authenticationOptions.userVerification
+                    };
+
+                    // Call the WebAuthn API
+                    const credential = await navigator.credentials.get({ publicKey });
+
+                    if (credential) {
+                        // Send the assertion response to the server
+                        const response = await fetch('login.php', {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/x-www-form-urlencoded',
+                            },
+                            body: `assertionResponse=${encodeURIComponent(JSON.stringify(credential))}`
+                        });
+
+                        const data = await response.json();
+
+                        if (data.success) {
+                            webauthnMessage.textContent = 'Connexion réussie ! Redirection...';
+                            window.location.href = data.redirect;
+                        } else {
+                            webauthnMessage.textContent = data.error || 'Erreur lors de la connexion';
+                            loginButton.disabled = false;
+                        }
+                    } else {
+                        webauthnMessage.textContent = 'Aucune credential reçue';
+                        loginButton.disabled = false;
+                    }
+                } catch (error) {
+                    console.error('WebAuthn error:', error);
+                    webauthnMessage.textContent = 'Erreur YubiKey: ' + error.message;
+                    loginButton.disabled = false;
+                }
+            }
+        });
+        </script>
 
         <div class="link-container">
             <p>Pas encore de compte ? <a href="register.php">S'inscrire</a></p>
index b67ba952f72a674cc1521c93ccec0ae49060ab1c..a1b872ce1105406d638f75a1308381e71b17266c 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 // register.php
 session_start();
-require_once __DIR__ . '/../includes/Database.php';
-require_once __DIR__ . '/../includes/WebAuthnManager.php';
+require_once __DIR__ . '/../include/Database.php';
+require_once __DIR__ . '/../include/WebAuthnManager.php';
 
 $db = new Database();
 $pdo = $db->connect();
@@ -16,18 +16,41 @@ if (isset($_SESSION['user_id'])) {
 
 // Traitement du formulaire d'inscription
 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-    $username = trim($_POST['username'] ?? '');
-    $yubikeyResponse = trim($_POST['yubikey'] ?? '');
-
-    if (!empty($username) && !empty($yubikeyResponse)) {
-        // Vérifier si le nom d'utilisateur existe déjà
-        $stmt = $pdo->prepare("SELECT user_id FROM users WHERE username = ?");
-        $stmt->execute([$username]);
-        if ($stmt->fetch()) {
-            $error = "Ce nom d'utilisateur est déjà pris.";
-        } else {
-            // Générer un défi WebAuthn et enregistrer la nouvelle YubiKey
-            $registrationData = $webAuthnManager->register($yubikeyResponse);
+    if (isset($_POST['username'])) {
+        // Step 1: Generate registration options
+        $username = trim($_POST['username']);
+        
+        if (!empty($username)) {
+            // Vérifier si le nom d'utilisateur existe déjà
+            $stmt = $pdo->prepare("SELECT user_id FROM users WHERE username = ?");
+            $stmt->execute([$username]);
+            if ($stmt->fetch()) {
+                $error = "Ce nom d'utilisateur est déjà pris.";
+            } else {
+                // Generate WebAuthn registration options
+                $registrationOptions = $webAuthnManager->generateRegistrationOptions($username);
+                $_SESSION['registration_options'] = $registrationOptions;
+                $_SESSION['registration_username'] = $username;
+                
+                // Return JSON for JavaScript WebAuthn API
+                header('Content-Type: application/json');
+                echo json_encode([
+                    'success' => true,
+                    'options' => $registrationOptions->jsonSerialize()
+                ]);
+                exit();
+            }
+        }
+    } elseif (isset($_POST['attestationResponse'])) {
+        // Step 2: Process the attestation response
+        $attestationResponse = trim($_POST['attestationResponse']);
+        
+        if (!empty($attestationResponse) && isset($_SESSION['registration_username'])) {
+            $username = $_SESSION['registration_username'];
+            unset($_SESSION['registration_username']);
+            
+            // Register the WebAuthn credential
+            $registrationData = $webAuthnManager->register($attestationResponse);
 
             if ($registrationData) {
                 // Enregistrer l'utilisateur et la YubiKey dans la base de données
@@ -39,8 +62,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                     $userId = $pdo->lastInsertId();
 
                     // Insérer la YubiKey
-                    $stmt = $pdo->prepare("INSERT INTO yubikeys (user_id, key_data) VALUES (?, ?)");
-                    $stmt->execute([$userId, $registrationData['credentialId']]);
+                    $stmt = $pdo->prepare("INSERT INTO yubikeys (user_id, key_data, public_key) VALUES (?, ?, ?)");
+                    $stmt->execute([$userId, $registrationData['credentialId'], $registrationData['publicKey']]);
 
                     // Mettre à jour l'utilisateur avec l'ID de la YubiKey
                     $stmt = $pdo->prepare("UPDATE users SET yubikey_id = ? WHERE user_id = ?");
@@ -49,14 +72,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                     $pdo->commit();
 
                     $_SESSION['status'] = "Inscription réussie ! Vous pouvez maintenant vous connecter.";
-                    header("Location: login.php");
+                    header('Content-Type: application/json');
+                    echo json_encode(['success' => true, 'redirect' => 'login.php']);
                     exit();
                 } catch (Exception $e) {
                     $pdo->rollBack();
-                    $error = "Une erreur est survenue lors de l'inscription : " . $e->getMessage();
+                    header('Content-Type: application/json');
+                    echo json_encode(['success' => false, 'error' => "Une erreur est survenue lors de l'inscription : " . $e->getMessage()]);
+                    exit();
                 }
             } else {
-                $error = "La réponse YubiKey est invalide.";
+                header('Content-Type: application/json');
+                echo json_encode(['success' => false, 'error' => "La réponse YubiKey est invalide."]);
+                exit();
             }
         }
     }
@@ -130,17 +158,118 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
     <?php endif; ?>
 
     <div class="register-form">
-        <form method="post">
+        <form method="post" id="registrationForm">
             <div>
                 <label for="username">Nom d'utilisateur :</label>
                 <input type="text" id="username" name="username" required>
             </div>
-            <div>
-                <label for="yubikey">Réponse YubiKey :</label>
-                <input type="text" id="yubikey" name="yubikey" required>
+            <div id="yubikeySection" style="display: none;">
+                <label>Enregistrement YubiKey :</label>
+                <p>Veuillez toucher votre YubiKey pour compléter l'inscription.</p>
+                <div id="webauthnMessage"></div>
             </div>
-            <button type="submit">S'inscrire</button>
+            <button type="submit" id="registerButton">S'inscrire</button>
         </form>
+        
+        <script>
+        document.addEventListener('DOMContentLoaded', function() {
+            const form = document.getElementById('registrationForm');
+            const usernameInput = document.getElementById('username');
+            const yubikeySection = document.getElementById('yubikeySection');
+            const registerButton = document.getElementById('registerButton');
+            const webauthnMessage = document.getElementById('webauthnMessage');
+
+            let registrationOptions = null;
+
+            form.addEventListener('submit', async function(e) {
+                e.preventDefault();
+                
+                if (!usernameInput.value.trim()) {
+                    alert('Veuillez entrer un nom d\'utilisateur');
+                    return;
+                }
+
+                if (registrationOptions === null) {
+                    // Step 1: Get registration options
+                    try {
+                        const response = await fetch('register.php', {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/x-www-form-urlencoded',
+                            },
+                            body: `username=${encodeURIComponent(usernameInput.value)}`
+                        });
+
+                        const data = await response.json();
+
+                        if (data.success) {
+                            registrationOptions = data.options;
+                            usernameInput.disabled = true;
+                            registerButton.disabled = true;
+                            yubikeySection.style.display = 'block';
+                            webauthnMessage.textContent = 'Prêt pour l\'authentification YubiKey...';
+                            
+                            // Step 2: Call WebAuthn API
+                            await startWebAuthnRegistration();
+                        } else {
+                            alert(data.error || 'Erreur lors de la préparation de l\'inscription');
+                        }
+                    } catch (error) {
+                        console.error('Error:', error);
+                        alert('Erreur lors de la communication avec le serveur');
+                    }
+                }
+            });
+
+            async function startWebAuthnRegistration() {
+                try {
+                    webauthnMessage.textContent = 'Veuillez toucher votre YubiKey...';
+                    
+                    // Convert the registration options to the format expected by the browser
+                    const publicKey = {
+                        challenge: Uint8Array.from(atob(registrationOptions.challenge), c => c.charCodeAt(0)),
+                        rp: registrationOptions.rp,
+                        user: registrationOptions.user,
+                        pubKeyCredParams: registrationOptions.pubKeyCredParams,
+                        authenticatorSelection: registrationOptions.authenticatorSelection,
+                        timeout: registrationOptions.timeout,
+                        attestation: registrationOptions.attestation
+                    };
+
+                    // Call the WebAuthn API
+                    const credential = await navigator.credentials.create({ publicKey });
+
+                    if (credential) {
+                        // Send the attestation response to the server
+                        const response = await fetch('register.php', {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/x-www-form-urlencoded',
+                            },
+                            body: `attestationResponse=${encodeURIComponent(JSON.stringify(credential))}`
+                        });
+
+                        const data = await response.json();
+
+                        if (data.success) {
+                            webauthnMessage.textContent = 'Inscription réussie ! Redirection...';
+                            window.location.href = data.redirect;
+                        } else {
+                            webauthnMessage.textContent = data.error || 'Erreur lors de l\'inscription';
+                            registerButton.disabled = false;
+                        }
+                    } else {
+                        webauthnMessage.textContent = 'Aucune credential reçue';
+                        registerButton.disabled = false;
+                    }
+                } catch (error) {
+                    console.error('WebAuthn error:', error);
+                    webauthnMessage.textContent = 'Erreur YubiKey: ' + error.message;
+                    registerButton.disabled = false;
+                }
+            }
+        });
+        </script>
         <div class="link">
             <p>Déjà un compte ? <a href="login.php">Se connecter</a></p>
         </div>