Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public
public/*
index.html
composer.lock
.DS_Store


# User-specific stuff:
Expand Down
11 changes: 8 additions & 3 deletions Classes/Controller/FolderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Fixpunkt\FpFileprotector\Domain\Repository\FolderRepository;
use Fixpunkt\FpFileprotector\Resource\Folder;
use Fixpunkt\FpFileprotector\Service\AccessService;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Backend\Attribute\AsController;
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
Expand All @@ -29,6 +30,7 @@ public function __construct(
protected readonly IconFactory $iconFactory,
protected readonly FolderRepository $folderRepository,
protected readonly StorageRepository $storageRepository,
protected readonly AccessService $accessService,
) {}

/**
Expand Down Expand Up @@ -56,7 +58,10 @@ public function showAction(string $id = "", bool $refreshFolderTree = false): Re
$moduleTemplate = $this->moduleTemplateFactory->create($this->request);
$this->initializeDocHeader($moduleTemplate, $folder);
$this->statusCheck($folder);
$moduleTemplate->assign('folder', $folder);
$moduleTemplate->assignMultiple([
'folder' => $folder,
'propertiesPartials' => $this->accessService->getPropertiesPartials(),
]);
return $moduleTemplate->renderResponse('Folder/Show');
}

Expand Down Expand Up @@ -95,9 +100,9 @@ protected function initializeDocHeader(ModuleTemplate $moduleTemplate, Folder $f
$moduleTemplate->getDocHeaderComponent()->setMetaInformationForResource($folder);

$editStorageUri = $this->uriBuilder->reset()
->uriFor('edit', ['fileStorageUid' => $folder->getStorage()->getUid()], 'FileStorage');
->uriFor('edit', ['fileStorageUid' => $folder->getStorage()->getUid(), 'id' => $folder->getCombinedIdentifier()], 'FileStorage');
$htaccessUri = $this->uriBuilder->reset()
->uriFor('htaccess', ['fileStorageUid' => $folder->getStorage()->getUid()], 'FileStorage');
->uriFor('htaccess', ['fileStorageUid' => $folder->getStorage()->getUid(), 'id' => $folder->getCombinedIdentifier()], 'FileStorage');

// add buttons
$buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar();
Expand Down
4 changes: 4 additions & 0 deletions Classes/Controller/ProtectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Fixpunkt\FpFileprotector\Domain\Repository\FrontendUserGroupRepository;
use Fixpunkt\FpFileprotector\Domain\Repository\FrontendUserRepository;
use Fixpunkt\FpFileprotector\Domain\Repository\ProtectionRepository;
use Fixpunkt\FpFileprotector\Service\AccessService;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Backend\Attribute\AsController;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
Expand All @@ -28,6 +29,7 @@ public function __construct(
protected readonly FrontendUserGroupRepository $userGroupRepository,
protected readonly FrontendUserRepository $userRepository,
protected readonly FolderRepository $folderRepository,
protected readonly AccessService $accessService,
) {
$querySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class);
$querySettings->setRespectStoragePage(false);
Expand All @@ -50,6 +52,7 @@ public function newAction(string $combinedIdentifier): ResponseInterface
'folder' => $this->folderRepository->findOneByCombinedIdentifier($combinedIdentifier),
'userGroups' => $this->userGroupRepository->findAll(),
'users' => $this->userRepository->findAll(),
'accessPartials' => $this->accessService->getPartials(),
]);

return $moduleTemplate->renderResponse('Protection/New');
Expand Down Expand Up @@ -87,6 +90,7 @@ public function editAction(Protection $protection): ResponseInterface
'folder' => $protection->getFolderObject(),
'userGroups' => $this->userGroupRepository->findAll(),
'users' => $this->userRepository->findAll(),
'accessPartials' => $this->accessService->getPartials(),
]);

return $moduleTemplate->renderResponse('Protection/Edit');
Expand Down
44 changes: 2 additions & 42 deletions Classes/Domain/Model/Protection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

use Fixpunkt\FpFileprotector\Domain\Repository\FolderRepository;
use Fixpunkt\FpFileprotector\Resource\Folder;
use Fixpunkt\FpFileprotector\Utility\FrontendUserUtility;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
Expand Down Expand Up @@ -177,50 +175,12 @@ public function removeUser(FrontendUser $user): void
}

/**
* Checks whether the current user is allowed to access the resource.
*
* @return bool
*/
public function isGranted(): bool
{
if ($this->isFeLogin()) {
$frontendUserUtility = GeneralUtility::makeInstance(FrontendUserUtility::class);
$feUser = $frontendUserUtility->getCurrentFrontendUser();
if ($feUser && $feUser->isLoggedIn()) {
if ($this->getUserGroups()->count() === 0 && $this->getUsers()->count() === 0) {
return true;
}

if (in_array($feUser->get('id'), $this->getUsersUids(), true)) {
return true;
}

foreach ($feUser->get('groupIds') as $userGroupId) {
if (in_array($userGroupId, $this->getUserGroupsUids(), true)) {
return true;
}
}
}
}

$context = GeneralUtility::makeInstance(Context::class);
if (
$this->isBeLogin()
&& (bool)$context->getPropertyFromAspect('backend.user', 'isLoggedIn')
) {
return true;
}

return false;
}

/**
* Returns whether the folder protection applies any restrictions.
* Returns whether the folder protection applies any FE restrictions.
*
* @return bool
*/
public function isProtected(): bool
{
return $this->isFeLogin() || $this->isBeLogin();
return $this->isFeLogin();
}
}
4 changes: 2 additions & 2 deletions Classes/Domain/Repository/FileStorageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ public function update(ResourceStorage $fileStorage): void
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('sys_file_storage')->createQueryBuilder();
$queryBuilder
->update('sys_file_storage')
->set('protected', $fileStorage->isProtected())
->set('protected_by_default', $fileStorage->isProtectedByDefault() ?: 0)
->set('protected', (int)$fileStorage->isProtected())
->set('protected_by_default', (int)$fileStorage->isProtectedByDefault())
->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($fileStorage->getUid())))
->executeStatement();
}
Expand Down
16 changes: 9 additions & 7 deletions Classes/Middleware/AccessMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Fixpunkt\FpFileprotector\Middleware;

use Fixpunkt\FpFileprotector\Domain\Repository\ProtectionRepository;
use Fixpunkt\FpFileprotector\Service\AccessService;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
Expand All @@ -16,10 +17,11 @@
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Resource\StorageRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;

class AccessMiddleware implements MiddlewareInterface
{
public function __construct(private readonly AccessService $accessService) {}

public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
Expand All @@ -44,7 +46,7 @@ public function process(

$storage = $this->getStorage($storageIdentifier);
if (!$storage) {
return $this->createError(LocalizationUtility::translate('sys_file_storage.errors.storage_not_found', 'FpFileprotector'));
return $this->createError('The storage could not be found.');
}
$protected = $storage->getStorageRecord()['protected'];
$protectedByDefault = $storage->getStorageRecord()['protected_by_default'];
Expand All @@ -65,7 +67,7 @@ public function process(
)
)
) {
return $this->createError(LocalizationUtility::translate('sys_file_storage.errors.file_not_found', 'FpFileprotector'));
return $this->createError('The file could not be found.');
}
$originalFile = $file;
if ($originalFile instanceof ProcessedFile) {
Expand All @@ -78,14 +80,14 @@ public function process(

$folder = $originalFile->getParentFolder();
if (!$folder) {
return $this->createError(LocalizationUtility::translate('sys_file_storage.errors.folder_not_found', 'FpFileprotector'));
return $this->createError('The storage location could not be found.');
}

$protection = ProtectionRepository::getProtectionStatic($folder);
if ((!$protection && !$protectedByDefault) || ($protection && $protection->isGranted())) {
if ((!$protection && !$protectedByDefault) || ($protection && $this->accessService->isGranted($protection))) {
return $this->releaseFile($storage, $filePath);
}
return $this->createError(LocalizationUtility::translate('sys_file_storage.errors.access_denied', 'FpFileprotector'), 500);
return $this->createError('You do not have permission to access this file.', 500);
}

/**
Expand Down Expand Up @@ -134,7 +136,7 @@ private function releaseFile(ResourceStorage $storage, string $fileIdentifier):
{
$file = $storage->getFile($fileIdentifier);
if (!$file) {
return $this->createError(LocalizationUtility::translate('sys_file_storage.errors.file_release_not_found', 'FpFileprotector'));
return $this->createError('The requested file could not be found.');
}

$body = new Stream('php://temp', 'rw');
Expand Down
44 changes: 44 additions & 0 deletions Classes/Service/AccessService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Fixpunkt\FpFileprotector\Service;

use Fixpunkt\FpFileprotector\Domain\Model\Protection;
use Fixpunkt\FpFileprotector\Utility\Access\AccessUtilityInterface;

class AccessService
{
/** @param iterable<AccessUtilityInterface> $accessUtilities */
public function __construct(private readonly iterable $accessUtilities) {}

public function isGranted(Protection $protection): bool
{
foreach ($this->accessUtilities as $utility) {
if ($utility->isGranted($protection)) {
return true;
}
}
return false;
}

/** @return string[] */
public function getPartials(): array
{
$partials = [];
foreach ($this->accessUtilities as $utility) {
$partials[] = $utility->getPartial();
}
return $partials;
}

/** @return string[] */
public function getPropertiesPartials(): array
{
$partials = [];
foreach ($this->accessUtilities as $utility) {
$partials[] = $utility->getPropertiesPartial();
}
return $partials;
}
}
14 changes: 14 additions & 0 deletions Classes/Utility/Access/AccessUtilityInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Fixpunkt\FpFileprotector\Utility\Access;

use Fixpunkt\FpFileprotector\Domain\Model\Protection;

interface AccessUtilityInterface
{
public function isGranted(Protection $protection): bool;
public function getPartial(): string;
public function getPropertiesPartial(): string;
}
48 changes: 48 additions & 0 deletions Classes/Utility/Access/BeLoginAccessUtility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Fixpunkt\FpFileprotector\Utility\Access;

use Fixpunkt\FpFileprotector\Domain\Model\Protection;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;

class BeLoginAccessUtility implements AccessUtilityInterface
{
public function isGranted(Protection $protection): bool
{
/** @var BackendUserAuthentication|null $beUser */
$beUser = $GLOBALS['BE_USER'] ?? null;
if (!$beUser || empty($beUser->user['uid'])) {
return false;
}

if ($beUser->isAdmin()) {
return true;
}

foreach ($beUser->getFileStorages() as $storage) {
if ($storage->getUid() !== $protection->getStorage()) {
continue;
}
try {
$folder = $storage->getFolder($protection->getFolder());
return $storage->isWithinFileMountBoundaries($folder, false);
} catch (\Exception) {
return false;
}
}

return false;
}

public function getPartial(): string
{
return 'Access/Be';
}

public function getPropertiesPartial(): string
{
return 'Properties/Be';
}
}
51 changes: 51 additions & 0 deletions Classes/Utility/Access/FeLoginAccessUtility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Fixpunkt\FpFileprotector\Utility\Access;

use Fixpunkt\FpFileprotector\Domain\Model\Protection;
use Fixpunkt\FpFileprotector\Utility\FrontendUserUtility;

class FeLoginAccessUtility implements AccessUtilityInterface
{
public function __construct(private readonly FrontendUserUtility $frontendUserUtility) {}

public function isGranted(Protection $protection): bool
{
if (!$protection->isFeLogin()) {
return false;
}

$feUser = $this->frontendUserUtility->getCurrentFrontendUser();
if (!$feUser || !$feUser->isLoggedIn()) {
return false;
}

if ($protection->getUserGroups()->count() === 0 && $protection->getUsers()->count() === 0) {
return true;
}

if (in_array($feUser->get('id'), $protection->getUsersUids(), true)) {
return true;
}

foreach ($feUser->get('groupIds') as $userGroupId) {
if (in_array($userGroupId, $protection->getUserGroupsUids(), true)) {
return true;
}
}

return false;
}

public function getPartial(): string
{
return 'Access/Fe';
}

public function getPropertiesPartial(): string
{
return 'Properties/Fe';
}
}
Loading
Loading