Comptabilite (Super Admin) : - ComptabiliteController avec 7 exports CSV/JSON compatibles SAGE (journal ventes, grand livre, FEC, balance agee, reglements, commissions Stripe 1.5%+0.25E, couts services) - Export PDF via ComptaPdf (FPDF) avec bloc legal pre-rempli, tableau pagine, champ signature DocuSeal - Signature electronique DocuSeal + callback + envoi email signe avec template dedie (compta_export_signed.html.twig) - Rapport financier public (RapportFinancierPdf) : recettes par service, depenses (Stripe, infra, prestataires), bilan excedent/deficit - Codes comptables clients EC-XXXX (plus de 411xxx) Prestataires (Super Admin) : - Entite Prestataire (raisonSociale, siret, email, phone, adresse) - Entite FacturePrestataire (numFacture, montantHt, montantTtc, year, month, isPaid, PDF via Vich) - CRUD complet avec recherche SIRET via proxy API data.gouv.fr - Commande cron app:reminder:factures-prestataire (5 du mois) - Factures prestataires integrees dans export couts services - Sidebar Super Admin : entree Prestataires + Comptabilite Stats (/admin/stats) : - Cout prestataire dynamique depuis FacturePrestataire - Fusion Infra + Prestataire en "Cout de fonctionnement" - Commission Stripe corrigee (1.5% + 0.25E par transaction) Divers : - DocuSealService::sendComptaForSignature() + getApi() - Customer::generateCodeComptable() format EC-XXXX-XXXXX - Protection double prefixe EC- a la creation client - Bouton regenerer PDF cache quand advert state=accepted - Modals sans script inline (data-modal-open/close dans app.js) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
253 lines
10 KiB
PHP
253 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Controller;
|
|
|
|
use App\Controller\CspReportController;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Container\ContainerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
use Symfony\Component\HttpFoundation\Session\Session;
|
|
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
|
use Symfony\Component\Mailer\MailerInterface;
|
|
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
|
|
|
class CspReportControllerTest extends TestCase
|
|
{
|
|
private function setupController(CspReportController $controller): void
|
|
{
|
|
$session = new Session(new MockArraySessionStorage());
|
|
$stack = $this->createStub(RequestStack::class);
|
|
$stack->method('getSession')->willReturn($session);
|
|
|
|
$paramBag = $this->createStub(\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface::class);
|
|
$paramBag->method('get')->willReturn('admin@e-cosplay.fr');
|
|
$paramBag->method('has')->willReturn(true);
|
|
|
|
$container = $this->createStub(ContainerInterface::class);
|
|
$container->method('has')->willReturn(true);
|
|
$container->method('get')->willReturnMap([
|
|
['security.authorization_checker', $this->createStub(AuthorizationCheckerInterface::class)],
|
|
['security.token_storage', $this->createStub(TokenStorageInterface::class)],
|
|
['request_stack', $stack],
|
|
['parameter_bag', $paramBag],
|
|
]);
|
|
$controller->setContainer($container);
|
|
}
|
|
|
|
public function testGetReturns204(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$response = $controller->get();
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportEmptyPayload(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$request = new Request([], [], [], [], [], [], '');
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportInvalidJson(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$request = new Request([], [], [], [], [], [], '{invalid');
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredExtension(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'chrome-extension://abc123',
|
|
'blocked-uri' => 'inline',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredMozExtension(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'moz-extension://abc',
|
|
'blocked-uri' => '',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredLocalhost(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'http://localhost:3000/app.js',
|
|
'blocked-uri' => 'eval',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredLocalDomain(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => '/app.js',
|
|
'blocked-uri' => 'inline',
|
|
'document-uri' => 'http://crm.local/dashboard',
|
|
'violated-directive' => 'style-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredWasmEval(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'https://crm.e-cosplay.fr/app.js',
|
|
'blocked-uri' => 'wasm-eval',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredAboutBlank(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => '',
|
|
'blocked-uri' => 'about:blank',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'frame-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportRealViolationSendsEmail(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$this->setupController($controller);
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
$mailer = $this->createStub(MailerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'https://evil.com/inject.js',
|
|
'blocked-uri' => 'https://evil.com',
|
|
'document-uri' => 'https://crm.e-cosplay.fr/dashboard',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportRealViolationEmailFailure(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$this->setupController($controller);
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$mailer = $this->createStub(MailerInterface::class);
|
|
$mailer->method('send')->willThrowException(new \Exception('SMTP error'));
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => 'https://evil.com/inject.js',
|
|
'blocked-uri' => 'https://evil.com',
|
|
'document-uri' => 'https://crm.e-cosplay.fr/dashboard',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportWithoutCspReportWrapper(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$this->setupController($controller);
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
$mailer = $this->createStub(MailerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'source-file' => 'https://evil.com/inject.js',
|
|
'blocked-uri' => 'https://evil.com',
|
|
'document-uri' => 'https://crm.e-cosplay.fr/dashboard',
|
|
'violated-directive' => 'script-src',
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $mailer, $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
|
|
public function testReportIgnoredNodeModulesInline(): void
|
|
{
|
|
$controller = new CspReportController();
|
|
$logger = $this->createStub(LoggerInterface::class);
|
|
|
|
$payload = json_encode([
|
|
'csp-report' => [
|
|
'source-file' => '/home/user/node_modules/some-lib/index.js',
|
|
'blocked-uri' => 'inline',
|
|
'document-uri' => 'https://crm.e-cosplay.fr',
|
|
'violated-directive' => 'script-src',
|
|
],
|
|
]);
|
|
$request = new Request([], [], [], [], [], [], $payload);
|
|
$response = $controller->report($request, $this->createStub(MailerInterface::class), $logger);
|
|
$this->assertSame(204, $response->getStatusCode());
|
|
}
|
|
}
|