diff --git a/src/Controller/FeaturesController.php b/src/Controller/FeaturesController.php index 2298bed..895ab05 100644 --- a/src/Controller/FeaturesController.php +++ b/src/Controller/FeaturesController.php @@ -7,10 +7,12 @@ namespace Drupal\features\Controller; +use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\system\FileDownloadController; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Returns responses for config module routes. @@ -25,11 +27,20 @@ class FeaturesController implements ContainerInjectionInterface { protected $fileDownloadController; /** + * The CSRF token generator. + * + * @var \Drupal\Core\Access\CsrfTokenGenerator + */ + protected $csrfToken; + + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( - new FileDownloadController() + new FileDownloadController(), + $container->get('csrf_token') ); } @@ -38,16 +49,32 @@ class FeaturesController implements ContainerInjectionInterface { * * @param \Drupal\system\FileDownloadController $file_download_controller * The file download controller. + * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token + * The CSRF token generator. */ - public function __construct(FileDownloadController $file_download_controller) { + public function __construct(FileDownloadController $file_download_controller, CsrfTokenGenerator $csrf_token) { $this->fileDownloadController = $file_download_controller; + $this->csrfToken = $csrf_token; } /** * Downloads a tarball of the site configuration. + * + * @param string $uri + * The URI to download. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * The downloaded file. */ - public function downloadExport($uri) { + public function downloadExport($uri, Request $request) { if ($uri) { + // @todo Simplify once https://www.drupal.org/node/2630920 is solved. + if (!$this->csrfToken->validate($request->query->get('token'), $uri)) { + throw new AccessDeniedHttpException(); + } + $request = new Request(array('file' => $uri)); return $this->fileDownloadController->download($request, 'temporary'); } diff --git a/src/Plugin/FeaturesGeneration/FeaturesGenerationArchive.php b/src/Plugin/FeaturesGeneration/FeaturesGenerationArchive.php index 686fcf0..91ed2fd 100644 --- a/src/Plugin/FeaturesGeneration/FeaturesGenerationArchive.php +++ b/src/Plugin/FeaturesGeneration/FeaturesGenerationArchive.php @@ -9,11 +9,14 @@ namespace Drupal\features\Plugin\FeaturesGeneration; use Drupal\Component\Serialization\Yaml; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Url; use Drupal\features\FeaturesGenerationMethodBase; use Drupal\Core\Archiver\ArchiveTar; use Drupal\Core\Config\InstallStorage; use Drupal\Core\Form\FormStateInterface; use Drupal\features\FeaturesBundleInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Class for generating a compressed archive of packages. @@ -25,7 +28,33 @@ use Drupal\features\FeaturesBundleInterface; * description = @Translation("Generate packages and optional profile as a compressed archive for download."), * ) */ -class FeaturesGenerationArchive extends FeaturesGenerationMethodBase { +class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements ContainerFactoryPluginInterface { + + /** + * The CSRF token generator. + * + * @var \Drupal\Core\Access\CsrfTokenGenerator + */ + protected $csrfToken; + + /** + * Creates a new FeaturesGenerationArchive instance. + * + * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token + * The CSRF token generator. + */ + public function __construct(\Drupal\Core\Access\CsrfTokenGenerator $csrf_token) { + $this->csrfToken = $csrf_token; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $container->get('csrf_token') + ); + } /** * The package generation method id. @@ -241,7 +270,7 @@ class FeaturesGenerationArchive extends FeaturesGenerationMethodBase { */ public function exportFormSubmit(array &$form, FormStateInterface $form_state) { // Redirect to the archive file download. - $form_state->setRedirect('features.export_download', ['uri' => $this->archiveName]); + $form_state->setRedirect('features.export_download', ['uri' => $this->archiveName, 'token' => $this->csrfToken->get($this->archiveName)]); } }