Commit 21a38e79 authored by Jochen Roth's avatar Jochen Roth Committed by Christian Kuhn
Browse files

[BUGFIX] Properly check permissions for system notes

The NoteController, used to display system notes in a
couple of modules, e.g. page layout, does now properly
check the corresponding user permissions (show/edit/delete).

Resolves: #96037
Releases: master, 11.5
Change-Id: Ic0e6670f7befa23802382c0818454c4e7c34a253
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72237

Tested-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent b5246ec9
......@@ -178,7 +178,7 @@ class DatabaseUserPermissionCheck implements FormDataProviderInterface
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] as $methodReference) {
$parameters = [
'table' => $result['tableName'],
'uid' => $result['databaseRow']['uid'],
'uid' => $result['databaseRow']['uid'] ?? 0,
'cmd' => $result['command'],
'hasAccess' => $userHasAccess,
];
......
......@@ -17,6 +17,9 @@ declare(strict_types=1);
namespace TYPO3\CMS\SysNote\Controller;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository;
......@@ -33,6 +36,8 @@ class NoteController
*/
protected $notesRepository;
protected array $pagePermissionCache = [];
public function __construct()
{
$this->notesRepository = GeneralUtility::makeInstance(SysNoteRepository::class);
......@@ -47,22 +52,59 @@ class NoteController
*/
public function listAction($pids, int $position = null): string
{
if (empty($pids) || empty($GLOBALS['BE_USER']->user['uid'])) {
$backendUser = $this->getBackendUser();
if (empty($pids)
|| empty($backendUser->user[$backendUser->userid_column])
|| !$backendUser->check('tables_select', 'sys_note')
) {
return '';
}
$notes = $this->notesRepository->findByPidsAndAuthorId($pids, (int)$GLOBALS['BE_USER']->user['uid'], $position);
if ($notes) {
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
'EXT:sys_note/Resources/Private/Templates/Note/List.html'
));
$view->setLayoutRootPaths(['EXT:sys_note/Resources/Private/Layouts']);
$view->getRequest()->setControllerExtensionName('SysNote');
$view->assign('notes', $notes);
return $view->render();
$notes = $this->notesRepository->findByPidsAndAuthorId($pids, (int)$backendUser->user[$backendUser->userid_column], $position);
if (!$notes) {
return '';
}
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
'EXT:sys_note/Resources/Private/Templates/Note/List.html'
));
$view->setLayoutRootPaths(['EXT:sys_note/Resources/Private/Layouts']);
$view->getRequest()->setControllerExtensionName('SysNote');
$view->assign('notes', $this->enrichWithEditPermissions($notes));
return $view->render();
}
protected function enrichWithEditPermissions(array $notes): array
{
$backendUser = $this->getBackendUser();
$hasEditAccess = $backendUser->isAdmin() || $backendUser->check('tables_modify', 'sys_note');
foreach ($notes as &$note) {
if (!$hasEditAccess) {
// If no edit access, disable edit and delete options for all notes
$note['canBeEdited'] = false;
$note['canBeDeleted'] = false;
continue;
}
// Check content edit permissions for the note
$pid = (int)($note['pid'] ?? 0);
if (!isset($this->pagePermissionCache[$pid])) {
// Calculate and cache the content edit permissions for this $pid
$permissionClause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW);
$pageRow = BackendUtility::readPageAccess($pid, $permissionClause) ?: [];
$this->pagePermissionCache[$pid] = $backendUser->doesUserHaveAccess($pageRow, Permission::CONTENT_EDIT);
}
$note['canBeEdited'] = $this->pagePermissionCache[$pid];
// For delete, also take user TSconfig into account
$note['canBeDeleted'] = $this->pagePermissionCache[$pid]
&& !(bool)trim($backendUser->getTSConfig()['options.']['disableDelete.']['sys_note'] ?? $backendUser->getTSConfig()['options.']['disableDelete'] ?? '');
}
return '';
return $notes;
}
protected function getBackendUser(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}
......@@ -31,12 +31,16 @@
</f:if>
<span class="note-actions">
<span class="btn-group">
<be:link.editRecord uid="{note.uid}" table="sys_note" class="btn btn-default btn-sm">
<core:icon identifier="actions-open" />
</be:link.editRecord>
<a href="{be:moduleLink(route:'tce_db', query:'cmd[sys_note][{note.uid}][delete]=1', currentUrlParameterName:'redirect')}" class="btn btn-default btn-sm t3js-modal-trigger" data-severity="warning" data-title="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:delete')}" data-bs-content="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf:deleteWarning')}" data-button-close-text="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel')}">
<core:icon identifier="actions-edit-delete" />
</a>
<f:if condition="{note.canBeEdited}">
<be:link.editRecord uid="{note.uid}" table="sys_note" class="btn btn-default btn-sm">
<core:icon identifier="actions-open" />
</be:link.editRecord>
</f:if>
<f:if condition="{note.canBeDeleted}">
<a href="{be:moduleLink(route:'tce_db', query:'cmd[sys_note][{note.uid}][delete]=1', currentUrlParameterName:'redirect')}" class="btn btn-default btn-sm t3js-modal-trigger" data-severity="warning" data-title="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:delete')}" data-bs-content="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf:deleteWarning')}" data-button-close-text="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel')}">
<core:icon identifier="actions-edit-delete" />
</a>
</f:if>
</span>
</span>
</div>
......
Markdown is supported
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