From c070e989c4de41441d1061d2678b461f3f13d63b Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Wed, 6 Jun 2018 16:45:16 +1200 Subject: [PATCH 1/6] BUG Safely handle empty injector factory responses Fixes issue with ImageBackendFactory returning null and breaking injector --- src/Core/Injector/Injector.php | 5 +++++ tests/php/Core/Injector/InjectorTest.php | 16 ++++++++++++++++ .../Core/Injector/InjectorTest/EmptyFactory.php | 13 +++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 tests/php/Core/Injector/InjectorTest/EmptyFactory.php diff --git a/src/Core/Injector/Injector.php b/src/Core/Injector/Injector.php index bf5fc8b54..6b0885132 100644 --- a/src/Core/Injector/Injector.php +++ b/src/Core/Injector/Injector.php @@ -584,6 +584,11 @@ class Injector implements ContainerInterface $factory = isset($spec['factory']) ? $this->get($spec['factory']) : $this->getObjectCreator(); $object = $factory->create($class, $constructorParams); + // Handle empty factory responses + if (!$object) { + return null; + } + // figure out if we have a specific id set or not. In some cases, we might be instantiating objects // that we don't manage directly; we don't want to store these in the service cache below if (!$id) { diff --git a/tests/php/Core/Injector/InjectorTest.php b/tests/php/Core/Injector/InjectorTest.php index d2a42af76..1e54cc1de 100644 --- a/tests/php/Core/Injector/InjectorTest.php +++ b/tests/php/Core/Injector/InjectorTest.php @@ -14,6 +14,7 @@ use SilverStripe\Core\Tests\Injector\InjectorTest\CircularOne; use SilverStripe\Core\Tests\Injector\InjectorTest\CircularTwo; use SilverStripe\Core\Tests\Injector\InjectorTest\ConstructableObject; use SilverStripe\Core\Tests\Injector\InjectorTest\DummyRequirements; +use SilverStripe\Core\Tests\Injector\InjectorTest\EmptyFactory; use SilverStripe\Core\Tests\Injector\InjectorTest\MyChildClass; use SilverStripe\Core\Tests\Injector\InjectorTest\MyParentClass; use SilverStripe\Core\Tests\Injector\InjectorTest\NeedsBothCirculars; @@ -102,6 +103,21 @@ class InjectorTest extends SapphireTest ); } + public function testEmptyFactory() + { + $this->expectException(InjectorNotFoundException::class); + $injector = new Injector(); + $services = array( + 'SomeClass' => array( + 'class' => AnotherService::class, + 'factory' => EmptyFactory::class, + ) + ); + + $injector->load($services); + $injector->create('SomeClass'); + } + public function testConfiguredInjector() { $injector = new Injector(); diff --git a/tests/php/Core/Injector/InjectorTest/EmptyFactory.php b/tests/php/Core/Injector/InjectorTest/EmptyFactory.php new file mode 100644 index 000000000..3354d6b3f --- /dev/null +++ b/tests/php/Core/Injector/InjectorTest/EmptyFactory.php @@ -0,0 +1,13 @@ + Date: Fri, 1 Jun 2018 16:05:17 +1200 Subject: [PATCH 2/6] BUG Fix issue with Disabled DateField always display (not set). --- src/Forms/DateField.php | 11 ++- src/Forms/DateField_Disabled.php | 50 ++++++++++---- tests/php/Forms/DateField_DisabledTest.php | 79 ++++++++++++++++++++++ 3 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 tests/php/Forms/DateField_DisabledTest.php diff --git a/src/Forms/DateField.php b/src/Forms/DateField.php index 9122aa0b9..5b2ea0474 100644 --- a/src/Forms/DateField.php +++ b/src/Forms/DateField.php @@ -220,6 +220,8 @@ class DateField extends TextField ); } + + if ($this->getHTML5() && $this->locale) { throw new \LogicException( 'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setLocale()' @@ -353,9 +355,12 @@ class DateField extends TextField public function performReadonlyTransformation() { - $field = $this->castedCopy(DateField_Disabled::class); - $field->setValue($this->dataValue()); - $field->setReadonly(true); + $field = $this + ->castedCopy(DateField_Disabled::class) + ->setValue($this->dataValue()) + ->setLocale($this->getLocale()) + ->setReadonly(true); + return $field; } diff --git a/src/Forms/DateField_Disabled.php b/src/Forms/DateField_Disabled.php index e0656f99a..22cd201c3 100644 --- a/src/Forms/DateField_Disabled.php +++ b/src/Forms/DateField_Disabled.php @@ -14,27 +14,51 @@ class DateField_Disabled extends DateField protected $disabled = true; - public function Field($properties = array()) + public function Field($properties = []) { - if ($this->valueObj) { - if ($this->valueObj->isToday()) { - $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('dateformat')) - . ' (' . _t('SilverStripe\\Forms\\DateField.TODAY', 'today') . ')'); + // Default display value + $displayValue = '(' . _t(DateField::class . '.NOTSET', 'not set') . ')'; + + $value = $this->dataValue(); + + if ($value) { + $value = $this->tidyInternal($value); + $df = new DBDate($this->name); + $df->setValue($value); + + if ($df->IsToday()) { + // e.g. 2018-06-01 (today) + $format = '%s (%s)'; + $infoComplement = _t(DateField::class . '.TODAY', 'today'); } else { - $df = new DBDate($this->name); - $df->setValue($this->dataValue()); - $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('dateformat')) - . ', ' . $df->Ago()); + // e.g. 2018-06-01, 5 days ago + $format = '%s, %s'; + $infoComplement = $df->Ago(); } - } else { - $val = '(' . _t('SilverStripe\\Forms\\DateField.NOTSET', 'not set') . ')'; + + // Render the display value with some complement of info + $displayValue = Convert::raw2xml(sprintf( + $format, + $this->Value(), + $infoComplement + )); } - return "ID() . "\">$val"; + return sprintf( + "%s", + $this->ID(), + $displayValue + ); } public function Type() { - return "date_disabled readonly"; + return "date_disabled readonly " . parent::Type(); + } + + public function getHTML5() + { + // Always disable HTML5 feature when using the readonly field. + return false; } } diff --git a/tests/php/Forms/DateField_DisabledTest.php b/tests/php/Forms/DateField_DisabledTest.php new file mode 100644 index 000000000..a8e5e3d1f --- /dev/null +++ b/tests/php/Forms/DateField_DisabledTest.php @@ -0,0 +1,79 @@ +setValue('2011-02-01') + ->Field(); + $expected = '1/02/2011 (today)'; + $this->assertEquals($expected, $actual); + + // Test today's date with time + $actual = DateField_Disabled::create('Test') + ->setValue('2011-02-01 10:34:00') + ->Field(); + $this->assertEquals($expected, $actual); + } + + public function testFieldWithDifferentDay() + { + // Test past + $actual = DateField_Disabled::create('Test') + ->setValue('2011-01-27') + ->Field(); + $expected = '27/01/2011, 5 days ago'; + $this->assertEquals($expected, $actual); + + // Test future + $actual = DateField_Disabled::create('Test') + ->setValue('2011-02-06') + ->Field(); + $expected = '6/02/2011, in 5 days'; + $this->assertEquals($expected, $actual); + } + + public function testFieldWithDifferentLocal() + { + // Test different local + $actual = DateField_Disabled::create('Test') + ->setValue('2011-02-06') + ->setHTML5(false) + ->setLocale('de_DE') + ->Field(); + $expected = '06.02.2011, in 5 days'; + $this->assertEquals($expected, $actual); + } + + public function testFieldWithNonValue() + { + // Test none value + $actual = DateField_Disabled::create('Test')->Field(); + $expected = '(not set)'; + $this->assertEquals($expected, $actual); + + $actual = DateField_Disabled::create('Test')->setValue('This is not a date')->Field(); + $this->assertEquals($expected, $actual); + } +} From 8f03c7df050979c8ec65efb8d6a328fbd427c68f Mon Sep 17 00:00:00 2001 From: Nicolaas Date: Mon, 11 Jun 2018 12:08:02 +1200 Subject: [PATCH 3/6] PATCH: removing duplicate key (SS_TRUSTED_PROXY_HOST_HEADER) --- .upgrade.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.upgrade.yml b/.upgrade.yml index a25ba0b11..a21b7730b 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -1171,8 +1171,6 @@ warnings: message: 'moved to SilverStripe\View\HTML->createTag()' 'SilverStripe\Forms\Form->transformTo()': message: 'Removed' - 'SilverStripe\Forms\Form->callfieldmethod()': - message: 'Removed' 'SilverStripe\Forms\Form::single_field_required()': message: 'Removed' 'SilverStripe\Forms\Form::current_action()': @@ -1323,8 +1321,6 @@ warnings: message: 'Use new asset abstraction' url: 'https://docs.silverstripe.org/en/4/changelogs/4.0.0#asset-storage' constants: - 'SS_TRUSTED_PROXY_HOST_HEADER': - message: 'See TrustedProxyMiddleware' 'SS_TRUSTED_PROXY_PROTOCOL_HEADER': message: 'See TrustedProxyMiddleware' 'SS_TRUSTED_PROXY_IP_HEADER': From 2a51f34c3e3c44acd603def241ac4447e715b165 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Mon, 11 Jun 2018 13:54:27 +1200 Subject: [PATCH 4/6] BUG Prevent canonical URL causing a redirect on CLI unless explicitly enabled Replaces #8157 --- .../Middleware/CanonicalURLMiddleware.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Control/Middleware/CanonicalURLMiddleware.php b/src/Control/Middleware/CanonicalURLMiddleware.php index a43dab80a..b368f4d29 100644 --- a/src/Control/Middleware/CanonicalURLMiddleware.php +++ b/src/Control/Middleware/CanonicalURLMiddleware.php @@ -43,7 +43,8 @@ class CanonicalURLMiddleware implements HTTPMiddleware /** * Environment variables this middleware is enabled in, or a fixed boolean flag to - * apply to all environments + * apply to all environments. cli is disabled unless present here as `cli`, or set to true + * to force enabled. * * @var array|bool */ @@ -292,7 +293,7 @@ class CanonicalURLMiddleware implements HTTPMiddleware } /** - * Get enabled flag, or list of environments to enable in + * Get enabled flag, or list of environments to enable in. * * @return array|bool */ @@ -302,6 +303,10 @@ class CanonicalURLMiddleware implements HTTPMiddleware } /** + * Set enabled flag, or list of environments to enable in. + * Note: CLI is disabled by default, so `"cli"(string)` or `true(bool)` should be specified if you wish to + * enable for testing. + * * @param array|bool $enabledEnvs * @return $this */ @@ -326,6 +331,13 @@ class CanonicalURLMiddleware implements HTTPMiddleware if (is_bool($enabledEnvs)) { return $enabledEnvs; } + + // If CLI, EnabledEnvs must contain CLI + if (Director::is_cli() && !in_array('cli', $enabledEnvs)) { + return false; + } + + // Check other envs return empty($enabledEnvs) || in_array(Director::get_environment_type(), $enabledEnvs); } } From 6d12deb4b9c4515881453914682a33cf894c2ea4 Mon Sep 17 00:00:00 2001 From: Fred Condo Date: Mon, 11 Jun 2018 09:32:40 -0400 Subject: [PATCH 5/6] Update nginx sample configuration for 4.1 - Remove unneeded denials (due to public folder) - Add caveats about public folder, error pages, and HTTPS --- .../01_Installation/How_To/Configure_Nginx.md | 45 +++++-------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md b/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md index 71b5747db..b9dafb44d 100644 --- a/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md +++ b/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md @@ -16,15 +16,19 @@ If you don't fully understand the configuration presented here, consult the Especially be aware of [accidental php-execution](https://nealpoole.com/blog/2011/04/setting-up-php-fastcgi-and-nginx-dont-trust-the-tutorials-check-your-configuration/ "Don't trust the tutorials") when extending the configuration. -But enough of the disclaimer, on to the actual configuration — typically in `nginx.conf`: +## Caveats about the sample configuration below + +* It does not cover serving securely over HTTPS. +* It uses the new filesystem layout (with `public` directory) introduced in version 4.1.0. If your installation has been upgraded to 4.1+ from an older version and you have not [upgraded to the public folder](/changelogs/4.1.0.md), see the version of this documentation for version 4.0. +* The error pages for 502 (Bad Gateway) and 503 (Service Unavailable) need to be manually created and published in the CMS (assuming use of the silverstripe/errorpage module). ```nginx server { include mime.types; default_type application/octet-stream; - client_max_body_size 0; # Manage this in php.ini + client_max_body_size 0; # Manage this in php.ini (upload_max_filesize & post_max_size) listen 80; - root /path/to/ss/folder; + root /path/to/ss/folder/public; server_name example.com www.example.com; # Defend against SS-2015-013 -- http://www.silverstripe.org/software/download/security-releases/ss-2015-013 @@ -39,6 +43,10 @@ server { error_page 404 /assets/error-404.html; error_page 500 /assets/error-500.html; + # See caveats + error_page 502 /assets/error-500.html; + error_page 503 /assets/error-500.html; + location ^~ /assets/ { sendfile on; try_files $uri =404; @@ -54,37 +62,6 @@ server { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } - - # Denials - location ~ /\.. { - deny all; - } - location ~ \.ss$ { - satisfy any; - allow 127.0.0.1; - deny all; - } - location ~ web\.config$ { - deny all; - } - location ~ \.ya?ml$ { - deny all; - } - location ~* README.*$ { - deny all; - } - location ^~ /vendor/ { - deny all; - } - location ~* /silverstripe-cache/ { - deny all; - } - location ~* composer\.(json|lock)$ { - deny all; - } - location ~* /(cms|framework)/silverstripe_version$ { - deny all; - } } ``` From 7b04949caa11d6e5c8cace3453cf2ed29996fb06 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Tue, 12 Jun 2018 15:00:22 +1200 Subject: [PATCH 6/6] BUG Remove duplicate key --- .upgrade.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.upgrade.yml b/.upgrade.yml index a21b7730b..e4e2c392a 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -1181,8 +1181,6 @@ warnings: message: 'Renamed to restoreFormState()' 'SilverStripe\Forms\Form->resetValidation()': message: 'Renamed to clearFormState()' - 'SilverStripe\Forms\Form->transformTo()': - message: 'Removed' 'SilverStripe\Forms\Form->callfieldmethod()': message: 'Removed' 'SilverStripe\Forms\Form->addErrorMessage()':