diff --git a/Classes/Hooks/FileDumpHook.php b/Classes/Hooks/FileDumpHook.php index cd02f04..b4f64b0 100644 --- a/Classes/Hooks/FileDumpHook.php +++ b/Classes/Hooks/FileDumpHook.php @@ -79,6 +79,11 @@ class FileDumpHook implements FileDumpEIDHookInterface */ protected $resumableDownload = false; + /** + * @var $checkPermissionsService CheckPermissions + */ + protected $checkPermissionsService = false; + /** * Constructor */ @@ -102,6 +107,9 @@ public function __construct() $this->forceDownloadForExt = ExtensionConfiguration::forceDownloadForExt(); } $this->resumableDownload = ExtensionConfiguration::resumableDownload(); + + $this->checkPermissionsService = GeneralUtility::makeInstance(CheckPermissions::class); + } /** @@ -173,10 +181,55 @@ public function checkFileAccess(ResourceInterface $file) // Dump the precise requested file for File and ProcessedFile, but dump the referenced file for FileReference $dumpFile = $file instanceof FileReference ? $file->getOriginalFile() : $file; - if ($this->forceDownload($dumpFile->getExtension())) { - $this->dumpFileContents($dumpFile, true, $this->resumableDownload); - } elseif ($this->resumableDownload) { - $this->dumpFileContents($dumpFile, false, true); + // check Time Restrictions from File Meta + $fileMeta = $dumpFile->getProperties(); + + + $condition1 = $fileMeta['starttime'] <= date('U'); // start lower than now + $condition2 = $fileMeta['starttime'] == 0; // start not set + $condition1_2 = ( $condition1 || $condition2 ); + $condition3 = $fileMeta['endtime'] >= date('U'); // end greater than now + $condition4 = $fileMeta['endtime'] == 0; // end not set + $condition3_4 = ( $condition3 || $condition4 ); + +// debug([ +// '1: $fileMeta[starttime] <= date(U)' => $con1, +// '2: $fileMeta[starttime] == 0'=> $con2, +// '1_2: 1||2' => $con1_2, +// '3: $fileMeta[endtime] >= date(U)'=> $con3, +// '4: $fileMeta[endtime] == 0'=> $con4, +// '3_4: 3||4' => $con3_4, +// '1_2 && 3_4' => ( $con1_2 && $con3_4), +// 'now' => date('U') +// ]); + + + if ( $condition1_2 && $condition3_4 ) { + // access inside period +// debug([ +// 'access'=>'granted', +// 'meta' => $fileMeta , +// 'now' => date ('d-m-Y H:i:s',date('U')), +// 'start' => date ('d-m-Y H:i:s',$fileMeta['starttime']), +// 'end' => date ('d-m-Y H:i:s',$fileMeta['endtime']) +// ]); exit; + + if ($this->forceDownload($dumpFile->getExtension())) { + $this->dumpFileContents($dumpFile, true, $this->resumableDownload); + } elseif ($this->resumableDownload) { + $this->dumpFileContents($dumpFile, false, true); + } + } else { + // no access outside this period +// debug([ +// 'access'=>'denied', +// 'meta' => $fileMeta , +// 'now' => date('U'), +// 'start' => date ('d-m-Y H:i:s',$fileMeta['starttime']), +// 'end' => date ('d-m-Y H:i:s',$fileMeta['endtime']) +// ]);exit; + header('HTTP/1.1 404 File not found'); + exit; } } @@ -226,6 +279,13 @@ protected function dumpFileContents($file, $asDownload, $resumableDownload) exit; } + // Find part of file and push this out + $filePointer = @fopen($file->getForLocalProcessing(false), 'rb'); + if ($filePointer === false) { + header('HTTP/1.1 404 File not found'); + exit; + } + $dumpSize = $fileSize; list($begin, $end) = $range; if ($begin !== 0 || $end !== $fileSize - 1) { diff --git a/Classes/Security/CheckPermissions.php b/Classes/Security/CheckPermissions.php index dba8b32..d1064e0 100644 --- a/Classes/Security/CheckPermissions.php +++ b/Classes/Security/CheckPermissions.php @@ -86,6 +86,10 @@ public function checkFileAccess($file, $userFeGroups) return true; } + if( !$this->checkFileAccessForTimePeriod( $file ) ){ + return false; + } + $customUserGroups = []; /** @var Dispatcher $signalSlotDispatcher */ $signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class); @@ -101,6 +105,11 @@ public function checkFileAccess($file, $userFeGroups) /** @var Folder $parentFolder */ $parentFolder = $file->getParentFolder(); + + if( !$this->checkFolderAccessForTimePeriod($parentFolder) ){ + return false; + } + // check folder access if ($this->checkFolderRootLineAccess($parentFolder, $userFeGroups)) { // access to folder then check file privileges if present @@ -113,6 +122,78 @@ public function checkFileAccess($file, $userFeGroups) return false; } + /** + * Check if the folder start and stop date is set and if the current date is in the period. + * + * possible are only start date, start and end date, only end date + * + * TODO: implement check folder times + * + * @param Folder $folder + * @return bool + */ + public function checkFolderAccessForTimePeriod(Folder $folder){ + // loop through the root line of an folder and check the permissions of every folder + $access = true; + $rootlineTree = array_slice($this->getFolderRootLine($folder),1); + + foreach ($rootlineTree as $rootlinefolder) { + // fetch folder permissions record + $folderRecord = $this->utilityService->getFolderRecord($rootlinefolder); + + // if no record found the folder in rootline has no access so subfolders have'nt also + if (!$folderRecord) { + $access = false; + break; + } + } + return $access; + } + + public function checkAccessForTimePeriod( $dataRecord ){ + + $condition1 = $dataRecord['starttime'] <= date('U'); // start lower than now + $condition2 = $dataRecord['starttime'] == 0; // start not set + $condition1_2 = ( $condition1 || $condition2 ); + $condition3 = $dataRecord['endtime'] >= date('U'); // end greater than now + $condition4 = $dataRecord['endtime'] == 0; // end not set + $condition3_4 = ( $condition3 || $condition4 ); + +// debug([ +// 'access' => ($condition1_2 && $condition3_4) ? 'granted' : 'dismissed', +// 'meta' => $dataRecord, +// 'now' => date ('d-m-Y H:i:s',date('U')), +// 'start' => date ('d-m-Y H:i:s',$dataRecord['starttime']), +// 'end' => date ('d-m-Y H:i:s',$dataRecord['endtime']), +// 'now' => date('U'), +// 'condition results' => [ +// '1: $fileMeta[starttime] <= date(U)' => $condition1, +// '2: $fileMeta[starttime] == 0'=> $condition2, +// '1_2: 1||2' => $condition1_2, +// '3: $fileMeta[endtime] >= date(U)'=> $condition3, +// '4: $fileMeta[endtime] == 0'=> $condition4, +// '3_4: 3||4' => $condition3_4, +// 'final' => ( $condition1_2 && $condition3_4), +// ] +// ]); exit; + + return $condition1_2 && $condition3_4; + } + /** + * Check if the file start and stop date is set and if the current date is in the period. + * + * possible are only start date, start and end date, only end date + * + * @param \TYPO3\CMS\Core\Resource\File $file + * @return bool + */ + public function checkFileAccessForTimePeriod(File $file){ + + // check Time Restrictions from File Meta + $fileMeta = $file->getProperties(); + return $this->checkAccessForTimePeriod($fileMeta); + } + /** * Check if given FeGroups have enough rights to access given folder * @@ -127,7 +208,6 @@ public function checkFolderRootLineAccess(Folder $folder, $userFeGroups) $folder->getHashedIdentifier() . serialize($userFeGroups) ); - if (!isset($this->checkFolderRootLineAccessCache[$cacheIdentifier])) { $this->checkFolderRootLineAccessCache[$cacheIdentifier] = true; diff --git a/Classes/Service/Utility.php b/Classes/Service/Utility.php index 9fd491a..b2f8ba0 100644 --- a/Classes/Service/Utility.php +++ b/Classes/Service/Utility.php @@ -74,7 +74,8 @@ public function getFolderRecord(Folder $folder) // cache results self::$folderRecordCache[$folder->getCombinedIdentifier()] = $record; } - +// debug($queryBuilder->getSQL()); +// debug($queryBuilder->getParameters()); return self::$folderRecordCache[$folder->getCombinedIdentifier()]; } diff --git a/Classes/ViewHelpers/Security/AssetAccessViewHelper.php b/Classes/ViewHelpers/Security/AssetAccessViewHelper.php index 0b4ced3..a74d5f0 100644 --- a/Classes/ViewHelpers/Security/AssetAccessViewHelper.php +++ b/Classes/ViewHelpers/Security/AssetAccessViewHelper.php @@ -24,6 +24,7 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use BeechIt\FalSecuredownload\Service\Utility; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Resource\Folder; @@ -73,6 +74,19 @@ protected static function evaluateCondition($arguments = null) $userFeGroups = self::getFeUserGroups(); $access = false; + if($folder){ + $utility = GeneralUtility::makeInstance(Utility::class); + $folderRecord = $utility->getFolderRecord($folder); + /* folder record automaticly disapears if start stop date is out of range, + * seems to be some native function... + */ + //debug($folderRecord); + if(!$folderRecord){ + // Return with no access... no more need to check file permissions + return false; + } + } + // check folder access if ($checkPermissionsService->checkFolderRootLineAccess($folder, $userFeGroups)) { if ($file === null) { diff --git a/Configuration/TCA/Overrides/sys_file_metadata.php b/Configuration/TCA/Overrides/sys_file_metadata.php index 431f767..426e29f 100644 --- a/Configuration/TCA/Overrides/sys_file_metadata.php +++ b/Configuration/TCA/Overrides/sys_file_metadata.php @@ -28,5 +28,48 @@ ] ]; +$GLOBALS['TCA']['sys_file_metadata'] = array_merge_recursive( + $GLOBALS['TCA']['sys_file_metadata'], + [ + 'ctrl'=>[ +// 'enablecolumns' => [ +// 'starttime' => 'starttime', +// 'endtime' => 'endtime', +// ] + ], + 'columns' => [ + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0 + ] + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0 + ] + ] + ], + 'palettes' => [ + 'timeRestriction' => ['showitem' => 'starttime, endtime'] + ], + ] +); + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('sys_file_metadata', $additionalColumns); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('sys_file_metadata', 'fe_groups'); + +// Add new Palette with Time Settings +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes( + 'sys_file_metadata', + '--div--;LLL:EXT:fal_securedownload/Resources/Private/Language/locallang_db.xlf:timeRestrictions, + --palette--;;timeRestriction'); diff --git a/Configuration/TCA/tx_falsecuredownload_folder.php b/Configuration/TCA/tx_falsecuredownload_folder.php index 5de07ff..434b6aa 100644 --- a/Configuration/TCA/tx_falsecuredownload_folder.php +++ b/Configuration/TCA/tx_falsecuredownload_folder.php @@ -13,15 +13,26 @@ 'ignoreWebMountRestriction' => true, 'ignoreRootLevelRestriction' => true, ], + 'enablecolumns' => [ + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'iconfile' => 'EXT:fal_securedownload/Resources/Public/Icons/folder.png' ], 'interface' => [ - 'showRecordFieldList' => 'fe_groups, storage, folder, folder_hash' + 'showRecordFieldList' => 'fe_groups, storage, folder, folder_hash, starttime, endtime' ], 'types' => [ - '0' => ['showitem' => 'fe_groups,--palette--;;filePalette'], + '0' => ['showitem' => '--div--;LLL:EXT:fal_securedownload/Resources/Private/Language/locallang_db.xlf:feGroupAccess, + --palette--;;accessPalette, + --palette--;;filePalette, + --div--;LLL:EXT:fal_securedownload/Resources/Private/Language/locallang_db.xlf:timeRestrictions, + --palette--;;timeRestriction'], ], 'palettes' => [ + 'accessPalette' => [ 'showitem' => 'fe_groups' ], + 'timeRestriction' => ['showitem' => 'starttime, endtime'], // File palette, hidden but needs to be included all the time 'filePalette' => [ 'showitem' => 'storage, folder, folder_hash', @@ -80,6 +91,26 @@ 'foreign_table_where' => 'ORDER BY fe_groups.title', 'enableMultiSelectFilterTextfield' => true, ] + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0 + ] + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0 + ] ] ] ]; diff --git a/Configuration/TypoScript/setup.txt b/Configuration/TypoScript/setup.txt index 1f0b547..72b3bbb 100644 --- a/Configuration/TypoScript/setup.txt +++ b/Configuration/TypoScript/setup.txt @@ -36,4 +36,21 @@ page.jsFooterInline.303030.value ( $(this).next('ul').slideDown(); } }); -) \ No newline at end of file +) + +#config.tx_extbase { +# objects { +# TYPO3\CMS\Core\Resource\Folder { +# className = BeechIt\FalSecuredownload\Resource\Folder +# } +# } +# persistence { +# classes { +# BeechIt\FalSecuredownload\Resource\Folder { +# mapping { +# tableName = tx_falsecuredownload_folder +# } +# } +# } +# } +#} \ No newline at end of file diff --git a/README.md b/README.md index a4c1656..6a4e714 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ The access to assets can be set on folder/file bases by setting access to fe_gro - Restrict FE access on folder level - Restrict FE access on file level +- Restrict FE access by start/stop datetime on folder level +- Restrict FE access by start/stop datetime on file level - Let editor set permissions in file list - Force download for all files (for protected file storages) - Force download for specific file extensions (for protected file storages) diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf index 5f91bd2..a5a5bf3 100644 --- a/Resources/Private/Language/locallang_db.xlf +++ b/Resources/Private/Language/locallang_db.xlf @@ -13,7 +13,12 @@ Folder - + + Access FE Group/User + + + Time Restrictions + \ No newline at end of file diff --git a/ext_tables.sql b/ext_tables.sql index 71aeeb8..1b3c568 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -13,6 +13,9 @@ CREATE TABLE tx_falsecuredownload_folder ( folder text, folder_hash varchar(40) DEFAULT '' NOT NULL, + starttime int(11) DEFAULT '0' NOT NULL, + endtime int(11) DEFAULT '0' NOT NULL, + # FE permissions fe_groups tinytext, @@ -25,7 +28,10 @@ CREATE TABLE tx_falsecuredownload_folder ( # CREATE TABLE sys_file_metadata ( # FE permissions - fe_groups tinytext + fe_groups tinytext, + + starttime int(11) DEFAULT '0' NOT NULL, + endtime int(11) DEFAULT '0' NOT NULL ); CREATE TABLE tx_falsecuredownload_download (