Files
ludikevent_crm/src/Controller/StController.php
Serreau Jovann 4c14932fee ```
 feat(Devis.php): Ajoute adresses de facturation et de livraison au devis.

🔒️ fix(IntranetLocked.php): Autorise l'accès à la route st_control en mode debug.

 feat(CustomerAddress.php): Gère les adresses de facturation et livraison.

 feat: Ajoute la console superadmin pour le contrôle système.

 feat(DevisController.php): Supprime la génération PDF temporaire.

 feat(st_control.js): Ajoute la logique de contrôle système via JS.

 feat: Crée les templates CGV, Cookies, Hébergement et RGPD.

🎨 style(app.scss): Ajoute un style de fond pour la console.

 feat: Ajoute le template pour les informations d'hébergement.

 feat: Crée un template de mail d'alerte pour les accès root.

 feat: Crée le template RGPD (données personnelles).

🐛 fix(ErrorListener.php): Gère les erreurs 404 en prod (JSON/HTML).

 feat: Ajoute les mentions légales.

 feat(DevisPdfService.php): Améliore la génération PDF du devis.

 feat(admin.js): Charge dynamiquement les produits dans le select.

 feat(add.twig): Ajoute un sélecteur de produit et d'autres champs.

 chore(config): Ajoute INTRANET_LOCK à l'env.
```
2026-01-19 13:52:41 +01:00

151 lines
5.7 KiB
PHP

<?php
namespace App\Controller;
use App\Service\Mailer\Mailer;
use App\Service\Signature\Client;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Process\Process;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class StController extends AbstractController
{
private Mailer $mailer;
#[Route('/st_control', name: 'str_control')]
public function stControl(
Request $request, Mailer $mailer,
Client $signatureClient,
\App\Service\Search\Client $searchClient,
\App\Service\Stripe\Client $stripeClient,
): Response
{
$this->mailer = $mailer; // Initialisation pour sendAlert()
$appEnv = $this->getParameter('kernel.environment');
$clientIp = $request->headers->get('cf-connecting-ip') ?? $request->getClientIp();
$host = $request->getHost();
// 1. GESTION DU MODE DEV
if ($appEnv === 'dev') {
if ($host !== 'esyweb.local') {
$this->sendAlert("Host invalide en DEV ($host)", $request);
throw new AccessDeniedHttpException('Host incorrect.');
}
$isLocal = ($clientIp === '127.0.0.1' || $clientIp === '::1');
$isSpecificRange = str_starts_with($clientIp, '172.');
if (!$isLocal && !$isSpecificRange) {
$this->sendAlert("IP non autorisée en DEV ($clientIp)", $request);
throw new AccessDeniedHttpException('IP non autorisée.');
}
}
// 2. GESTION DU MODE PROD (Cloudflare)
else {
if (!$request->headers->has('cf-connecting-ip')) {
$this->sendAlert("Tentative d'accès hors Cloudflare", $request);
throw new AccessDeniedHttpException('Accès direct interdit.');
}
}
// 3. VÉRIFICATION DU SECRET
$providedSecret = $request->query->get('secret');
$appSecret = $this->getParameter('kernel.secret');
if (!$providedSecret || $providedSecret !== $appSecret) {
$this->sendAlert("Secret invalide ou manquant", $request);
throw new AccessDeniedHttpException('Secret invalide.');
}
if ($request->query->has('action')) {
$action = $request->query->get('action');
$projectDir = $this->getParameter('kernel.project_dir');
$command = null;
if ($action === 'cache_clear') {
$command = ['php', $projectDir . '/bin/console', 'cache:clear', '--env=' . $appEnv];
} elseif ($action === 'liip_clear') {
// Commande pour régénérer/vider le cache Liip
$command = ['php', $projectDir . '/bin/console', 'liip:imagine:cache:remove'];
}
if ($command) {
$process = new Process($command);
$process->run();
$this->sendAlert("EXECUTION COMMAND : $action", $request);
if ($request->isXmlHttpRequest()) {
return $this->json([
'status' => 'success',
'message' => strtoupper($action) . ' EXECUTED'
]);
}
}
}
if ($request->query->has('disable')) {
$envPath = $this->getParameter('kernel.project_dir') . '/.env.local';
$disable = $request->query->get('disable');
// Définition de l'état et du message
$isLocking = ($disable === '1');
$newValue = $isLocking ? "true" : "false";
$logMsg = $isLocking ? "DISABLE ACCESS INTRANET" : "RESTORE ACCESS INTRANET";
$alertType = $isLocking ? "SUSPENSION CRITIQUE" : "RESTAURATION ACCÈS";
if (file_exists($envPath)) {
$envContent = file_get_contents($envPath);
// Mise à jour du fichier .env.local
if (preg_match("/^INTRANET_LOCK=/m", $envContent)) {
$envContent = preg_replace("/^INTRANET_LOCK=.*/m", "INTRANET_LOCK=$newValue", $envContent);
} else {
$envContent .= "\nINTRANET_LOCK=$newValue";
}
file_put_contents($envPath, $envContent);
// --- ENVOI DE L'ALERTE ---
$this->sendAlert("ACTION ROOT : $alertType (IP: $clientIp)", $request);
if ($request->isXmlHttpRequest()) {
return $this->json([
'status' => 'success',
'message' => $logMsg,
'lock' => $newValue
]);
}
}
}
return $this->render('root/console.twig',[
'signatureStatus' => $signatureClient->status(),
'stripeStatus' => $stripeClient->status(),
'searchClient' => $searchClient->status(),
]);
}
/**
* Centralise les alertes de sécurité par email
*/
private function sendAlert(string $reason, Request $request): void
{
$clientIp = $request->headers->get('cf-connecting-ip') ?? $request->getClientIp();
$this->mailer->send(
'notification@siteconseil.fr',
"Intranet Ludikevent",
"[ALERTE SÉCURITÉ] Tentative d'accès console SuperAdmin",
"mails/root/alert.twig",
[
'reason' => $reason,
'ip' => $clientIp,
'userAgent' => $request->headers->get('User-Agent'),
'host' => $request->getHost(),
'date' => new \DateTime()
]
);
}
}