[TASK] Use JsConfirmation enumeration in BackendUserAuthentication 30/43330/7
authorAndreas Wolf <andreas.wolf@typo3.org>
Sat, 5 Mar 2016 11:56:30 +0000 (12:56 +0100)
committerBenni Mack <benni@typo3.org>
Sun, 6 Mar 2016 00:47:41 +0000 (01:47 +0100)
This makes use of the JsConfirmation enumeration to ensure valid values
in BackendUserAuthentication::jsConfirmation.

As combinations of values are allowed, we need to check for all possible
combinations by comparing to an OR-ed bitmask with all possible bits.
Additionally, this fixes a bug where setting the TSconfig option to "0"
would yield a value of 255, which would enable all notifications instead
of disabling them.

Resolves: #69827
Releases: master
Change-Id: I59b8b8de3efb5c33273ea4c7dfdad2ac25473463
Reviewed-on: https://review.typo3.org/43330
Reviewed-by: Jan Helke <typo3@helke.de>
Tested-by: Jan Helke <typo3@helke.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php
typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php
typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php

index 3a84b9b..57db4e1 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Authentication;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -1204,22 +1205,25 @@ class BackendUserAuthentication extends \TYPO3\CMS\Core\Authentication\AbstractU
     /**
      * Returns TRUE or FALSE, depending if an alert popup (a javascript confirmation) should be shown
      * call like $GLOBALS['BE_USER']->jsConfirmation($BITMASK).
-     * See \TYPO3\CMS\Core\Type\Bitmask\JsConfirmation.
      *
-     * @param int $bitmask Bitmask
+     * @param int $bitmask Bitmask, one of \TYPO3\CMS\Core\Type\Bitmask\JsConfirmation
      * @return bool TRUE if the confirmation should be shown
+     * @see JsConfirmation
      */
     public function jsConfirmation($bitmask)
     {
         $alertPopup = $this->getTSConfig('options.alertPopups');
-        if (empty($alertPopup['value'])) {
-            // Default: show all warnings
-            $alertPopup = 255;
+
+        if (trim((string)$alertPopup['value']) === '') {
+            // Default: show all confirmations
+            $alertPopup = JsConfirmation::ALL;
         } else {
-            $alertPopup = (int)$alertPopup['value'];
+            $alertPopup = $alertPopup['value'];
         }
-        // Show confirmation
-        return ($alertPopup & $bitmask) == $bitmask;
+
+        $bitmask = JsConfirmation::cast($bitmask);
+        $alertPopup = JsConfirmation::cast($alertPopup);
+        return $bitmask->matches($alertPopup);
     }
 
     /**
index 2f0e3ee..ab571e5 100644 (file)
@@ -14,10 +14,13 @@ namespace TYPO3\CMS\Core\Type\Bitmask;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Type\Enumeration;
+use TYPO3\CMS\Core\Type\Exception;
+
 /**
  * A class providing constants for bitwise operations on javascript confirmation popups
  */
-class JsConfirmation extends \TYPO3\CMS\Core\Type\Enumeration
+class JsConfirmation extends Enumeration
 {
     /**
      * @var int
@@ -43,4 +46,69 @@ class JsConfirmation extends \TYPO3\CMS\Core\Type\Enumeration
      * @var int
      */
     const OTHER = 0b10000000;
+
+    /**
+     * @var int
+     */
+    const ALL = 255;
+
+    protected static $allowedValues = self::TYPE_CHANGE | self::COPY_MOVE_PASTE | self::DELETE | self::FE_EDIT | self::OTHER;
+
+    /**
+     * Returns TRUE if a given value matches the internal value
+     *
+     * @param JsConfirmation $value Value to check
+     * @return bool
+     */
+    public function matches(JsConfirmation $value)
+    {
+        $value = (int)(string)$value;
+        $thisValue = (int)$this->value;
+
+        return ($value & $thisValue) == $thisValue;
+    }
+
+    /**
+     * Set the Enumeration value to the associated enumeration value by a loose comparison.
+     * The value, that is used as the enumeration value, will be of the same type like defined in the enumeration
+     *
+     * @param mixed $value
+     * @throws Exception\InvalidEnumerationValueException
+     */
+    protected function setValue($value)
+    {
+        if ($value < 255) {
+            if (($value & self::$allowedValues) !== $value) {
+                throw new Exception\InvalidEnumerationValueException(
+                    sprintf('Invalid value %s for %s', $value, __CLASS__),
+                    1457175152
+                );
+            }
+            $this->value = $value;
+        } else {
+            parent::setValue($value);
+        }
+    }
+
+    /**
+     * Check if the value on this enum is a valid value for the enum
+     *
+     * @param mixed $value
+     * @return bool
+     */
+    protected function isValid($value)
+    {
+        if ($value < 255) {
+            return (($value & self::$allowedValues) === $value);
+        }
+
+        $value = (string)$value;
+        foreach (static::$enumConstants[get_class($this)] as $constantValue) {
+            if ($value === (string)$constantValue) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
index 7f34b2a..6be323a 100644 (file)
@@ -14,8 +14,11 @@ namespace TYPO3\CMS\Core\Tests\Unit\Authentication;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
+
 /**
- * Testcase for \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+ * Testcase for BackendUserAuthentication
  */
 class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
 {
@@ -77,11 +80,11 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         );
 
         // logoff() call the static factory that has a dependency to a valid BE_USER object. Mock this away
-        $GLOBALS['BE_USER'] = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array(), array(), '', false);
+        $GLOBALS['BE_USER'] = $this->getMock(BackendUserAuthentication::class, array(), array(), '', false);
         $GLOBALS['BE_USER']->user = array('uid' => $this->getUniqueId());
         $GLOBALS['TYPO3_DB'] = $this->getMock(\TYPO3\CMS\Core\Database\DatabaseConnection::class, array(), array(), '', false);
 
-        $subject = $this->getAccessibleMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('dummy'), array(), '', false);
+        $subject = $this->getAccessibleMock(BackendUserAuthentication::class, array('dummy'), array(), '', false);
         $subject->_set('db', $GLOBALS['TYPO3_DB']);
         $subject->logoff();
     }
@@ -233,7 +236,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getTSConfigReturnsCorrectArrayForGivenObjectString(array $completeConfiguration, $objectString, array $expectedConfiguration)
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('dummy'), array(), '', false);
+        $subject = $this->getMock(BackendUserAuthentication::class, array('dummy'), array(), '', FALSE);
         $subject->userTS = $completeConfiguration;
 
         $actualConfiguration = $subject->getTSConfig($objectString);
@@ -299,7 +302,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getFilePermissionsTakesUserDefaultPermissionsFromTsConfigIntoAccountIfUserIsNotAdmin(array $userTsConfiguration)
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('isAdmin'));
+        $subject = $this->getMock(BackendUserAuthentication::class, array('isAdmin'));
 
         $subject
             ->expects($this->any())
@@ -434,7 +437,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getFilePermissionsFromStorageOverwritesDefaultPermissions(array $defaultPermissions, $storageUid, array $storagePermissions, array $expectedPermissions)
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('isAdmin', 'getFilePermissions'));
+        $subject = $this->getMock(BackendUserAuthentication::class, array('isAdmin', 'getFilePermissions'));
         $storageMock = $this->getMock(\TYPO3\CMS\Core\Resource\ResourceStorage::class, array(), array(), '', false);
         $storageMock->expects($this->any())->method('getUid')->will($this->returnValue($storageUid));
 
@@ -470,7 +473,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getFilePermissionsFromStorageAlwaysReturnsDefaultPermissionsForAdmins(array $defaultPermissions, $storageUid, array $storagePermissions)
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('isAdmin', 'getFilePermissions'));
+        $subject = $this->getMock(BackendUserAuthentication::class, array('isAdmin', 'getFilePermissions'));
         $storageMock = $this->getMock(\TYPO3\CMS\Core\Resource\ResourceStorage::class, array(), array(), '', false);
         $storageMock->expects($this->any())->method('getUid')->will($this->returnValue($storageUid));
 
@@ -612,7 +615,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdmin($permissionValue, $expectedPermissions)
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('isAdmin'));
+        $subject = $this->getMock(BackendUserAuthentication::class, array('isAdmin'));
 
         $subject
             ->expects($this->any())
@@ -629,7 +632,7 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getFilePermissionsGrantsAllPermissionsToAdminUsers()
     {
-        $subject = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class, array('isAdmin'));
+        $subject = $this->getMock(BackendUserAuthentication::class, array('isAdmin'));
 
         $subject
             ->expects($this->any())
@@ -656,4 +659,50 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
 
         $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
     }
+
+    /**
+     * @test
+     */
+    public function jsConfirmationReturnsTrueIfPassedValueEqualsConfiguration()
+    {
+        $subject = $this->getMock(BackendUserAuthentication::class, ['getTSConfig']);
+        $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 1]);
+
+        $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
+        $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
+    }
+
+    /**
+     * @test
+     */
+    public function jsConfirmationAllowsSettingMultipleBitsInValue()
+    {
+        $subject = $this->getMock(BackendUserAuthentication::class, ['getTSConfig']);
+        $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 3]);
+
+        $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
+        $this->assertTrue($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
+    }
+
+    /**
+     * @test
+     */
+    public function jsConfirmationAlwaysReturnsFalseIfNoConfirmationIsSet()
+    {
+        $subject = $this->getMock(BackendUserAuthentication::class, ['getTSConfig']);
+        $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 0]);
+
+        $this->assertFalse($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
+        $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
+    }
+
+    /**
+     * @test
+     */
+    public function jsConfirmationReturnsTrueIfConfigurationIsMissing()
+    {
+        $subject = $this->getMock(BackendUserAuthentication::class, ['getTSConfig']);
+
+        $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
+    }
 }