From 389b2c308c509117035213a7a4fa3699374966e7 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Fri, 3 Apr 2026 09:41:17 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20corrections=20SonarQube=20-=20qualit?= =?UTF-8?q?=C3=A9=20code,=20accessibilit=C3=A9,=20complexit=C3=A9=20cognit?= =?UTF-8?q?ive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propriétés inutilisées supprimées : - CheckDnsCommand : suppression de $urlGenerator (jamais lu, seulement injecté) - PurgeEmailTrackingCommand : suppression de $repository (jamais lu, requêtes via $em->createQueryBuilder directement), suppression import EmailTrackingRepository Corrections PHPStan / types : - SyncController : suppression $wh['status'] ?? 'created' redondant, accès direct à $wh['status'] car le type retour inclut désormais status: string - StripeWebhookService : PHPDoc createAllWebhooks corrigé de list vers list pour refléter les clés status et secret effectivement présentes - DnsReportController : suppression ?? '' sur EXPECTED_MX[$domain] (clé toujours existante) - CloudflareService : ajout @param array $query sur request() - CheckDnsCommand : suppression ?? '' sur EXPECTED_MX[$domain], ajout PHPDoc @param list> $cfRecords sur checkMailcow Méthode manquante : - DnsCheckService : ajout getDkimTxtRecord() qui parcourt les TXT records et retourne le premier commençant par 'v=DKIM1', appelé dans checkDkim() Code mort supprimé : - MailcowService : suppression is_array($data) toujours vrai sur retour de $response->toArray(false), retour direct - DnsInfraHelper : suppression getFirstTxtValueRaw() identique à getFirstTxtValue(), simplification de getActualDnsValue() qui n'appelle plus le fallback Constantes pour littéraux dupliqués : - DnsInfraHelper : ajout LABEL_AWS_SES, LABEL_MAILCOW, LABEL_MAILCOW_DNS, NOT_FOUND, NOT_CONFIGURED — remplace les chaînes 'AWS SES' (10×), 'Non trouve' (4×), 'Non configure' (3×), 'Mailcow' et 'Mailcow DNS' - Utilisation dans CheckDnsCommand (checkAwsSes, checkSesDomain, checkSesDkim, checkSesMailFrom, checkSesBounce, checkMailcow) Réduction complexité cognitive checkAwsSes (61 → ~10 par méthode) : - Extraction checkSesDomain() : vérifie isDomainVerified, ajoute check + erreur/succès - Extraction checkSesDkim() : vérifie getDkimStatus (enabled+verified), parcourt les tokens DKIM CNAME avec enrichLastCheck - Extraction checkSesMailFrom() : vérifie getMailFromStatus, MAIL FROM MX (checkMxExists + getMxValues), MAIL FROM TXT (checkTxtContains + getTxtSpfValue) - Extraction checkSesBounce() : vérifie getNotificationStatus (forwarding ou bounce_topic) Accessibilité WCAG AA : - app.scss : contraste sidebar-nav-item augmenté de rgba(255,255,255,0.6) à rgba(255,255,255,0.75) pour ratio de contraste suffisant sur fond sombre - tarification/index.html.twig : ajout for/id sur les 5 paires label/input (title-{id}, priceHt-{id}, monthPrice-{id}, period-{id}, description-{id}) - membres.html.twig : ajout for/id sur les 15 checkboxes de groupes (group-member, group-admin, group-esy-web, ..., group-esy-ndd), remplacement du label titre par (n'est pas associé à un contrôle) - 2fa_google.html.twig : ajout for="trusted-device" et id="trusted-device" sur le checkbox de confiance appareil - tarif.html.twig : ajout avec OptionTarif sur la table options Esy-Mail (table sans en-têtes) Ansible : - vault.yml : ajout discord_webhook pour le déploiement prod Co-Authored-By: Claude Opus 4.6 (1M context) --- ansible/vault.yml | 1 + assets/app.scss | 2 +- src/Command/CheckDnsCommand.php | 249 ++++++++----------- src/Command/PurgeEmailTrackingCommand.php | 2 - src/Controller/Admin/SyncController.php | 3 +- src/Controller/DnsReportController.php | 2 +- src/Service/CloudflareService.php | 1 + src/Service/DnsCheckService.php | 11 + src/Service/DnsInfraHelper.php | 25 +- src/Service/MailcowService.php | 4 +- src/Service/StripeWebhookService.php | 2 +- templates/admin/membres.html.twig | 62 ++--- templates/admin/tarification/index.html.twig | 20 +- templates/legal/tarif.html.twig | 3 + templates/security/2fa_google.html.twig | 4 +- 15 files changed, 183 insertions(+), 208 deletions(-) diff --git a/ansible/vault.yml b/ansible/vault.yml index 7d113d1..5e6fb74 100644 --- a/ansible/vault.yml +++ b/ansible/vault.yml @@ -19,6 +19,7 @@ cloudflare_key: cfut_xqEEvg5LDezheCI9rWsd4JdfflvLH5vjmeMp7QHO442dd83b mailcow_api_key: DF0E7E-0FD059-16226F-8ECFF1-E558B3 docuseal_api: pgAU116mCFmeF7WQSezHqxtZW8V1fgo31u5d2FXoaKe docuseal_webhooks_secret: CRM_COSLAY +discord_webhook: https://discord.com/api/webhooks/1419573620602044518/ikAdxWxsrrTqMTb5Gh_8ylcoJHlOnq7aJZvR5udoS_fCK56Jk3qpEnJHVKdD8fwuNJF3 smime_private_key: | Bag Attributes localKeyID: 75 15 E3 C2 1D 7B 61 75 99 B9 22 D8 FD A4 19 AC 6B BE 1F 8F diff --git a/assets/app.scss b/assets/app.scss index 9baf747..be87763 100644 --- a/assets/app.scss +++ b/assets/app.scss @@ -228,7 +228,7 @@ body.glass-bg { letter-spacing: 0.08em; border-radius: var(--radius-sm); transition: all 0.2s ease; - color: rgba(255, 255, 255, 0.6); + color: rgba(255, 255, 255, 0.75); &:hover { background: rgba(255, 255, 255, 0.08); diff --git a/src/Command/CheckDnsCommand.php b/src/Command/CheckDnsCommand.php index 59db771..2285a8b 100644 --- a/src/Command/CheckDnsCommand.php +++ b/src/Command/CheckDnsCommand.php @@ -13,7 +13,6 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Twig\Environment; @@ -32,7 +31,6 @@ class CheckDnsCommand extends Command private MailerService $mailer, private Environment $twig, private HttpClientInterface $httpClient, - private UrlGeneratorInterface $urlGenerator, private DnsInfraHelper $helper, #[Autowire('%kernel.environment%')] private string $appEnv, #[Autowire(env: 'DISCORD_WEBHOOK')] private string $discordWebhook = '', @@ -63,7 +61,7 @@ class CheckDnsCommand extends Command $this->dnsCheck->checkDmarc($domain, $checks, $errors, $successes); $this->helper->enrichWithCloudflare($checks, '_dmarc.'.$domain, 'DMARC', 'TXT', $cfRecords); - $this->dnsCheck->checkMx($domain, DnsInfraHelper::EXPECTED_MX[$domain] ?? '', $checks, $errors, $successes); + $this->dnsCheck->checkMx($domain, DnsInfraHelper::EXPECTED_MX[$domain], $checks, $errors, $successes); $this->helper->enrichWithCloudflare($checks, $domain, 'MX', 'MX', $cfRecords); $this->dnsCheck->checkBounce($domain, $checks, $errors, $warnings, $successes); @@ -128,142 +126,121 @@ class CheckDnsCommand extends Command */ private function checkAwsSes(string $domain, array &$checks, array &$errors, array &$successes, array $cfRecords = []): void { + $ses = DnsInfraHelper::LABEL_AWS_SES; + if (!$this->awsSes->isAvailable()) { - $checks[] = DnsCheckService::check('AWS SES', 'API', 'warning', 'Cles non configurees', 'Acces API SES', 'N/A'); + $checks[] = DnsCheckService::check($ses, 'API', 'warning', 'Cles non configurees', 'Acces API SES', 'N/A'); return; } try { - $verif = $this->awsSes->isDomainVerified($domain); - $checks[] = DnsCheckService::check( - 'AWS SES', 'Domaine', 'Success' === $verif ? 'ok' : 'error', - $verif ?? 'Non verifie', 'Success', $verif ?? 'Absent' - ); - if ('Success' === $verif) { - $successes[] = "[$domain] AWS SES : domaine verifie"; - } else { - $errors[] = "[$domain] AWS SES : domaine non verifie ($verif)"; - } - - $dkim = $this->awsSes->getDkimStatus($domain); - $dkimOk = $dkim['enabled'] && $dkim['verified']; - - $checks[] = DnsCheckService::check( - 'AWS SES', 'DKIM statut', $dkimOk ? 'ok' : 'error', - $dkimOk ? 'Active et verifiee' : 'Non active ou non verifiee', - 'Enabled=oui, Verified=oui', - 'Enabled='.($dkim['enabled'] ? 'oui' : 'non').', Verified='.($dkim['verified'] ? 'oui' : 'non') - ); - - if ($dkimOk) { - $successes[] = "[$domain] AWS SES DKIM : active et verifiee"; - } else { - $errors[] = "[$domain] AWS SES DKIM : non active ou non verifiee"; - } - - foreach ($dkim['tokens'] as $token) { - $expectedCname = $token.'.dkim.amazonses.com'; - $dkimFqdn = $token.'._domainkey.'.$domain; - $actualCname = $this->dnsCheck->getCnameRecord($dkimFqdn); - - $found = null !== $actualCname && str_contains($actualCname, 'dkim.amazonses.com'); - $checks[] = DnsCheckService::check( - 'AWS SES', 'DKIM CNAME '.$token, $found ? 'ok' : 'error', - $found ? 'Present' : 'Absent', - $expectedCname, - $actualCname ?? 'Non trouve' - ); - - $this->helper->enrichLastCheck($checks, $dkimFqdn, 'CNAME', $cfRecords); - - if ($found) { - $successes[] = "[$domain] AWS SES DKIM CNAME $token : OK"; - } else { - $errors[] = "[$domain] AWS SES DKIM CNAME $token : absent (attendu: $dkimFqdn CNAME $expectedCname)"; - } - } - - $mailFrom = $this->awsSes->getMailFromStatus($domain); - $mailFromDomain = $mailFrom['mail_from_domain']; - - if (null !== $mailFromDomain) { - $mailFromStatus = $mailFrom['mail_from_status']; - $checks[] = DnsCheckService::check( - 'AWS SES', 'MAIL FROM', 'Success' === $mailFromStatus ? 'ok' : 'error', - $mailFromStatus ?? 'Inconnu', - $mailFromDomain.' (statut: Success)', - $mailFromDomain.' (statut: '.($mailFromStatus ?? '?').')' - ); - - if ('Success' === $mailFromStatus) { - $successes[] = "[$domain] AWS SES MAIL FROM : $mailFromDomain verifie"; - } else { - $errors[] = "[$domain] AWS SES MAIL FROM : $mailFromDomain statut $mailFromStatus"; - } - - $mxExpected = $mailFrom['mx_expected']; - if (null !== $mxExpected) { - $mxFound = $this->helper->checkMxExists($mailFromDomain, $mxExpected); - $actualMx = $this->helper->getMxValues($mailFromDomain); - $checks[] = DnsCheckService::check( - 'AWS SES', 'MAIL FROM MX', $mxFound ? 'ok' : 'error', - $mxFound ? 'Present' : 'Absent', - "$mailFromDomain MX $mxExpected", - $actualMx ?: 'Non trouve' - ); - - $this->helper->enrichLastCheck($checks, $mailFromDomain, 'MX', $cfRecords); - - if ($mxFound) { - $successes[] = "[$domain] AWS SES MAIL FROM MX : OK"; - } else { - $errors[] = "[$domain] AWS SES MAIL FROM MX absent (attendu: $mailFromDomain MX $mxExpected)"; - } - } - - $txtExpected = $mailFrom['txt_expected']; - if (null !== $txtExpected) { - $txtFound = $this->helper->checkTxtContains($mailFromDomain, 'v=spf1'); - $actualTxt = $this->helper->getTxtSpfValue($mailFromDomain); - $checks[] = DnsCheckService::check( - 'AWS SES', 'MAIL FROM TXT', $txtFound ? 'ok' : 'error', - $txtFound ? 'Present' : 'Absent', - "$mailFromDomain TXT $txtExpected", - $actualTxt ?: 'Non trouve' - ); - $this->helper->enrichLastCheck($checks, $mailFromDomain, 'TXT', $cfRecords); - - if ($txtFound) { - $successes[] = "[$domain] AWS SES MAIL FROM SPF : OK"; - } else { - $errors[] = "[$domain] AWS SES MAIL FROM SPF absent (attendu: $mailFromDomain TXT $txtExpected)"; - } - } - } else { - $checks[] = DnsCheckService::check('AWS SES', 'MAIL FROM', 'warning', 'Non configure', 'bounce.'.$domain, 'N/A'); - } - - $notif = $this->awsSes->getNotificationStatus($domain); - $bounceOk = $notif['forwarding'] || null !== $notif['bounce_topic']; - $bounceDetail = $notif['forwarding'] ? 'Forwarding actif' : ($notif['bounce_topic'] ?? 'Non configure'); - $checks[] = DnsCheckService::check('AWS SES', 'Bounce notif', $bounceOk ? 'ok' : 'warning', $bounceDetail, 'Forwarding ou SNS topic', $bounceDetail); + $this->checkSesDomain($domain, $checks, $errors, $successes); + $this->checkSesDkim($domain, $checks, $errors, $successes, $cfRecords); + $this->checkSesMailFrom($domain, $checks, $errors, $successes, $cfRecords); + $this->checkSesBounce($domain, $checks); } catch (\Throwable $e) { - $errors[] = "[$domain] AWS SES : ".$e->getMessage(); - $checks[] = DnsCheckService::check('AWS SES', 'API', 'error', $e->getMessage()); + $errors[] = "[$domain] $ses : ".$e->getMessage(); + $checks[] = DnsCheckService::check($ses, 'API', 'error', $e->getMessage()); } } + /** @param list $checks @param list $errors @param list $successes */ + private function checkSesDomain(string $domain, array &$checks, array &$errors, array &$successes): void + { + $ses = DnsInfraHelper::LABEL_AWS_SES; + $verif = $this->awsSes->isDomainVerified($domain); + $ok = 'Success' === $verif; + + $checks[] = DnsCheckService::check($ses, 'Domaine', $ok ? 'ok' : 'error', $verif ?? 'Non verifie', 'Success', $verif ?? 'Absent'); + $ok ? $successes[] = "[$domain] $ses : domaine verifie" : $errors[] = "[$domain] $ses : domaine non verifie ($verif)"; + } + + /** @param list $checks @param list $errors @param list $successes @param list> $cfRecords */ + private function checkSesDkim(string $domain, array &$checks, array &$errors, array &$successes, array $cfRecords): void + { + $ses = DnsInfraHelper::LABEL_AWS_SES; + $dkim = $this->awsSes->getDkimStatus($domain); + $dkimOk = $dkim['enabled'] && $dkim['verified']; + + $checks[] = DnsCheckService::check( + $ses, 'DKIM statut', $dkimOk ? 'ok' : 'error', + $dkimOk ? 'Active et verifiee' : 'Non active ou non verifiee', + 'Enabled=oui, Verified=oui', + 'Enabled='.($dkim['enabled'] ? 'oui' : 'non').', Verified='.($dkim['verified'] ? 'oui' : 'non') + ); + $dkimOk ? $successes[] = "[$domain] $ses DKIM : active et verifiee" : $errors[] = "[$domain] $ses DKIM : non active ou non verifiee"; + + foreach ($dkim['tokens'] as $token) { + $expectedCname = $token.'.dkim.amazonses.com'; + $dkimFqdn = $token.'._domainkey.'.$domain; + $actualCname = $this->dnsCheck->getCnameRecord($dkimFqdn); + $found = null !== $actualCname && str_contains($actualCname, 'dkim.amazonses.com'); + + $checks[] = DnsCheckService::check($ses, 'DKIM CNAME '.$token, $found ? 'ok' : 'error', $found ? 'Present' : 'Absent', $expectedCname, $actualCname ?? DnsInfraHelper::NOT_FOUND); + $this->helper->enrichLastCheck($checks, $dkimFqdn, 'CNAME', $cfRecords); + $found ? $successes[] = "[$domain] $ses DKIM CNAME $token : OK" : $errors[] = "[$domain] $ses DKIM CNAME $token : absent (attendu: $dkimFqdn CNAME $expectedCname)"; + } + } + + /** @param list $checks @param list $errors @param list $successes @param list> $cfRecords */ + private function checkSesMailFrom(string $domain, array &$checks, array &$errors, array &$successes, array $cfRecords): void + { + $ses = DnsInfraHelper::LABEL_AWS_SES; + $mailFrom = $this->awsSes->getMailFromStatus($domain); + $mfd = $mailFrom['mail_from_domain']; + + if (null === $mfd) { + $checks[] = DnsCheckService::check($ses, 'MAIL FROM', 'warning', DnsInfraHelper::NOT_CONFIGURED, 'bounce.'.$domain, 'N/A'); + + return; + } + + $status = $mailFrom['mail_from_status']; + $statusOk = 'Success' === $status; + $checks[] = DnsCheckService::check($ses, 'MAIL FROM', $statusOk ? 'ok' : 'error', $status ?? 'Inconnu', $mfd.' (statut: Success)', $mfd.' (statut: '.($status ?? '?').')'); + $statusOk ? $successes[] = "[$domain] $ses MAIL FROM : $mfd verifie" : $errors[] = "[$domain] $ses MAIL FROM : $mfd statut $status"; + + if (null !== $mailFrom['mx_expected']) { + $mxFound = $this->helper->checkMxExists($mfd, $mailFrom['mx_expected']); + $actualMx = $this->helper->getMxValues($mfd); + $checks[] = DnsCheckService::check($ses, 'MAIL FROM MX', $mxFound ? 'ok' : 'error', $mxFound ? 'Present' : 'Absent', "$mfd MX {$mailFrom['mx_expected']}", $actualMx ?: DnsInfraHelper::NOT_FOUND); + $this->helper->enrichLastCheck($checks, $mfd, 'MX', $cfRecords); + $mxFound ? $successes[] = "[$domain] $ses MAIL FROM MX : OK" : $errors[] = "[$domain] $ses MAIL FROM MX absent (attendu: $mfd MX {$mailFrom['mx_expected']})"; + } + + if (null !== $mailFrom['txt_expected']) { + $txtFound = $this->helper->checkTxtContains($mfd, 'v=spf1'); + $actualTxt = $this->helper->getTxtSpfValue($mfd); + $checks[] = DnsCheckService::check($ses, 'MAIL FROM TXT', $txtFound ? 'ok' : 'error', $txtFound ? 'Present' : 'Absent', "$mfd TXT {$mailFrom['txt_expected']}", $actualTxt ?: DnsInfraHelper::NOT_FOUND); + $this->helper->enrichLastCheck($checks, $mfd, 'TXT', $cfRecords); + $txtFound ? $successes[] = "[$domain] $ses MAIL FROM SPF : OK" : $errors[] = "[$domain] $ses MAIL FROM SPF absent (attendu: $mfd TXT {$mailFrom['txt_expected']})"; + } + } + + /** @param list $checks */ + private function checkSesBounce(string $domain, array &$checks): void + { + $ses = DnsInfraHelper::LABEL_AWS_SES; + $notif = $this->awsSes->getNotificationStatus($domain); + $bounceOk = $notif['forwarding'] || null !== $notif['bounce_topic']; + $detail = $notif['forwarding'] ? 'Forwarding actif' : ($notif['bounce_topic'] ?? DnsInfraHelper::NOT_CONFIGURED); + $checks[] = DnsCheckService::check($ses, 'Bounce notif', $bounceOk ? 'ok' : 'warning', $detail, 'Forwarding ou SNS topic', $detail); + } + /** * @param list $checks * @param list $errors * @param list $warnings * @param list $successes + * @param list> $cfRecords */ private function checkMailcow(string $domain, array &$checks, array &$errors, array &$warnings, array &$successes, array $cfRecords = []): void { + $mc = DnsInfraHelper::LABEL_MAILCOW; + if (!$this->mailcow->isAvailable()) { - $checks[] = DnsCheckService::check('Mailcow', 'API', 'warning', 'Non disponible', 'Acces API Mailcow', 'N/A'); + $checks[] = DnsCheckService::check($mc, 'API', 'warning', 'Non disponible', 'Acces API Mailcow', 'N/A'); return; } @@ -271,50 +248,44 @@ class CheckDnsCommand extends Command try { $info = $this->mailcow->getDomainStatus($domain); if (null === $info) { - $warnings[] = "[$domain] Mailcow : domaine non configure"; - $checks[] = DnsCheckService::check('Mailcow', 'Domaine', 'warning', 'Non configure', 'Domaine actif', 'Absent'); + $warnings[] = "[$domain] $mc : domaine non configure"; + $checks[] = DnsCheckService::check($mc, 'Domaine', 'warning', DnsInfraHelper::NOT_CONFIGURED, 'Domaine actif', 'Absent'); return; } $checks[] = DnsCheckService::check( - 'Mailcow', 'Domaine', $info['active'] ? 'ok' : 'error', + $mc, 'Domaine', $info['active'] ? 'ok' : 'error', $info['active'] ? "Actif, {$info['mailboxes']} boite(s)" : 'Desactive', 'Actif', $info['active'] ? "Actif ({$info['mailboxes']} boites)" : 'Desactive' ); + $info['active'] ? $successes[] = "[$domain] $mc : actif, {$info['mailboxes']} boite(s)" : $errors[] = "[$domain] $mc : desactive"; - if ($info['active']) { - $successes[] = "[$domain] Mailcow : actif, {$info['mailboxes']} boite(s)"; - } else { - $errors[] = "[$domain] Mailcow : desactive"; - } - - $expectedRecords = $this->mailcow->getExpectedDnsRecords($domain); - foreach ($expectedRecords as $expected) { + $mcDns = DnsInfraHelper::LABEL_MAILCOW_DNS; + foreach ($this->mailcow->getExpectedDnsRecords($domain) as $expected) { $found = $this->helper->checkDnsRecordExists($expected['type'], $expected['name'], $expected['content']); $isOptional = $expected['optional']; $label = $expected['type'].' '.$expected['name']; $digValue = $this->helper->getActualDnsValue($expected['type'], $expected['name']); $checks[] = DnsCheckService::check( - 'Mailcow DNS', $label, $found ? 'ok' : ($isOptional ? 'warning' : 'error'), + $mcDns, $label, $found ? 'ok' : ($isOptional ? 'warning' : 'error'), $found ? 'Present' : ($isOptional ? 'Absent (optionnel)' : 'Absent'), - $expected['content'], $digValue ?: 'Non trouve' + $expected['content'], $digValue ?: DnsInfraHelper::NOT_FOUND ); - $this->helper->enrichLastCheck($checks, $expected['name'], $expected['type'], $cfRecords); if ($found) { - $successes[] = "[$domain] Mailcow DNS : $label OK"; + $successes[] = "[$domain] $mcDns : $label OK"; } elseif ($isOptional) { - $warnings[] = "[$domain] Mailcow DNS : $label absent (optionnel)"; + $warnings[] = "[$domain] $mcDns : $label absent (optionnel)"; } else { - $errors[] = "[$domain] Mailcow DNS : $label absent"; + $errors[] = "[$domain] $mcDns : $label absent"; } } } catch (\Throwable $e) { - $errors[] = "[$domain] Mailcow : ".$e->getMessage(); - $checks[] = DnsCheckService::check('Mailcow', 'API', 'error', $e->getMessage()); + $errors[] = "[$domain] $mc : ".$e->getMessage(); + $checks[] = DnsCheckService::check($mc, 'API', 'error', $e->getMessage()); } } diff --git a/src/Command/PurgeEmailTrackingCommand.php b/src/Command/PurgeEmailTrackingCommand.php index b76ebda..045a11c 100644 --- a/src/Command/PurgeEmailTrackingCommand.php +++ b/src/Command/PurgeEmailTrackingCommand.php @@ -2,7 +2,6 @@ namespace App\Command; -use App\Repository\EmailTrackingRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -18,7 +17,6 @@ use Symfony\Component\Console\Style\SymfonyStyle; class PurgeEmailTrackingCommand extends Command { public function __construct( - private EmailTrackingRepository $repository, private EntityManagerInterface $em, ) { parent::__construct(); diff --git a/src/Controller/Admin/SyncController.php b/src/Controller/Admin/SyncController.php index f37ff1d..4b9f8e1 100644 --- a/src/Controller/Admin/SyncController.php +++ b/src/Controller/Admin/SyncController.php @@ -123,8 +123,7 @@ class SyncController extends AbstractController ]; foreach ($result['created'] as $wh) { - $status = $wh['status'] ?? 'created'; - if ('exists' === $status) { + if ('exists' === $wh['status']) { $this->addFlash('success', $wh['type'].' : deja configure ('.$wh['id'].')'); } else { $this->addFlash('success', $wh['type'].' : cree ('.$wh['id'].')'); diff --git a/src/Controller/DnsReportController.php b/src/Controller/DnsReportController.php index 973f517..c0ecad0 100644 --- a/src/Controller/DnsReportController.php +++ b/src/Controller/DnsReportController.php @@ -54,7 +54,7 @@ class DnsReportController extends AbstractController $dnsCheck->checkDmarc($domain, $checks, $errors, $successes); $helper->enrichWithCloudflare($checks, '_dmarc.'.$domain, 'DMARC', 'TXT', $cfRecords); - $dnsCheck->checkMx($domain, DnsInfraHelper::EXPECTED_MX[$domain] ?? '', $checks, $errors, $successes); + $dnsCheck->checkMx($domain, DnsInfraHelper::EXPECTED_MX[$domain], $checks, $errors, $successes); $helper->enrichWithCloudflare($checks, $domain, 'MX', 'MX', $cfRecords); $dnsCheck->checkBounce($domain, $checks, $errors, $warnings, $successes); diff --git a/src/Service/CloudflareService.php b/src/Service/CloudflareService.php index 135bc6d..0d5fedd 100644 --- a/src/Service/CloudflareService.php +++ b/src/Service/CloudflareService.php @@ -130,6 +130,7 @@ class CloudflareService } /** + * @param array $query * @return array */ private function request(string $method, string $path, array $query = []): array diff --git a/src/Service/DnsCheckService.php b/src/Service/DnsCheckService.php index 689b27a..83c3bcd 100644 --- a/src/Service/DnsCheckService.php +++ b/src/Service/DnsCheckService.php @@ -338,6 +338,17 @@ class DnsCheckService return $records; } + public function getDkimTxtRecord(string $domain): ?string + { + foreach ($this->getTxtRecords($domain) as $txt) { + if (str_starts_with($txt, 'v=DKIM1')) { + return $txt; + } + } + + return null; + } + /** * @return list */ diff --git a/src/Service/DnsInfraHelper.php b/src/Service/DnsInfraHelper.php index b75f202..5b5407e 100644 --- a/src/Service/DnsInfraHelper.php +++ b/src/Service/DnsInfraHelper.php @@ -11,6 +11,12 @@ class DnsInfraHelper 'esy-web.dev' => 'mail.esy-web.dev', ]; + public const LABEL_AWS_SES = 'AWS SES'; + public const LABEL_MAILCOW = 'Mailcow'; + public const LABEL_MAILCOW_DNS = 'Mailcow DNS'; + public const NOT_FOUND = 'Non trouve'; + public const NOT_CONFIGURED = 'Non configure'; + public function __construct( private DnsCheckService $dnsCheck, private CloudflareService $cloudflare, @@ -58,7 +64,7 @@ class DnsInfraHelper } if (null === $cfValue) { - $cfValue = 'Non trouve'; + $cfValue = self::NOT_FOUND; $cfStatus = '' === $cfStatus ? '' : 'error'; } @@ -76,7 +82,7 @@ class DnsInfraHelper */ public function enrichLastCheck(array &$checks, string $recordName, string $dnsType, array $cfRecords): void { - $cfValue = 'Non trouve'; + $cfValue = self::NOT_FOUND; $cfStatus = ''; foreach ($cfRecords as $r) { @@ -99,7 +105,7 @@ class DnsInfraHelper return match ($type) { 'MX' => $this->getMxValues($name), 'CNAME' => $this->dnsCheck->getCnameRecord($name) ?? '', - 'TXT' => $this->getFirstTxtValue($name) ?: $this->getFirstTxtValueRaw($name), + 'TXT' => $this->getFirstTxtValue($name), 'SRV' => $this->getSrvValue($name), default => '', }; @@ -128,19 +134,6 @@ class DnsInfraHelper return ''; } - private function getFirstTxtValueRaw(string $domain): string - { - $output = $this->dnsCheck->dig($domain, 'TXT'); - - foreach (explode("\n", $output) as $line) { - if (preg_match('/\bIN\s+TXT\s+"(.+)"/', $line, $m)) { - return str_replace('" "', '', $m[1]); - } - } - - return ''; - } - public function getSrvValue(string $domain): string { $values = []; diff --git a/src/Service/MailcowService.php b/src/Service/MailcowService.php index f51397f..3c51adb 100644 --- a/src/Service/MailcowService.php +++ b/src/Service/MailcowService.php @@ -137,8 +137,6 @@ class MailcowService ], ]); - $data = $response->toArray(false); - - return \is_array($data) ? $data : []; + return $response->toArray(false); } } diff --git a/src/Service/StripeWebhookService.php b/src/Service/StripeWebhookService.php index 9bfb43b..02ee466 100644 --- a/src/Service/StripeWebhookService.php +++ b/src/Service/StripeWebhookService.php @@ -74,7 +74,7 @@ class StripeWebhookService /** * Cree les 4 webhooks Stripe (main light/instant + connect light/instant). * - * @return array{created: list, errors: list} + * @return array{created: list, errors: list} */ public function createAllWebhooks(string $baseUrl): array { diff --git a/templates/admin/membres.html.twig b/templates/admin/membres.html.twig index 298616b..7ecd283 100644 --- a/templates/admin/membres.html.twig +++ b/templates/admin/membres.html.twig @@ -41,66 +41,66 @@ placeholder="email@exemple.fr">
- + Groupes d'acces
-
diff --git a/templates/admin/tarification/index.html.twig b/templates/admin/tarification/index.html.twig index 055e330..a77172e 100644 --- a/templates/admin/tarification/index.html.twig +++ b/templates/admin/tarification/index.html.twig @@ -44,20 +44,20 @@
- - + +
- - + +
- - + +
- - {% for p in [1, 2, 3, 6, 12] %} {% endfor %} @@ -66,8 +66,8 @@
- - + +
diff --git a/templates/legal/tarif.html.twig b/templates/legal/tarif.html.twig index fc3a810..2a7ef94 100644 --- a/templates/legal/tarif.html.twig +++ b/templates/legal/tarif.html.twig @@ -620,6 +620,9 @@
Options
+ + + diff --git a/templates/security/2fa_google.html.twig b/templates/security/2fa_google.html.twig index 9af3675..27e80ff 100644 --- a/templates/security/2fa_google.html.twig +++ b/templates/security/2fa_google.html.twig @@ -37,8 +37,8 @@ {% if displayTrustedOption %} -
OptionTarif
Boite mail supplementaire