From f9f1a54c699c48e0405e9af4c4c717d8db056d28 Mon Sep 17 00:00:00 2001 From: Kevin Jilissen Date: Fri, 28 Feb 2025 15:46:39 +0000 Subject: [PATCH] Allow SVG in jury test case visualization --- .../src/Controller/Jury/ProblemController.php | 30 ++++++++++++------- webapp/src/Service/DOMJudgeService.php | 6 ++++ webapp/src/Service/ImportProblemService.php | 9 ++++++ webapp/templates/jury/submission.html.twig | 3 +- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index d9256f2a6aa..9253992658e 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -605,16 +605,26 @@ public function testcasesAction(Request $request, int $probId): Response } $content = file_get_contents($file->getRealPath()); if ($type === 'image') { - $imageType = Utils::getImageType($content, $error); - if ($imageType === false) { - $this->addFlash('danger', sprintf('image: %s', $error)); - return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]); - } - $thumb = Utils::getImageThumb($content, $thumbnailSize, - $this->dj->getDomjudgeTmpDir(), $error); - if ($thumb === false) { - $this->addFlash('danger', sprintf('image: %s', $error)); - return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]); + if (mime_content_type($file->getRealPath()) === 'image/svg+xml') { + $content = Utils::sanitizeSvg($content); + if ($content === false) { + $this->addFlash('danger', sprintf('image: %s', $error)); + return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]); + } + $thumb = $content; + $imageType = 'svg'; + } else { + $imageType = Utils::getImageType($content, $error); + if ($imageType === false) { + $this->addFlash('danger', sprintf('image: %s', $error)); + return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]); + } + $thumb = Utils::getImageThumb($content, $thumbnailSize, + $this->dj->getDomjudgeTmpDir(), $error); + if ($thumb === false) { + $this->addFlash('danger', sprintf('image: %s', $error)); + return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]); + } } $testcase->setImageType($imageType); diff --git a/webapp/src/Service/DOMJudgeService.php b/webapp/src/Service/DOMJudgeService.php index bfad289f419..120b30c36df 100644 --- a/webapp/src/Service/DOMJudgeService.php +++ b/webapp/src/Service/DOMJudgeService.php @@ -85,6 +85,12 @@ class DOMJudgeService 'image/svg+xml' => 'svg', ]; + final public const EXTENSION_TO_MIMETYPE = [ + 'png' => 'image/png', + 'jpg' => 'image/jpeg', + 'svg' => 'image/svg+xml', + ]; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly LoggerInterface $logger, diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index f341187c93d..9a705fc0322 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -427,6 +427,15 @@ public function importZippedProblem( break; } } + // Handle SVG differently, as a lot of the above concepts do not make sense in this context. + $imageFileName = $baseFileName . '.svg'; + if (($imageFile = $zip->getFromName($imageFileName)) !== false) { + if (($imageFile = Utils::sanitizeSvg($imageFile)) === false) { + $messages['warning'][] = sprintf("Contents of '%s' is not safe.", $imageFileName); + } + $imageType = 'svg'; + $imageThumb = $imageFile; + } if (str_contains($testInput, "\r")) { $messages['warning'][] = "Testcase file '$baseFileName.in' contains Windows newlines."; diff --git a/webapp/templates/jury/submission.html.twig b/webapp/templates/jury/submission.html.twig index 4b04e74b3a6..6a84e5c3b9b 100644 --- a/webapp/templates/jury/submission.html.twig +++ b/webapp/templates/jury/submission.html.twig @@ -742,7 +742,8 @@ {% set imgUrl = path('jury_problem_testcase_fetch', {'probId': submission.problem.probid, 'rank': run.rank, 'type': 'image'}) %} - + {% set EXTENSION_TO_MIMETYPE = constant('App\\Service\\DOMJudgeService::EXTENSION_TO_MIMETYPE') %} + {% endif %}