From 41b9b1e8c57ace5db43e80d3c71cb507cfc9a748 Mon Sep 17 00:00:00 2001
From: Mathias Brodala <mbrodala@pagemachine.de>
Date: Fri, 14 Oct 2016 10:29:27 +0200
Subject: [PATCH] [BUGFIX] Fix unset bits in options.alertPopup bitmask

The validation in JsConfirmation did not allow for a value
based on JsConfirmation:ALL with some bits unset.

Change-Id: I74d43d59ee3cd06498bbebd6b7b7682ca1d79cd5
Resolves: #78240
Releases: master, 8.7
Reviewed-on: https://review.typo3.org/50223
Reviewed-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Reviewed-by: Reiner Teubner <rteubner@me.com>
Tested-by: Reiner Teubner <rteubner@me.com>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 .../Classes/Type/Bitmask/JsConfirmation.php   | 24 +++------
 .../BackendUserAuthenticationTest.php         | 50 +++++++++++++++++++
 2 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php b/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php
index bfc6ab20148a..b0a7d73a99bf 100644
--- a/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php
+++ b/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php
@@ -52,6 +52,9 @@ class JsConfirmation extends Enumeration
      */
     const ALL = 255;
 
+    /**
+     * @var int
+     */
     const __default = self::ALL;
 
     /**
@@ -84,13 +87,7 @@ class JsConfirmation extends Enumeration
      */
     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
-                );
-            }
+        if ($this->isValid($value)) {
             $this->value = $value;
         } else {
             parent::setValue($value);
@@ -106,15 +103,10 @@ class JsConfirmation extends Enumeration
     protected function isValid($value)
     {
         if ($value < 255) {
-            return ($value & self::$allowedValues) === $value;
-        }
-
-        $value = (string)$value;
-        foreach (static::$enumConstants[static::class] as $constantValue) {
-            if ($value === (string)$constantValue) {
-                return true;
-            }
+            // Check for combined bitmask or bitmask with bits unset from self::ALL
+            $unsetValues = (self::ALL ^ $value);
+            return ($value & self::$allowedValues) === $value || $unsetValues === ($unsetValues & self::$allowedValues);
         }
-        return false;
+        return parent::isValid($value);
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php b/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php
index 235b0823fbc7..a8266796cb53 100644
--- a/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php
+++ b/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php
@@ -743,6 +743,56 @@ class BackendUserAuthenticationTest extends UnitTestCase
         $this->assertTrue($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
     }
 
+    /**
+     * @test
+     * @dataProvider jsConfirmationsWithUnsetBits
+     *
+     * @param int $jsConfirmation
+     * @param int $typeChangeAllowed
+     * @param int $copyMovePasteAllowed
+     * @param int $deleteAllowed
+     * @param int $feEditAllowed
+     * @param int $otherAllowed
+     */
+    public function jsConfirmationAllowsUnsettingBitsInValue($jsConfirmation, $typeChangeAllowed, $copyMovePasteAllowed, $deleteAllowed, $feEditAllowed, $otherAllowed)
+    {
+        $subject = $this->getMockBuilder(BackendUserAuthentication::class)
+            ->setMethods(['getTSConfig'])
+            ->getMock();
+        $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => $jsConfirmation]);
+
+        $this->assertEquals($typeChangeAllowed, $subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
+        $this->assertEquals($copyMovePasteAllowed, $subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
+        $this->assertEquals($deleteAllowed, $subject->jsConfirmation(JsConfirmation::DELETE));
+        $this->assertEquals($feEditAllowed, $subject->jsConfirmation(JsConfirmation::FE_EDIT));
+        $this->assertEquals($otherAllowed, $subject->jsConfirmation(JsConfirmation::OTHER));
+    }
+
+    /**
+     * @return array
+     */
+    public function jsConfirmationsWithUnsetBits()
+    {
+        return [
+            'All except "type change" and "copy/move/paste"' => [
+                252,
+                false,
+                false,
+                true,
+                true,
+                true,
+            ],
+            'All except "other"' => [
+                127,
+                true,
+                true,
+                true,
+                true,
+                false,
+            ],
+        ];
+    }
+
     /**
      * @test
      */
-- 
GitLab