Code index php

Depuis votre terminal, connectez-vous a votre Raspberry PI et rentrez la commande suivante pour créer le fichier index.php.

sudo nano /var/www/html/index.php

Copier le code suivant et coller le dans le fichier qui vient de s'ouvrir..

<?php
// Force le fuseau horaire sur Europe/Paris
date_default_timezone_set('Europe/Paris');

session_start();

// --- CONFIGURATION CRITIQUE ---
define('PIN_HASH_STORAGE', 'Remplacer ce texte par le hash de votre code pin'); 
define('MAX_ATTEMPTS', 3);
define('BLACKLIST_FILE', '/var/www/html/data/ip_blacklist.json');
define('LOG_FILE', '/var/log/camera_status.log');
// ------------------------------

// >> SYSTÈME ANTI-BRUTE FORCE PHP <<

$client_ip = $_SERVER['REMOTE_ADDR'];

function get_blacklist() {
    if (file_exists(BLACKLIST_FILE)) {
        $data = file_get_contents(BLACKLIST_FILE);
        return json_decode($data, true) ?: [];
    }
    return [];
}

function is_ip_blacklisted($ip) {
    $blacklist = get_blacklist();
    return isset($blacklist[$ip]);
}

if (!isset($_SESSION['pin_attempts'])) {
    $_SESSION['pin_attempts'] = 0;
}

$is_ip_blocked = is_ip_blacklisted($client_ip);
$attempts_exceeded = ($_SESSION['pin_attempts'] >= MAX_ATTEMPTS);

if ($is_ip_blocked || $attempts_exceeded) {
    if (!$is_ip_blocked && $attempts_exceeded) {
        $blacklist = get_blacklist();
        $timestamp = date('Y-m-d H:i:s');
        $blacklist[$client_ip] = ['blocked_time' => $timestamp, 'reason' => 'Tentatives de PIN dépassées'];
        file_put_contents(BLACKLIST_FILE, json_encode($blacklist, JSON_PRETTY_PRINT));
        session_destroy();
    }
    
    header('HTTP/1.0 403 Forbidden');
    echo '<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Accès Refusé</title><style>body { font-family: sans-serif; text-align: center; padding-top: 50px; background-color: #fdd; color: #800; }</style></head><body><h1>❌ ACCÈS TEMPORAIREMENT BLOQUÉ</h1><p>Votre adresse IP a été bloquée pour raisons de sécurité suite à trop de tentatives de connexion échouées.</p><p>Veuillez contacter l\'administrateur pour débloquer votre accès.</p></body></html>';
    exit;
}

// --- LOGIQUE DE VÉRIFICATION DU STATUT DE LA CAMÉRA ---
function get_motioneye_status() {
    $max_attempts = 3;
    $status = 'unknown';

    for ($i = 0; $i < $max_attempts; $i++) {
        $output = shell_exec('STATUS=$(/bin/systemctl is-active motioneye 2>/dev/null); echo "$STATUS"');
        $status = trim($output);
        $status = strtolower($status);
        
        if ($status === 'active' || $status === 'inactive') {
            break;
        }
        sleep(1);
    }
    
    if ($status === 'active') {
        return ['text' => 'ACTIVE', 'class' => 'status-active', 'icon' => '🟢'];
    } elseif ($status === 'inactive') {
        return ['text' => 'INACTIVE', 'class' => 'status-inactive', 'icon' => '🔴'];
    } elseif ($status === 'activating' || $status === 'deactivating') {
        return ['text' => 'EN TRANSITION', 'class' => 'status-error', 'icon' => '🟡'];
    } else {
        return ['text' => 'ERREUR', 'class' => 'status-error', 'icon' => '⚠️'];
    }
}

$status_data = get_motioneye_status();
$page_title = "Alarme Maison";
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo $page_title; ?> - Statut</title>
    <style>
        /* Styles CSS (omission pour la concision) */
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #f0f0f5; color: #333; margin: 0; padding: 20px; text-align: center; }
        h1 { color: #1a1a1a; font-size: 24px; margin-bottom: 30px; }
        .status-box, .control-box { background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); padding: 20px; margin: 20px auto; max-width: 500px; }
        .status-indicator { font-size: 40px; margin-bottom: 10px; }
        .status-text { font-size: 32px; font-weight: bold; text-transform: uppercase; padding: 10px 0; }
        .status-active { color: #007aff; }
        .status-inactive { color: #ff3b30; }
        .status-error { color: #ffcc00; }
        .control-box a { display: block; font-size: 18px; font-weight: 600; padding: 15px 0; margin-bottom: 10px; border-radius: 8px; text-decoration: none; cursor: pointer; transition: background-color 0.2s; }
        .btn-marche { background-color: #34c759; color: white; }
        .btn-arret { background-color: #ff3b30; color: white; }
        .pin-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.8); display: none; justify-content: center; align-items: center; z-index: 1000; }
        .pin-container { background: white; padding: 30px; border-radius: 15px; text-align: center; width: 80%; max-width: 300px; }
        .pin-input { width: 100%; padding: 10px; font-size: 20px; margin: 10px 0 20px; text-align: center; letter-spacing: 5px; }
        
        .log-box { background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); padding: 20px; margin: 20px auto; max-width: 800px; text-align: left;}
        .log-box h2 { margin-top: 0; font-size: 20px; border-bottom: 1px solid #eee; padding-bottom: 10px; color: #1a1a1a; text-align: center;}
        table { width: 100%; border-collapse: collapse; margin-top: 15px; font-size: 0.85em; table-layout: fixed;}
        table th, table td { padding: 10px 8px; text-align: left; border-bottom: 1px solid #ddd; word-wrap: break-word;}
        table th { background-color: #f2f2f2; font-weight: bold; color: #333;}
        .action-start { color: green; font-weight: bold;}
        .action-stop { color: red; font-weight: bold;}
        .action-info { color: #007aff; font-weight: 500; }
        .action-manuel { font-style: italic;}
    </style>
    
    <meta http-equiv="refresh" content="15">
    
</head>
<body>

    <h1><?php echo $page_title; ?></h1>

    <div class="status-box">
        <div class="status-indicator">
            <?php echo $status_data['icon']; ?>
        </div>
        <div class="status-text <?php echo $status_data['class']; ?>">
            <?php echo $status_data['text']; ?>
        </div>
    </div>

    <div class="control-box">
        <h2>Contrôle Manuel</h2>
        <a href="#" class="btn-marche" data-action="marche" onclick="showPin('marche');">
            Caméra MARCHE
        </a>
        <a href="#" class="btn-arret" data-action="arret" onclick="showPin('arret');">
            Caméra ARRÊT
        </a>
    </div>
    
    <div class="last-update">
        Dernière vérification : <?php echo date('H:i:s'); ?>
    </div>

    <div id="pinOverlay" class="pin-overlay">
        <div class="pin-container">
            <h3>Entrez votre code PIN</h3>
            <input type="password" id="pinInput" class="pin-input" maxlength="4" inputmode="numeric" oninput="checkPin();">
            <p style="font-size: 14px; color: #555;">Tentatives restantes: <span id="attempts_left"><?php echo MAX_ATTEMPTS - $_SESSION['pin_attempts']; ?></span></p>
            <p id="pinMessage" style="color: red;"></p>
        </div>
    </div>

    <div class="log-box">
        <h2>Historique des 10 dernières actions</h2>
        <table>
            <thead>
                <tr>
                    <th style="width: 20%;">Date & Heure</th>
                    <th style="width: 20%;">Source</th>
                    <th style="width: 35%;">Action / Mouvement</th>
                    <th style="width: 25%;">Détails</th>
                </tr>
            </thead>
            <tbody>
                <?php
                $log_file = LOG_FILE;
                $log_lines = [];
                $permission_error = false;
                
                if (file_exists($log_file)) {
                    $logs_raw = shell_exec("tail -n 10 " . escapeshellarg($log_file) . " 2>&1");
                    
                    if (strpos($logs_raw, 'Permission denied') !== false) {
                        $permission_error = true;
                    } elseif (!empty($logs_raw)) {
                        $log_lines = array_reverse(array_filter(explode("\n", trim($logs_raw))));
                    }
                }

                if ($permission_error) {
                    echo '<tr><td colspan="4" style="color:red; text-align:center;">Erreur: Accès refusé aux logs. Vérifiez les permissions de ' . htmlspecialchars($log_file) . '.</td></tr>';
                } elseif (!empty($log_lines)) {
                    foreach ($log_lines as $line) {
                        // Regex Ultra-Tolérante : retire la parenthèse fermante optionnelle, capture tout après la première ouvrante s'il y en a une.
                        if (preg_match('/^\[(.*?)\] \[(.*?)\] (.*?)(?: \((.*))?$/', $line, $matches)) {
                            $timestamp = trim($matches[1]);
                            $source = trim($matches[2]);
                            $message = trim($matches[3]);
                            // Utilise $matches[4] ou une chaîne vide si non capturé
                            $details = isset($matches[4]) ? trim($matches[4]) : ''; 
                        } else {
                            echo '<tr><td colspan="4" class="action-info">' . htmlspecialchars($line) . '</td></tr>';
                            continue;
                        }

                        // --- Détermination de la présentation ---
                        $action_text = '';
                        $action_class = 'action-info';
                        $detail_display = 'N/A';
                        $appareil_nom = '';
                        $mouvement = '';

                        // 1. Détermination de l'Action
                        if (strpos($message, 'DÉMARRÉE') !== false) {
                            $action_text = "Activation Caméra (ON)";
                            $action_class = 'action-start';
                        } elseif (strpos($message, 'ARRÊTÉE') !== false) {
                            $action_text = "Désactivation Caméra (OFF)";
                            $action_class = 'action-stop';
                        } else {
                            $action_text = htmlspecialchars($message);
                        }

                        // 3. Extraction des Détails (Nom de l'appareil, Mouvement, etc.)
                        if (!empty($details)) {
                            
                            // 3a. Recherche du mouvement (et mise à jour de l'Action)
                            if (preg_match('/(Premier Entré|Dernier Sorti)/i', $details, $mouv_matches)) {
                                $mouvement = htmlspecialchars($mouv_matches[1]);
                                $mouvement_display = ($mouvement === 'Premier Entré') ? 'Arrivée/Entrée' : 'Départ/Sortie';
                                
                                $action_text = $mouvement_display . " - " . $action_text;
                            }

                            // 3b. Recherche du nom de l'appareil
                            if (preg_match('/(iphone_[a-z0-9_-]+)/i', $details, $device_matches)) {
                                $appareil_nom = htmlspecialchars($device_matches[1]);
                                $detail_display = "Appareil: " . $appareil_nom;

                            } elseif ($source === 'MANUAL' && strpos($message, 'manuellement par l\'interface web') !== false) {
                                $detail_display = 'Interface Web';

                            } else {
                                // Afficher les détails bruts si non reconnu pour le débogage
                                $detail_display = htmlspecialchars($details);
                            }
                        }
                        
                        // 2. Détermination de la Source
                        $source_display = $source;
                        if ($source === 'MANUAL') {
                            $source_display = "Manuel (Web)";
                            $action_class .= ' action-manuel';
                        } elseif ($source === 'RACC. iOS') {
                            $source_display = "Raccourci iOS";
                            $action_class .= ' action-manuel';
                        } elseif ($source === 'AUTO') {
                            $source_display = "Automatique";
                        }
                        
                        // --- Affichage ---
                        echo '<tr>';
                        echo '<td>' . htmlspecialchars($timestamp) . '</td>';
                        echo '<td>' . $source_display . '</td>';
                        echo '<td class="' . $action_class . '">' . $action_text . '</td>';
                        echo '<td>' . $detail_display . '</td>';
                        echo '</tr>';
                    }
                } else {
                    echo '<tr><td colspan="4" style="text-align:center;">Aucun historique récent trouvé.</td></tr>';
                }
                ?>
            </tbody>
        </table>
    </div>


    <script>
        // ... (Le code JavaScript est inchangé et complet)
        const CORRECT_PIN_HASH = "<?php echo PIN_HASH_STORAGE; ?>"; 
        const SECURE_ACTION_URL = "secure_action.php?action=";
        let pendingAction = ''; 
        
        // La fonction sha256 a été omise ici pour la concision mais elle est incluse dans le code à copier/coller.

        function sha256(str) {
            // ... (Fonction complète de sha256)
            function rotateRight(n, count) {
                return (n >>> count) | (n << (32 - count));
            }
            function safeAdd(x, y) {
                const lsw = (x & 0xFFFF) + (y & 0xFFFF);
                const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
                return (msw << 16) | (lsw & 0xFFFF);
            }

            const K = [
                0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
                0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
                0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
                0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
                0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
                0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
                0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
                0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
            ];
            
            let H = [
                0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
            ];

            const utf8 = unescape(encodeURIComponent(str));
            const w = [];
            let i;
            for (i = 0; i < utf8.length * 8; i += 8) {
                w[i >> 5] |= (utf8.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
            }

            w[i >> 5] |= 0x80 << (24 - i % 32);
            w[((i + 64) >>> 9 << 4) + 15] = i;

            for (let j = 0; j < w.length; j += 16) {
                const W = new Array(64);
                let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4], f = H[5], g = H[6], h = H[7];

                for (let t = 0; t < 64; t++) {
                    if (t < 16) {
                        W[t] = w[j + t];
                    } else {
                        const s0 = rotateRight(W[t - 15], 7) ^ rotateRight(W[t - 15], 18) ^ (W[t - 15] >>> 3);
                        const s1 = rotateRight(W[t - 2], 17) ^ rotateRight(W[t - 2], 19) ^ (W[t - 2] >>> 10);
                        W[t] = safeAdd(safeAdd(safeAdd(W[t - 16], s0), W[t - 7]), s1);
                    }
                    
                    const S1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
                    const ch = (e & f) ^ ((~e) & g);
                    const temp1 = safeAdd(safeAdd(safeAdd(safeAdd(h, S1), ch), K[t]), W[t]);
                    const S0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
                    const maj = (a & b) ^ (a & c) ^ (b & c);
                    const temp2 = safeAdd(S0, maj);

                    h = g;
                    g = f;
                    f = e;
                    e = safeAdd(d, temp1);
                    d = c;
                    c = b;
                    b = a;
                    a = safeAdd(temp1, temp2);
                }

                H[0] = safeAdd(a, H[0]);
                H[1] = safeAdd(b, H[1]);
                H[2] = safeAdd(c, H[2]);
                H[3] = safeAdd(d, H[3]);
                H[4] = safeAdd(e, H[4]);
                H[5] = safeAdd(f, H[5]);
                H[6] = safeAdd(g, H[6]);
                H[7] = safeAdd(h, H[7]);
            }
            
            let result = '';
            for (let t = 0; t < H.length; t++) {
                result += H[t].toString(16).padStart(8, '0');
            }
            return result.replace(/[^0-9a-f]/gi, '').toLowerCase(); 
        }

        function showPin(action) {
            pendingAction = action;
            document.getElementById('pinInput').value = ''; 
            document.getElementById('pinMessage').textContent = '';
            document.getElementById('pinOverlay').style.display = 'flex';
            document.getElementById('pinInput').focus();
        }

        function checkPin() {
            const pinInput = document.getElementById('pinInput');
            const pin = pinInput.value;
            const messageElement = document.getElementById('pinMessage');
            
            if (pin.length === 4) { 
                messageElement.textContent = "Vérification...";
                
                // Hachage synchrone
                const hashedInput = sha256(pin); 
                
                if (hashedInput === CORRECT_PIN_HASH) {
                    messageElement.textContent = "Connexion OK. Établissement de la session...";
    
                    fetch('pin_login.php')
                        .then(response => {
                            if (!response.ok) throw new Error("Erreur de connexion (pin_login.php).");
                            return response.json();
                        })
                        .then(data => {
                            if (data.status === 'success') {
                            messageElement.textContent = "Session OK. Exécution...";
                            executeWebhook(pendingAction);
                        } else {
                            messageElement.textContent = "Erreur interne de session.";
                        }
                    })
                    .catch(error => {
                        messageElement.textContent = "Erreur de communication : " + error.message;
                        console.error(error);
                    });
                } else {
                    fetch('pin_failed.php')
                        .then(response => {
                            if (!response.ok) throw new Error("Erreur serveur lors de la tentative échouée.");
                            return response.json();
                        })
                        .then(data => {
                            if (data.status === 'blocked') {
                                window.location.reload(); 
                            } else {
                                messageElement.textContent = "Code PIN incorrect.";
                                pinInput.value = '';
                                document.getElementById('attempts_left').textContent = data.attempts_left;
                            }
                        })
                        .catch(error => {
                            messageElement.textContent = "Erreur de communication avec le serveur (pin_failed.php).";
                            console.error(error);
                        });
                }
            }
        }

        function executeWebhook(action) {
            const finalAction = (action === 'marche' ? 'start' : 'stop');
            const url = "secure_action.php";
    
            fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: 'action=' + finalAction
            })
            .then(response => {
                if (!response.ok) {
                     throw new Error(`Erreur HTTP: ${response.status}. Le serveur relais a échoué.`);
                }
                return response.json();
            })
            .then(data => {
                if (data.status === 'error') {
                    alert(`ERREUR LORS DE L'EXÉCUTION (${data.message}). Clé ou URL invalide.`);
                } else {
                    alert(`Action '${action}' lancée. Statut : ${data.status}. ${data.message}`);
                }
                document.getElementById('pinOverlay').style.display = 'none';
                window.location.reload(); 
            })
            .catch(error => {
                alert('Erreur critique de communication : ' + error);
                document.getElementById('pinOverlay').style.display = 'none';
            });
        }
        
        document.getElementById('pinOverlay').addEventListener('click', function(e) {
            if (e.target === this) {
                this.style.display = 'none';
            }
        });
    </script>
</body>
</html>

 

- Vous devez remplacer la valeur de la variable " PIN_HASH_STORAGE " par le Hash de votre code pin. Pour connaitre la valeur du hash utiliser cette commande en remplacant "1234" par votre code pin.

echo -n "1234" | sha256sum

- Le résultat est "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"

calcul de la valeur Sash