Skip to content

Commit

Permalink
Merge branch 'release/3.x/3.5.0' into 3.x-master
Browse files Browse the repository at this point in the history
  • Loading branch information
telawat committed Nov 19, 2023
2 parents 98ac251 + 923f2e8 commit cc8bc42
Show file tree
Hide file tree
Showing 12 changed files with 1,396 additions and 16 deletions.
33 changes: 18 additions & 15 deletions composer.json
Expand Up @@ -39,34 +39,34 @@
"drupal/captcha": "2.0.5",
"drupal/chosen": "4.0.0",
"drupal/components": "3.0.0-beta3",
"drupal/config_filter": "2.4.0",
"drupal/config_ignore": "2.4.0",
"drupal/config_filter": "2.6.0",
"drupal/config_ignore": "3.1.0",
"drupal/config_perms": "2.1",
"drupal/config_split": "2.0.0-rc4",
"drupal/config_split": "2.0.0",
"drupal/config_update": "2.0.0-alpha3",
"drupal/consultation-consultation": "1.0.4",
"drupal/consumers": "1.17.0",
"drupal/contact_storage": "1.3.0",
"drupal/context": "5.0.0-rc1",
"drupal/core-composer-scaffold": "10.1.5",
"drupal/core-recommended": "10.1.5",
"drupal/core-composer-scaffold": "10.1.6",
"drupal/core-recommended": "10.1.6",
"drupal/crop": "2.3.0",
"drupal/ctools": "3.14.0",
"drupal/devel": "5.1.2",
"drupal/diff": "1.1.0",
"drupal/dropzonejs": "2.8.0",
"drupal/ds": "3.15.0",
"drupal/dynamic_entity_reference": "3.1.0",
"drupal/embed": "1.6.0",
"drupal/embed": "1.7.0",
"drupal/encrypt": "3.1.0",
"drupal/entity_browser": "2.9.0",
"drupal/entity_class_formatter": "2.0.0",
"drupal/entity_embed": "1.4",
"drupal/entity_embed": "1.5",
"drupal/entity_hierarchy": "3.3.9",
"drupal/entity_reference_display": "2.0.0",
"drupal/entity_reference_revisions": "1.10.0",
"drupal/environment_indicator": "4.0.17",
"drupal/events_log_track": "3.1.7",
"drupal/events_log_track": "3.1.8",
"drupal/facets": "2.0.6",
"drupal/field_group": "3.4.0",
"drupal/focal_point": "2.0.2",
Expand Down Expand Up @@ -104,21 +104,21 @@
"drupal/robotstxt": "1.5.0",
"drupal/role_delegation": "1.2.0",
"drupal/scheduled_transitions": "2.3.0",
"drupal/search_api": "1.29.0",
"drupal/search_api": "1.30.0",
"drupal/search_api_attachments": "9.0.2",
"drupal/search_api_solr": "4.2.12",
"drupal/search_api_solr": "4.3.0",
"drupal/seckit": "2.0.1",
"drupal/securitytxt": "1.4.0",
"drupal/shield": "1.7.0",
"drupal/simple_oauth": "5.2.3",
"drupal/simple_oauth": "5.2.4",
"drupal/simple_sitemap": "4.1.6",
"drupal/swiftmailer": "2.4.0",
"drupal/symfony_mailer": "1.4.0-beta2",
"drupal/tfa": "1.2.0",
"drupal/token": "1.12.0",
"drupal/symfony_mailer": "1.4.0",
"drupal/tfa": "1.3.0",
"drupal/token": "1.13.0",
"drupal/twig_tweak": "3.2.1",
"drupal/username_enumeration_prevention": "1.3.0",
"drupal/webform": "6.2.0-rc1",
"drupal/webform": "6.2.0",
"egulias/email-validator": "4.0.1 as 3.2.6",
"govcms-assets/chosen": "2.2.1",
"oomphinc/composer-installers-extender": "^2.0",
Expand Down Expand Up @@ -168,6 +168,9 @@
},
"drupal/tfa": {
"Create Email one-time-code Validation Plugin & related Setup Plugin - https://www.drupal.org/project/tfa/issues/2930541": "https://www.drupal.org/files/issues/2023-07-19/tfa-2930541-81.patch"
},
"drupal/search_api": {
"OOM issue after creating approx 5000 nodes - https://www.drupal.org/project/search_api/issues/3321677": "https://www.drupal.org/files/issues/2023-05-20/3321677-4--indexing_memory_exhaustion.patch"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion govcms.info.yml
Expand Up @@ -3,7 +3,7 @@ type: profile
description: 'A GovCMS Drupal Distribution for government and the public sector in Australia.'
core_version_requirement: ^10
project: 'govcms'
version: '3.4.0'
version: '3.5.0'

distribution:
name: GovCMS
Expand Down
@@ -0,0 +1,8 @@
services:
# GovCMS events subscriber.
govcms_security_events_subscriber:
# Event subscriber class that will listen for the events.
class: '\Drupal\govcms_security\EventSubscriber\GovcmsSecurityEventsSubscriber'
# Tagged as an event_subscriber to register this subscriber with the event_dispatch service.
tags:
- { name: 'event_subscriber' }
@@ -0,0 +1,93 @@
<?php

namespace Drupal\govcms_security\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Drupal\govcms_security\GovcmsFileConstraintInterface;

/**
* GovCMS security event subscriber.
*/
class GovcmsSecurityEventsSubscriber implements EventSubscriberInterface {

/**
* {@inheritdoc}
*
* @return array
* The event names to listen for, and the methods that should be executed.
*/
public static function getSubscribedEvents() {
$events = [];
// Subscribe to Symfony kernel request with default priority of 0.
$events[KernelEvents::REQUEST][] = ['onRequest'];
return $events;
}

/**
* React to files being uploaded.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* HTTP request event.
*/
public function onRequest(RequestEvent $event) {
// Only need to check the main request.
if ($event->isMainRequest()) {
$current_request = $event->getRequest();
// Content Disposition from the request's header.
$content_disposition = $current_request->headers->get('content-disposition');
$matches = [];

// File upladed by API.
if ($content_disposition) {
if (preg_match(GovcmsFileConstraintInterface::REQUEST_HEADER_FILENAME_REGEX, $content_disposition, $matches)) {
if (!empty($matches['filename'])) {
// Validate the file name.
$this->validateFile($matches['filename']);
}
}
}

// File uploaded by a form.
$file_names = array_column($_FILES, 'name');
// Search the array to find the filename element.
array_walk_recursive($file_names, function ($file_name, $field) {
if (is_string($file_name)) {
// Validate the file name.
$this->validateFile($file_name);
}
});
}
}

/**
* Validate uploading file.
*
* @param string $name
* The file name to validate.
*
* @return bool
* Return ture if the validation passed. Otherwise, it will throw an Access
* Denied Exception.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
* Thrown when the file validation failed.
*/
protected function validateFile($name) {
// The file extension of the original name.
$extension = pathinfo($name, PATHINFO_EXTENSION);
if ($extension && is_string($extension)) {
if (in_array(strtolower($extension), GovcmsFileConstraintInterface::BLOCKED_EXTENSIONS, TRUE)) {
$message = sprintf('\'%s\' file is blocked from uploading ', $extension);
// @todo Remove the uploaded file from the temporary folder as it is blocked
// and do not need anymore.
throw new AccessDeniedHttpException($message);
}
}

return TRUE;
}

}
@@ -0,0 +1,22 @@
<?php

namespace Drupal\govcms_security;

/**
* Provides an interface for constrants on files uploaded.
*/
interface GovcmsFileConstraintInterface {

/**
* A list of blocked file extensions.
*/
public const BLOCKED_EXTENSIONS = ['doc', 'xls', 'ppt', 'rtf'];

/**
* The regex used to extract the filename from the content disposition header.
*
* @var string
*/
public const REQUEST_HEADER_FILENAME_REGEX = '@\bfilename(?<star>\*?)=\"(?<filename>.+)\"@';

}
@@ -0,0 +1,4 @@
name: 'GovCMS File test'
type: module
description: 'Support module for GovCMS file handling tests.'
package: Testing
@@ -0,0 +1,6 @@
govcms.test.file.save_upload_from_form_test:
path: '/govcms-file-test/save_upload_from_form_test'
defaults:
_form: '\Drupal\govcms_file_test\Form\FileTestSaveUploadFromForm'
requirements:
_access: 'TRUE'
@@ -0,0 +1,64 @@
<?php

namespace Drupal\govcms_file_test\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

/**
* File test form class.
*/
class FileTestSaveUploadFromForm extends FormBase {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'govcms_file_test_save_upload_from_form';
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['file_test_upload'] = [
'#type' => 'file',
'#upload_location' => 'temporary://',
'#multiple' => TRUE,
'#title' => $this->t('Upload a file'),
];

// Ajax file upload element.
$form['file_test_ajax'] = [
'#type' => 'managed_file',
'#title' => $this->t('Managed <em>@type</em>', ['@type' => 'file & butter']),
'#upload_location' => 'temporary://',
'#progress_message' => $this->t('Please wait...'),
'#multiple' => TRUE,
];

$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
];
return $form;
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$file = file_save_upload('file_test_upload', [], $form['file_test_upload']['#upload_location'], 0);
if ($file) {
$form_state->setValue('file_test_upload', $file);
\Drupal::messenger()->addStatus(t('File @filepath was uploaded.', ['@filepath' => $file->getFileUri()]));
\Drupal::messenger()->addStatus(t('File name is @filename.', ['@filename' => $file->getFilename()]));
\Drupal::messenger()->addStatus(t('File MIME type is @mimetype.', ['@mimetype' => $file->getMimeType()]));
\Drupal::messenger()->addStatus(t('File uploaded successfully!'));
}
elseif ($file === FALSE) {
\Drupal::messenger()->addError(t('Epic upload FAIL!'));
}
}

}

0 comments on commit cc8bc42

Please sign in to comment.