security: add download action for attachments - refactor controllers (params)

This commit is contained in:
Simon Vieille 2020-11-11 19:48:16 +01:00
parent b3eadc5139
commit 1a01841326
Signed by: deblan
GPG Key ID: 03383D15A1D31745
8 changed files with 82 additions and 39 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/public/attachments/
/private/attachments/
/migrations/
/data/
/var/

View File

@ -91,7 +91,7 @@ class MailImportCommand extends Command
$this->em->flush();
if (!empty($attachments)) {
$attachmentsDirectory = $this->kernel->getProjectDir().'/public/attachments/'.$mailing->getId().'/'.$entity->getId();
$attachmentsDirectory = $this->kernel->getProjectDir().'/private/attachments/'.$mailing->getId().'/'.$entity->getId();
$filesystem = new Filesystem();
$filesystem->mkdir($attachmentsDirectory);

View File

@ -39,7 +39,7 @@ class MailingListCommand extends Command
{
$io = new SymfonyStyle($input, $output);
$headers = ['Label', 'Feed', 'Created at', 'Updated at'];
$headers = ['Label', 'ID', 'Feed', 'Created at', 'Updated at'];
$rows = [];
$entities = $this->repo->findAll([], ['createdAt' => 'DEC']);
@ -47,9 +47,10 @@ class MailingListCommand extends Command
foreach ($entities as $entity) {
$rows[] = [
$entity->getLabel(),
$entity->getId(),
$this->router->generate(
'mailing_rss',
['id' => $entity->getId()],
'mailing_rss',
['mailing' => $entity->getId()],
UrlGeneratorInterface::ABSOLUTE_URL
),
$entity->getCreatedAt()->format('Y-m-d H:i:s'),

View File

@ -0,0 +1,38 @@
<?php
namespace App\Controller;
use App\Entity\Mail;
use App\Entity\Mailing;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpKernel\KernelInterface;
use App\Entity\MailAttachment;
class MailAttachmentController extends AbstractController
{
/**
* @Route("/attachment/{mail}/{attachment}/download", name="attachment_download")
* @ParamConverter("attachment", options={"mapping": {"id": "attachment", "mail": "mail"}})
*/
public function download(MailAttachment $attachment, KernelInterface $kernel): Response
{
$mail = $attachment->getMail();
$mailing = $mail->getMailing();
$filename = $attachment->getFilename();
$path = $kernel->getProjectDir().'/private/attachments/'.$mailing->getId().'/'.$mail->getId().'/'.$filename;
return new BinaryFileResponse(
$path,
200,
[
'Content-Type' => $attachment->getContentType(),
'Content-Disposition' => sprintf('inline; filename="%s"', $filename),
]
);
}
}

View File

@ -7,46 +7,38 @@ use App\Entity\Mailing;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
class MailController extends AbstractController
{
/**
* @Route("/mail/{mailing}/{id}/show", name="mail_show")
* @Route("/mail/{mailing}/{mail}/show", name="mail_show")
* @ParamConverter("mail", options={"mapping": {"mail": "id", "mailing": "mailing"}})
*/
public function show(string $mailing, Mail $mail): Response
public function show(Mail $mail): Response
{
if ($mail->getMailing()->getId() !== $mailing) {
throw $this->createNotFoundException();
}
return $this->render('mail/show.html.twig', [
'mail' => $mail,
]);
}
/**
* @Route("/mail/{mailing}/{id}/html", name="mail_html")
* @Route("/mail/{mailing}/{mail}/html", name="mail_html")
* @ParamConverter("mail", options={"mapping": {"mail": "id", "mailing": "mailing"}})
*/
public function html(string $mailing, Mail $mail): Response
public function html(Mail $mail): Response
{
if ($mail->getMailing()->getId() !== $mailing) {
throw $this->createNotFoundException();
}
return $this->render('mail/html.html.twig', [
'mail' => $mail,
]);
}
/**
* @Route("/mail/{mailing}/{id}/text", name="mail_text")
* @Route("/mail/{mailing}/{mail}/text", name="mail_text")
* @ParamConverter("mail", options={"mapping": {"mail": "id", "mailing": "mailing"}})
*/
public function text(string $mailing, Mail $mail): Response
public function text(Mail $mail): Response
{
if ($mail->getMailing()->getId() !== $mailing) {
throw $this->createNotFoundException();
}
$response = $this->render('mail/text.html.twig', [
'mail' => $mail,
]);

View File

@ -8,11 +8,13 @@ use Symfony\Component\Routing\Annotation\Route;
use App\Repository\MailRepository;
use App\Entity\Mailing;
use App\Entity\Mail;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
class MailingController extends AbstractController
{
/**
* @Route("/mailing/{id}/rss", name="mailing_rss")
* @Route("/mailing/{mailing}/rss", name="mailing_rss")
* @ParamConverter("mailing", options={"mapping": {"mailing": "id"}})
*/
public function rss(Mailing $mailing, MailRepository $mailRepository): Response
{

View File

@ -45,31 +45,41 @@
Pièces jointes
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('mailing_rss', {mailing: mail.mailing.id}) }}">
Afficher le flux RSS
</a>
</li>
</ul>
</div>
<div class="col-12">
<div class="tab-content">
<div class="tab-pane fade show active" id="html" role="tabpanel" aria-labelledby="html-tab">
<iframe src="{{ path('mail_html', {mailing: mail.mailing.id, id: mail.id}) }}"></iframe>
<iframe src="{{ path('mail_html', {mailing: mail.mailing.id, mail: mail.id}) }}"></iframe>
</div>
<div class="tab-pane fade" id="text" role="tabpanel" aria-labelledby="text-tab">
<iframe src="{{ path('mail_text', {mailing: mail.mailing.id, id: mail.id}) }}"></iframe>
<iframe src="{{ path('mail_text', {mailing: mail.mailing.id, mail: mail.id}) }}"></iframe>
</div>
<div class="tab-pane fade" id="attachments" role="tabpanel" aria-labelledby="attachments-tab">
{% if mail.mailAttachments|length %}
<ul>
{% for item in mail.mailAttachments %}
<li>
<a target="_blank" href="{{ asset('attachments/' ~ mail.mailing.id ~ '/' ~ mail.id ~ '/' ~ item.filename) }}">
{{ item.filename }}
</a>
<div class="row">
<div class="col-4 m-4">
<ul class="list-group">
{% for item in mail.mailAttachments %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="{{ path('attachment_download', {mail: mail.id, attachment: item.id}) }}">
{{ item.filename }}
</a>
<span class="badge badge-secondary">
{{ item.contentType }}
</span>
</li>
{% endfor %}
</ul>
<span class="badge badge-secondary">
{{ item.contentType }}
</span>
</li>
{% endfor %}
</ul>
</div>
</div>
{% else %}
<div class="alert alert-info">
Aucune pièce jointe

View File

@ -6,7 +6,7 @@
{% for item in mails %}
<item>
<title><![CDATA[{{ item.subject|raw }}]]></title>
<link>{{ absolute_url(path('mail_show', {mailing: mailing.id, id: item.id})) }}</link>
<link>{{ absolute_url(path('mail_show', {mailing: mailing.id, mail: item.id})) }}</link>
<description>
<![CDATA[
{% if item.htmlContent %}