Code admin.php
Depuis votre terminal, connectez-vous a votre Raspberry PI et rentrez la commande suivante pour créer le fichier admin.php.
sudo nano /var/www/html/admin.phpCopier le code suivant et coller le dans le fichier qui vient de s'ouvrir.
<?php
date_default_timezone_set('Europe/Paris');
session_start();
// --- CONFIGURATION CRITIQUE (Doit correspondre à index.php) ---
// PIN sécurisé : Hash qui est COMPATIBLE avec votre fonction SHA-256 en pur JavaScript.
// Remplacer par le hash de votre code pin, valeur actuel '1234'
define('PIN_HASH_STORAGE', 'Remplacer ce texte par le hash de votre code pin');
const MAX_ATTEMPTS = 3;
const BLACKLIST_FILE = '/var/www/html/data/admin_blacklist.json';
const LOG_FILE = '/var/log/camera_status.log';
// --------------------------------------------------------------
// >> FONCTIONS ET LOGIQUE DE SÉCURITÉ 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 save_blacklist($blacklist) {
file_put_contents(BLACKLIST_FILE, json_encode($blacklist, JSON_PRETTY_PRINT));
}
function is_ip_blacklisted($ip) {
$blacklist = get_blacklist();
return isset($blacklist[$ip]);
}
if (!isset($_SESSION['pin_attempts_admin'])) {
$_SESSION['pin_attempts_admin'] = 0;
}
// Vérifie si l'IP est déjà bloquée (liste noire) ou si la limite de tentatives en session est dépassée.
$is_ip_blocked = is_ip_blacklisted($client_ip);
$attempts_exceeded = ($_SESSION['pin_attempts_admin'] >= MAX_ATTEMPTS);
if ($is_ip_blocked || $attempts_exceeded) {
if (!$is_ip_blocked && $attempts_exceeded) {
// Blocage de l'IP si la limite de session est atteinte
$blacklist = get_blacklist();
$timestamp = date('Y-m-d H:i:s');
$blacklist[$client_ip] = ['blocked_time' => $timestamp, 'reason' => 'Tentatives de PIN dépassées (ADMIN)'];
save_blacklist($blacklist);
session_destroy();
}
// Affiche l'erreur 403 et coupe l'accès
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 sur la page d\'administration.</p></body></html>';
exit;
}
// --- GESTION DES ACTIONS (Déblocage) ---
// Le contenu principal est affiché UNIQUEMENT si l'utilisateur est connecté (PIN entré correctement)
$is_admin_logged_in = isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true;
if ($is_admin_logged_in) {
// Logique de gestion du déblocage d'IP (seulement si connecté)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['unblock_ip'])) {
$ip_to_unblock = filter_var($_POST['unblock_ip'], FILTER_VALIDATE_IP);
if ($ip_to_unblock) {
$blacklist = get_blacklist();
if (isset($blacklist[$ip_to_unblock])) {
unset($blacklist[$ip_to_unblock]);
save_blacklist($blacklist);
$timestamp = date('Y-m-d H:i:s');
$log_message = sprintf("[%s] [SECURITY] IP Unblocked: %s by Admin IP: %s\n", $timestamp, $ip_to_unblock, $client_ip);
file_put_contents(LOG_FILE, $log_message, FILE_APPEND | LOCK_EX);
$_SESSION['admin_message'] = "L'IP $ip_to_unblock a été débloquée.";
} else {
$_SESSION['admin_message'] = "Erreur: L'IP $ip_to_unblock n'était pas bloquée.";
}
} else {
$_SESSION['admin_message'] = "Erreur: Format d'IP invalide.";
}
header('Location: admin.php');
exit;
}
}
// Récupère la liste des IP pour l'affichage (si connecté)
$current_blacklist = $is_admin_logged_in ? get_blacklist() : [];
$admin_message = '';
if (isset($_SESSION['admin_message'])) {
$admin_message = $_SESSION['admin_message'];
unset($_SESSION['admin_message']);
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Administration Blocage IP</title>
<style>
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; }
.container { max-width: 600px; margin: 0 auto; background-color: #fff; padding: 20px; border-radius: 12px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); text-align: left; }
h1 { color: #1a1a1a; font-size: 24px; margin-bottom: 20px; text-align: center; }
.ip-list { list-style: none; padding: 0; }
.ip-list li { display: flex; justify-content: space-between; align-items: center; padding: 10px; border-bottom: 1px solid #eee; }
.ip-list li:last-child { border-bottom: none; }
.ip-info { flex-grow: 1; }
.ip-address { font-weight: bold; }
.unblock-btn { background-color: #ff3b30; color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
.unblock-btn:hover { background-color: #cc2e24; }
.message { padding: 10px; margin-bottom: 20px; border-radius: 6px; font-weight: bold; }
.info { background-color: #e6f7ff; color: #007aff; border: 1px solid #007aff; }
/* Styles pour le PIN */
.pin-container { background: white; padding: 30px; border-radius: 15px; text-align: center; width: 80%; max-width: 300px; margin: 50px auto; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
.pin-input { width: 100%; padding: 10px; font-size: 20px; margin: 10px 0 20px; text-align: center; letter-spacing: 5px; }
</style>
</head>
<body>
<?php if (!$is_admin_logged_in): ?>
<div class="pin-container">
<h1>Accès Administration Sécurisé</h1>
<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_admin"><?php echo MAX_ATTEMPTS - $_SESSION['pin_attempts_admin']; ?></span></p>
<p id="pinMessage" style="color: red;"></p>
<p style="margin-top: 30px;"><a href="index.php" style="color:#007aff; text-decoration: none;">← Retour à l'accueil</a></p>
</div>
<?php else: ?>
<div class="container">
<h1>Administration de la Liste Noire (IP: <?php echo htmlspecialchars($client_ip); ?>)</h1>
<?php if ($admin_message): ?>
<div class="message info">
<?php echo htmlspecialchars($admin_message); ?>
</div>
<?php endif; ?>
<h2>Adresses IP Bloquées (<?php echo count($current_blacklist); ?>)</h2>
<?php if (empty($current_blacklist)): ?>
<p>Aucune adresse IP n'est actuellement bloquée.</p>
<?php else: ?>
<ul class="ip-list">
<?php foreach ($current_blacklist as $ip => $data): ?>
<li>
<div class="ip-info">
<span class="ip-address"><?php echo htmlspecialchars($ip); ?></span>
<br>
<small>Bloqué le: <?php echo htmlspecialchars($data['blocked_time'] ?? 'N/A'); ?> (Raison: <?php echo htmlspecialchars($data['reason'] ?? 'Inconnue'); ?>)</small>
</div>
<form method="POST" action="admin.php">
<input type="hidden" name="unblock_ip" value="<?php echo htmlspecialchars($ip); ?>">
<button type="submit" class="unblock-btn">Débloquer</button>
</form>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<p style="text-align: center; margin-top: 30px;"><a href="index.php" style="color:#007aff; text-decoration: none;">← Retour à la page de contrôle</a></p>
</div>
<?php endif; ?>
<script>
// Récupération des constantes PHP
const CORRECT_PIN_HASH = "<?php echo PIN_HASH_STORAGE; ?>";
const is_admin_logged_in = <?php echo json_encode($is_admin_logged_in); ?>;
// N'exécuter le script de PIN que si l'administrateur n'est pas déjà connecté
if (!is_admin_logged_in) {
// La fonction SHA-256 synchrone spécifique à votre projet (copiée de index.php)
function sha256(str) {
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); // Corrected safeAdd
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 checkPin() {
const pinInput = document.getElementById('pinInput');
const pin = pinInput.value;
const messageElement = document.getElementById('pinMessage');
if (pin.length === 4) {
messageElement.textContent = "Vérification...";
const hashedInput = sha256(pin);
if (hashedInput === CORRECT_PIN_HASH) {
messageElement.textContent = "Connexion OK. Redirection...";
// Succès : Appeler un endpoint PHP qui définit la session 'admin_logged_in'
fetch('admin_login.php')
.then(response => {
if (!response.ok) throw new Error("Erreur de connexion.");
return response.json();
})
.then(data => {
if (data.status === 'success') {
window.location.reload(); // Recharger la page pour afficher le panneau
} else {
messageElement.textContent = "Erreur interne de session.";
}
})
.catch(error => {
messageElement.textContent = "Erreur de communication avec le serveur (admin_login.php).";
console.error(error);
});
} else {
// PIN incorrect : Appel au PHP pour incrémenter le compteur de tentatives (pour la page admin)
fetch('pin_failed_admin.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_admin').textContent = data.attempts_left;
}
})
.catch(error => {
messageElement.textContent = "Erreur de communication avec le serveur (pin_failed_admin.php).";
console.error(error);
});
}
}
}
}
</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 remplaçant "1234" par votre code pin.
echo -n "1234" | sha256sum- Le résultat est "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4"
