Files
wallabag/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php
Kevin Decherf 3ed7f2b751 AnnotationController: fix improper authorization vulnerability
This PR is based on 2.5.x branch.

We fix the improper authorization by retrieving the annotation using id
and user id.

We also replace the ParamConverter used to get the requested Annotation
on put and delete actions with an explicit call to AnnotationRepository
in order to prevent a resource enumeration through response discrepancy.

Fixes GHSA-mrqx-mjc4-vfh3

Co-authored-by: Jeremy Benoist <jeremy.benoist@gmail.com>
Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2023-01-27 23:34:14 +01:00

143 lines
4.3 KiB
PHP

<?php
namespace Wallabag\AnnotationBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Wallabag\AnnotationBundle\Entity\Annotation;
use Wallabag\AnnotationBundle\Form\EditAnnotationType;
use Wallabag\AnnotationBundle\Form\NewAnnotationType;
use Wallabag\CoreBundle\Entity\Entry;
class WallabagAnnotationController extends FOSRestController
{
/**
* Retrieve annotations for an entry.
*
* @see Wallabag\ApiBundle\Controller\WallabagRestController
*
* @return JsonResponse
*/
public function getAnnotationsAction(Entry $entry)
{
$annotationRows = $this
->getDoctrine()
->getRepository('WallabagAnnotationBundle:Annotation')
->findByEntryIdAndUserId($entry->getId(), $this->getUser()->getId());
$total = \count($annotationRows);
$annotations = ['total' => $total, 'rows' => $annotationRows];
$json = $this->get('jms_serializer')->serialize($annotations, 'json');
return (new JsonResponse())->setJson($json);
}
/**
* Creates a new annotation.
*
* @return JsonResponse
*
* @see Wallabag\ApiBundle\Controller\WallabagRestController
*/
public function postAnnotationAction(Request $request, Entry $entry)
{
$data = json_decode($request->getContent(), true);
$em = $this->getDoctrine()->getManager();
$annotation = new Annotation($this->getUser());
$annotation->setEntry($entry);
$form = $this->get('form.factory')->createNamed('', NewAnnotationType::class, $annotation, [
'csrf_protection' => false,
'allow_extra_fields' => true,
]);
$form->submit($data);
if ($form->isValid()) {
$em->persist($annotation);
$em->flush();
$json = $this->get('jms_serializer')->serialize($annotation, 'json');
return JsonResponse::fromJsonString($json);
}
return $form;
}
/**
* Updates an annotation.
*
* @see Wallabag\ApiBundle\Controller\WallabagRestController
*
* @return JsonResponse
*/
public function putAnnotationAction(Request $request, int $annotation)
{
try {
$annotation = $this->validateAnnotation($annotation, $this->getUser()->getId());
$data = json_decode($request->getContent(), true, 512, \JSON_THROW_ON_ERROR);
$form = $this->get('form.factory')->createNamed('', EditAnnotationType::class, $annotation, [
'csrf_protection' => false,
'allow_extra_fields' => true,
]);
$form->submit($data);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($annotation);
$em->flush();
$json = $this->get('jms_serializer')->serialize($annotation, 'json');
return JsonResponse::fromJsonString($json);
}
return $form;
} catch (\InvalidArgumentException $e) {
throw new NotFoundHttpException($e);
}
}
/**
* Removes an annotation.
*
* @see Wallabag\ApiBundle\Controller\WallabagRestController
*
* @return JsonResponse
*/
public function deleteAnnotationAction(int $annotation)
{
try {
$annotation = $this->validateAnnotation($annotation, $this->getUser()->getId());
$em = $this->getDoctrine()->getManager();
$em->remove($annotation);
$em->flush();
$json = $this->get('jms_serializer')->serialize($annotation, 'json');
return (new JsonResponse())->setJson($json);
} catch (\InvalidArgumentException $e) {
throw new NotFoundHttpException($e);
}
}
private function validateAnnotation(int $annotationId, int $userId)
{
$em = $this->getDoctrine()->getManager();
$annotation = $em->getRepository('WallabagAnnotationBundle:Annotation')->findOneByIdAndUserId($annotationId, $userId);
if (null === $annotation) {
throw new NotFoundHttpException();
}
return $annotation;
}
}