Commit 8a79bfa5 authored by Andreas Wolf's avatar Andreas Wolf Committed by Benni Mack
Browse files

[TASK] Use JsConfirmation enumeration in BackendUserAuthentication

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's avatarJan Helke <typo3@helke.de>
Tested-by: Jan Helke's avatarJan Helke <typo3@helke.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 0b7eb76c
......@@ -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);
}
/**
......
......@@ -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;
}
}
......@@ -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));
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment