Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MediaBundle] file whitelist #2871

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/bundles/config-reference.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Configuration Options

Ever wondered what configuration options you have available to you in yaml config files? In this section,
all the available configurations are broken down for each bundle (e.g. AdminBundle, NodeBundle) that defines each
Ever wondered what configuration options you have available to you in yaml config files? In this section,
all the available configurations are broken down for each bundle (e.g. AdminBundle, NodeBundle) that defines each
possible section of your Kunstmaan cms configuration.

## Adminbundle
Expand Down Expand Up @@ -89,6 +89,7 @@ kunstmaan_media:
# Defaults:
- php
- htaccess
whitelisted_extensions: []
```

## MediaPagePartBundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public function getConfigTreeBuilder()
->defaultValue(['php', 'htaccess'])
->prototype('scalar')->end()
->end()
->arrayNode('whitelisted_extensions')
->defaultValue([])
->prototype('scalar')->end()
->end()
->scalarNode('web_root')
->defaultValue(SymfonyVersion::getRootWebPath())
->cannotBeEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('kunstmaan_media.soundcloud_api_key', $config['soundcloud_api_key']);
$container->setParameter('kunstmaan_media.remote_video', $config['remote_video']);
$container->setParameter('kunstmaan_media.enable_pdf_preview', $config['enable_pdf_preview']);
$container->setParameter('kunstmaan_media.blacklisted_extensions', $config['blacklisted_extensions']);
$container->setParameter('kunstmaan_media.whitelisted_extensions', $this->getWhitelistedExtensions($config));
$container->setParameter('kunstmaan_media.blacklisted_extensions', $this->getBlacklistedExtensions($config));
$container->setParameter('kunstmaan_media.web_root', $config['web_root']);
$container->setParameter('kunstmaan_media.full_media_path', $config['web_root'] . '%kunstmaan_media.media_path%');

Expand Down Expand Up @@ -137,4 +138,31 @@ private function addAvairyApiKeyParameter(ContainerBuilder $container, array $co

$container->setParameter('kunstmaan_media.aviary_api_key', $aviaryApiKey);
}

private function getExtensions(array $config, string $key): array
{
$extensions = $config[$key];

foreach ($extensions as &$extension) {
$extension = strtolower($extension);
}

return $extensions;
}

private function getWhitelistedExtensions(array $config): array
{
return $this->getExtensions(
$config,
'whitelisted_extensions'
);
}

private function getBlacklistedExtensions(array $config): array
{
return $this->getExtensions(
$config,
'blacklisted_extensions'
);
}
}
33 changes: 32 additions & 1 deletion src/Kunstmaan/MediaBundle/Form/File/FileType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Kunstmaan\MediaBundle\Form\File;

use Kunstmaan\MediaBundle\Repository\FolderRepository;
use Kunstmaan\MediaBundle\Validator\Constraints\ExtensionConstraint;
use Kunstmaan\MediaBundle\Validator\Constraints\HasGuessableExtension;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
Expand All @@ -21,6 +22,26 @@
*/
class FileType extends AbstractType
{
/**
* @var array
*/
private $blacklistedExtensions = [];

/**
* @var array
*/
private $whitelistedExtensions = [];

public function setBlacklistedExtensions(array $blacklistedExtensions): void
{
$this->blacklistedExtensions = $blacklistedExtensions;
}

public function setWhitelistedExtensions(array $whitelistedExtensions): void
{
$this->whitelistedExtensions = $whitelistedExtensions;
}

/**
* Builds the form.
*
Expand Down Expand Up @@ -81,7 +102,17 @@ function (FormEvent $event) {
BaseFileType::class,
[
'label' => 'media.form.file.file.label',
'constraints' => [new NotBlank(), new File(), new HasGuessableExtension()],
'constraints' => [
new NotBlank(),
new File(),
new HasGuessableExtension(),
new ExtensionConstraint(
[
'whitelistedExtensions' => $this->whitelistedExtensions,
'blacklistedExtensions' => $this->blacklistedExtensions,
]
)
],
'required' => true,
]
);
Expand Down
91 changes: 65 additions & 26 deletions src/Kunstmaan/MediaBundle/Helper/File/FileHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class FileHandler extends AbstractMediaHandler
*/
const TYPE = 'file';

private const DEFAULT_EXTENSION = 'txt';

/**
* @var string
*/
Expand Down Expand Up @@ -59,6 +61,13 @@ class FileHandler extends AbstractMediaHandler
*/
private $blacklistedExtensions = [];

/**
* Files with an extension not in the whitelist will be converted to txt
*
* @var array
*/
private $whitelistedExtensions = [];

/**
* @var SlugifierInterface
*/
Expand Down Expand Up @@ -100,14 +109,16 @@ public function setSlugifier(SlugifierInterface $slugifier)
$this->slugifier = $slugifier;
}

/**
* Inject the blacklisted
*/
public function setBlacklistedExtensions(array $blacklistedExtensions)
{
$this->blacklistedExtensions = $blacklistedExtensions;
}

public function setWhitelistedExtensions(array $whitelistedExtensions)
{
$this->whitelistedExtensions = $whitelistedExtensions;
}

/**
* Inject the path used in media urls.
*
Expand Down Expand Up @@ -275,23 +286,24 @@ public function getOriginalFile(Media $media)
*/
public function createNew($data)
{
if ($data instanceof File) {
/** @var $data File */
$media = new Media();
if (method_exists($data, 'getClientOriginalName')) {
$media->setOriginalFilename($data->getClientOriginalName());
} else {
$media->setOriginalFilename($data->getFilename());
}
$media->setContent($data);
if (!$data instanceof File) {
return null;
}

$contentType = $this->guessMimeType($media->getContent()->getPathname());
$media->setContentType($contentType);
$fileName = $data->getFilename();

return $media;
if (method_exists($data, 'getClientOriginalName')) {
$fileName = $data->getClientOriginalName();
}

return null;
$media = new Media();
$media->setOriginalFilename($fileName);
$media->setContent($data);

$contentType = $this->guessMimeType($media->getContent()->getPathname());
$media->setContentType($contentType);

return $media;
}

/**
Expand Down Expand Up @@ -322,22 +334,49 @@ private function getFilePath(Media $media)
{
$filename = $media->getOriginalFilename();
$filename = str_replace(['/', '\\', '%'], '', $filename);
$pathInfo = pathinfo($filename);
$filename = $this->slugifier->slugify($pathInfo['filename']);

if (!empty($this->blacklistedExtensions)) {
$filename = preg_replace('/\.(' . implode('|', $this->blacklistedExtensions) . ')$/', '.txt', $filename);
return sprintf(
'%s/%s.%s',
$media->getUuid(),
$filename,
$this->getFilePathExtension($pathInfo['extension'] ?? null)
);
}

private function getFilePathExtension(?string $extension): string
{
if (!is_string($extension)) {
return static::DEFAULT_EXTENSION;
}

$parts = pathinfo($filename);
$filename = $this->slugifier->slugify($parts['filename']);
if (\array_key_exists('extension', $parts)) {
$filename .= '.' . strtolower($parts['extension']);
$extension = strtolower($extension);
$isBlacklisted = in_array(
$extension,
$this->blacklistedExtensions,
true
);

if ($isBlacklisted) {
return static::DEFAULT_EXTENSION;
}

return sprintf(
'%s/%s',
$media->getUuid(),
$filename
if (!count($this->whitelistedExtensions)) {
return $extension;
}

$isWhitelisted = in_array(
$extension,
$this->whitelistedExtensions,
true
);

if (!$isWhitelisted) {
return static::DEFAULT_EXTENSION;
}

return $extension;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/Kunstmaan/MediaBundle/Resources/config/handlers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ services:
- [ setFileSystem, [ '@kunstmaan_media.filesystem' ] ]
- [ setMediaPath, [ '%kunstmaan_media.media_path%' ] ]
- [ setBlacklistedExtensions, [ '%kunstmaan_media.blacklisted_extensions%' ] ]
- [ setWhitelistedExtensions, [ '%kunstmaan_media.whitelisted_extensions%' ] ]
- [ setSlugifier, ['@kunstmaan_utilities.slugifier']]
tags:
- { name: 'kunstmaan_media.media_handler' }
Expand All @@ -43,6 +44,7 @@ services:
- [ setFileSystem, [ '@kunstmaan_media.filesystem' ] ]
- [ setMediaPath, [ '%kunstmaan_media.media_path%' ] ]
- [ setBlacklistedExtensions, [ '%kunstmaan_media.blacklisted_extensions%' ] ]
- [ setWhitelistedExtensions, [ '%kunstmaan_media.whitelisted_extensions%' ] ]
- [ setSlugifier, ['@kunstmaan_utilities.slugifier']]
tags:
- { name: 'kunstmaan_media.media_handler' }
Expand Down
7 changes: 7 additions & 0 deletions src/Kunstmaan/MediaBundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,10 @@ services:
Kunstmaan\MediaBundle\DataFixtures\ORM\FolderFixtures:
tags:
- { name: doctrine.fixture.orm }

Kunstmaan\MediaBundle\Form\File\FileType:
calls:
- [ setBlacklistedExtensions, [ '%kunstmaan_media.blacklisted_extensions%' ] ]
- [ setWhitelistedExtensions, [ '%kunstmaan_media.whitelisted_extensions%' ] ]
tags:
- { name: form.type }
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,5 @@ media:
flash:
created: Media %medianame% has been created!
not_created: Media not created! %mediaerrors%
extension_is_not_allowed:
label: 'File extension is not allowed'
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,5 @@ media:
flash:
created: Media-item %medianame% is aangemaakt!
not_created: Media-item is niet aangemaakt! %mediaerrors%
extension_is_not_allowed:
label: 'Bestandsextensie is niet toegestaan'
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extension_is_not_allowed:
label: 'File extension is not allowed'
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extension_is_not_allowed:
label: 'Bestandsextensie is niet toegestaan'
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Kunstmaan\MediaBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
* @Annotation
*/
class ExtensionConstraint extends Constraint
{
/**
* @var array
*/
public $whitelistedExtensions = [];

/**
* @var array
*/
public $blacklistedExtensions = [];

public function __construct($options = null)
{
parent::__construct($options);

if (is_array($options)) {
$this->setOptions($options);
}
}

public function validatedBy(): string
{
return ExtensionValidator::class;
}

private function setOptions(array $options): void
{
$whitelistedExtensions = $options['whitelistedExtensions'] ?? [];

if (is_array($whitelistedExtensions)) {
$this->whitelistedExtensions = $whitelistedExtensions;
}

$blacklistedExtensions = $options['blacklistedExtensions'] ?? [];

if (is_array($blacklistedExtensions)) {
$this->blacklistedExtensions = $blacklistedExtensions;
}
}
}
Loading