Skip to content

Commit

Permalink
Merge branch '5.3' into 5.x
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
#	calendar-bundle/contao/languages/sv/tl_module.xlf
#	core-bundle/contao/languages/sv/default.xlf
#	core-bundle/contao/languages/sv/explain.xlf
#	core-bundle/contao/languages/sv/tl_article.xlf
#	core-bundle/contao/languages/sv/tl_content.xlf
#	core-bundle/contao/languages/sv/tl_maintenance.xlf
#	core-bundle/contao/languages/sv/tl_member.xlf
#	core-bundle/contao/languages/sv/tl_module.xlf
#	core-bundle/contao/languages/sv/tl_page.xlf
#	core-bundle/contao/languages/sv/tl_theme.xlf
#	core-bundle/contao/languages/sv/tl_user.xlf
#	news-bundle/contao/languages/sv/tl_module.xlf
  • Loading branch information
leofeyer committed May 24, 2024
2 parents 9dbb0e5 + b6b55a8 commit 2be2bf9
Show file tree
Hide file tree
Showing 20 changed files with 96 additions and 147 deletions.
4 changes: 1 addition & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
"toflar/psr6-symfony-http-cache-store": "^4.0",
"twig/extra-bundle": "^3.0",
"twig/string-extra": "^3.0",
"twig/twig": "^3.8",
"twig/twig": "^3.10.2",
"ua-parser/uap-php": "^3.9",
"webignition/robots-txt-file": "^3.0",
"wikimedia/less.php": "^1.7"
Expand Down Expand Up @@ -202,8 +202,6 @@
"nikic/php-parser": "4.7.0",
"terminal42/contao-ce-access": "<3.0",
"thecodingmachine/safe": "<1.2",
"twig/intl-extra": "3.9.0",
"twig/twig": "3.9.0 || 3.10.0 || 3.10.1",
"zendframework/zend-code": "<3.3.1"
},
"autoload": {
Expand Down
6 changes: 2 additions & 4 deletions core-bundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
"terminal42/service-annotation-bundle": "^1.1",
"toflar/cronjob-supervisor": "^2.0",
"twig/string-extra": "^3.0",
"twig/twig": "^3.8",
"twig/twig": "^3.10.2",
"ua-parser/uap-php": "^3.9",
"webignition/robots-txt-file": "^3.0",
"wikimedia/less.php": "^1.7"
Expand Down Expand Up @@ -179,9 +179,7 @@
"contao/manager-plugin": "<2.0 || >=3.0",
"doctrine/cache": "<1.10",
"terminal42/contao-ce-access": "<3.0",
"thecodingmachine/safe": "<1.2",
"twig/intl-extra": "3.9.0",
"twig/twig": "3.9.0 || 3.10.0 || 3.10.1"
"thecodingmachine/safe": "<1.2"
},
"autoload": {
"psr-4": {
Expand Down
16 changes: 1 addition & 15 deletions core-bundle/config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,7 @@ contao_backend_redirect:
path: '%contao.backend.route_prefix%/'
defaults:
_scope: backend
_store_referrer: false
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
route: contao_backend
permanent: true

contao_backend_fallback:
path: '%contao.backend.route_prefix%/{parameters}'
defaults:
_scope: backend
_controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController
template: '@ContaoCore\Error\backend.html.twig'
context:
template: '@ContaoCore\Error\backend.html.twig'
language: en
statusName: Page Not Found
exception: The requested page does not exist.
statusCode: 404
requirements:
parameters: .*
2 changes: 0 additions & 2 deletions core-bundle/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,6 @@ services:
class: Contao\CoreBundle\Monolog\ContaoTableHandler
arguments:
- !service_closure '@database_connection'
- debug
- false
tags:
- { name: monolog.logger, channel: contao }

Expand Down
2 changes: 1 addition & 1 deletion core-bundle/contao/drivers/DC_Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ protected function copyChildren($table, $insertID, $id, $parentId)
$this->loadDataContainer($v);
$cctable[$v] = $GLOBALS['TL_DCA'][$v]['config']['ctable'] ?? null;

if (!($GLOBALS['TL_DCA'][$v]['config']['doNotCopyRecords'] ?? null) && \strlen($v))
if (!($GLOBALS['TL_DCA'][$v]['config']['doNotCopyRecords'] ?? null))
{
// Consider the dynamic parent table (see #4867)
if ($GLOBALS['TL_DCA'][$v]['config']['dynamicPtable'] ?? null)
Expand Down
33 changes: 24 additions & 9 deletions core-bundle/src/Controller/BackendController.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public function mainAction(): Response
return $controller->run();
}

#[Route('/login', name: 'contao_backend_login')]
#[Route('/login-link', name: 'contao_backend_login_link')]
#[Route('/login', name: 'contao_backend_login', defaults: ['_store_referer' => false])]
#[Route('/login-link', name: 'contao_backend_login_link', defaults: ['_store_referer' => false])]
public function loginAction(Request $request): Response
{
$this->initializeContaoFramework();
Expand All @@ -72,13 +72,13 @@ public function loginAction(Request $request): Response
/**
* Symfony will un-authenticate the user automatically by calling this route.
*/
#[Route('/logout', name: 'contao_backend_logout')]
#[Route('/logout', name: 'contao_backend_logout', defaults: ['_store_referer' => false])]
public function logoutAction(): RedirectResponse
{
return $this->redirectToRoute('contao_backend_login');
}

#[Route('/password', name: 'contao_backend_password')]
#[Route('/password', name: 'contao_backend_password', defaults: ['_store_referer' => false])]
public function passwordAction(): Response
{
$this->initializeContaoFramework();
Expand All @@ -88,7 +88,7 @@ public function passwordAction(): Response
return $controller->run();
}

#[Route('/confirm', name: 'contao_backend_confirm')]
#[Route('/confirm', name: 'contao_backend_confirm', defaults: ['_store_referer' => false])]
public function confirmAction(): Response
{
$this->initializeContaoFramework();
Expand All @@ -98,7 +98,7 @@ public function confirmAction(): Response
return $controller->run();
}

#[Route('/help', name: 'contao_backend_help')]
#[Route('/help', name: 'contao_backend_help', defaults: ['_store_referer' => false])]
public function helpAction(): Response
{
$this->initializeContaoFramework();
Expand All @@ -108,7 +108,7 @@ public function helpAction(): Response
return $controller->run();
}

#[Route('/popup', name: 'contao_backend_popup')]
#[Route('/popup', name: 'contao_backend_popup', defaults: ['_store_referer' => false])]
public function popupAction(): Response
{
$this->initializeContaoFramework();
Expand All @@ -118,7 +118,7 @@ public function popupAction(): Response
return $controller->run();
}

#[Route('/alerts', name: 'contao_backend_alerts')]
#[Route('/alerts', name: 'contao_backend_alerts', defaults: ['_store_referer' => false])]
public function alertsAction(): Response
{
$this->initializeContaoFramework();
Expand All @@ -133,7 +133,7 @@ public function alertsAction(): Response
* It will determine the current provider URL based on the value, which is usually
* read dynamically via JavaScript.
*/
#[Route('/picker', name: 'contao_backend_picker')]
#[Route('/picker', name: 'contao_backend_picker', defaults: ['_store_referer' => false])]
public function pickerAction(Request $request): RedirectResponse
{
$extras = [];
Expand All @@ -156,6 +156,21 @@ public function pickerAction(Request $request): RedirectResponse
return new RedirectResponse($picker->getCurrentUrl());
}

#[Route('/{parameters}', name: 'contao_backend_fallback', requirements: ['parameters' => '.*'], defaults: ['_store_referer' => false], priority: -1000)]
public function backendFallback(): Response
{
return $this->render(
'@ContaoCore/Error/backend.html.twig',
[
'language' => 'en',
'statusName' => 'Page Not Found',
'exception' => 'The requested page does not exist.',
'template' => '@ContaoCore/Error/backend.html.twig',
],
new Response('', 404),
);
}

public static function getSubscribedServices(): array
{
$services = parent::getSubscribedServices();
Expand Down
3 changes: 1 addition & 2 deletions core-bundle/src/Controller/BackendPreviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* requested front end page while ensuring that the /preview.php entry point is
* used. When requested, the front end user gets authenticated.
*/
#[Route('%contao.backend.route_prefix%', defaults: ['_scope' => 'backend', '_allow_preview' => true])]
#[Route('%contao.backend.route_prefix%/preview', name: 'contao_backend_preview', defaults: ['_scope' => 'backend', '_allow_preview' => true, '_store_referrer' => false])]
class BackendPreviewController
{
public function __construct(
Expand All @@ -44,7 +44,6 @@ public function __construct(
) {
}

#[Route('/preview', name: 'contao_backend_preview')]
public function __invoke(Request $request): Response
{
// Skip the redirect if there is no preview script, otherwise we will end up in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* - Provide the member usernames for the datalist
* - Process the switch action (i.e. log in a specific front end user)
*/
#[Route('%contao.backend.route_prefix%', defaults: ['_scope' => 'backend', '_allow_preview' => true])]
#[Route('%contao.backend.route_prefix%/preview_switch', name: 'contao_backend_switch', defaults: ['_scope' => 'backend', '_allow_preview' => true, '_store_referrer' => false])]
class BackendPreviewSwitchController
{
public function __construct(
Expand All @@ -54,7 +54,6 @@ public function __construct(
) {
}

#[Route('/preview_switch', name: 'contao_backend_switch')]
public function __invoke(Request $request): Response
{
$user = $this->security->getUser();
Expand Down
9 changes: 9 additions & 0 deletions core-bundle/src/EventListener/CsrfTokenCookieSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ private function requiresCsrf(Request $request, Response $response): bool

private function isSessionEmpty(SessionInterface $session): bool
{
foreach (headers_list() as $header) {
if (
str_starts_with($header, "Set-Cookie: {$session->getName()}=")
&& !str_starts_with($header, "Set-Cookie: {$session->getName()}=deleted;")
) {
return false;
}
}

if (!$session->isStarted()) {
return true;
}
Expand Down
9 changes: 9 additions & 0 deletions core-bundle/src/EventListener/MakeResponsePrivateListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ private function makePrivate(Response $response, string $reason): void

private function isSessionEmpty(SessionInterface $session): bool
{
foreach (headers_list() as $header) {
if (
str_starts_with($header, "Set-Cookie: {$session->getName()}=")
&& !str_starts_with($header, "Set-Cookie: {$session->getName()}=deleted;")
) {
return false;
}
}

if (!$session->isStarted()) {
return true;
}
Expand Down
3 changes: 2 additions & 1 deletion core-bundle/src/EventListener/StoreRefererListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ private function canModifyBackendSession(Request $request): bool
&& !$request->query->has('token')
&& !$request->query->has('state')
&& 'feRedirect' !== $request->query->get('do')
&& 'contao_backend' === $request->attributes->get('_route')
&& 'backend' === $request->attributes->get('_scope')
&& false !== $request->attributes->get('_store_referrer')
&& !$request->isXmlHttpRequest();
}

Expand Down
2 changes: 1 addition & 1 deletion core-bundle/src/Security/Voter/BackendAccessVoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private function hasAccess(mixed $subject, string $field, BackendUser $user): bo

// Additionally check the child pages of the mounted pages
if ('pagemounts' === $field) {
if (!isset($this->pagemountsCache[$user->id])) {
if (!isset($this->pagemountsCache[$user->id]) || (!empty($this->pagemountsCache[$user->id]) && !array_intersect($subject, $this->pagemountsCache[$user->id]))) {
$database = $this->framework->createInstance(Database::class);
$this->pagemountsCache[$user->id] = $database->getChildRecords($user->pagemounts, 'tl_page');
}
Expand Down
50 changes: 26 additions & 24 deletions core-bundle/src/Twig/Extension/ContaoExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Extension\CoreExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\GlobalsInterface;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\Runtime\EscaperRuntime;
use Twig\TwigFilter;
use Twig\TwigFunction;

Expand All @@ -69,24 +69,19 @@ public function __construct(
private readonly ContaoVariable $contaoVariable,
) {
$contaoEscaper = new ContaoEscaper();
$escaperExtension = $environment->getExtension(EscaperExtension::class);

// Forward compatibility with twig/twig >=3.10.0
if (method_exists($escaperExtension, 'setEnvironment')) {
$escaperExtension->setEnvironment($environment);
}

$escaperExtension->setEscaper('contao_html', $contaoEscaper->escapeHtml(...));
$escaperExtension->setEscaper('contao_html_attr', $contaoEscaper->escapeHtmlAttr(...));
$escaperRuntime = $this->environment->getRuntime(EscaperRuntime::class);
$escaperRuntime->setEscaper('contao_html', $contaoEscaper->escapeHtml(...));
$escaperRuntime->setEscaper('contao_html_attr', $contaoEscaper->escapeHtmlAttr(...));

// Use our escaper on all templates in the "@Contao" and "@Contao_*" namespaces,
// as well as the existing bundle templates we're already shipping.
$this->addContaoEscaperRule('%^@Contao(_[a-zA-Z0-9_-]*)?/%');
$this->addContaoEscaperRule('%^@ContaoCore/%');

// Mark classes as safe for HTML that already escape their output themselves
$escaperExtension->addSafeClass(HtmlAttributes::class, ['html', 'contao_html']);
$escaperExtension->addSafeClass(HighlightResult::class, ['html', 'contao_html']);
$escaperRuntime->addSafeClass(HtmlAttributes::class, ['html', 'contao_html']);
$escaperRuntime->addSafeClass(HighlightResult::class, ['html', 'contao_html']);

$this->environment->addGlobal(
'request_token',
Expand Down Expand Up @@ -242,39 +237,46 @@ function (Environment $env, $context, $template, $variables = [], $withContext =

public function getFilters(): array
{
$escaperFilter = static function (Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) {
$escaperFilter = static function (Environment $env, $string, string $strategy = 'html', string|null $charset = null, bool $autoescape = false) {
$runtime = $env->getRuntime(EscaperRuntime::class);

if ($string instanceof ChunkedText) {
$parts = [];

foreach ($string as [$type, $chunk]) {
if (ChunkedText::TYPE_RAW === $type) {
$parts[] = $chunk;
} else {
$parts[] = twig_escape_filter($env, $chunk, $strategy, $charset);
$parts[] = $runtime->escape($chunk, $strategy, $charset);
}
}

return implode('', $parts);
}

return twig_escape_filter($env, $string, $strategy, $charset, $autoescape);
return $runtime->escape($string, $strategy, $charset, $autoescape);
};

/** @see \Twig\Extension\EscaperExtension::escapeFilterIsSafe() */
$twigEscaperFilterIsSafe = static function (Node $filterArgs): array {
$expression = iterator_to_array($filterArgs)[0] ?? null;

if ($expression instanceof ConstantExpression) {
$value = $expression->getAttribute('value');
foreach ($filterArgs as $arg) {
if ($arg instanceof ConstantExpression) {
$value = $arg->getAttribute('value');

// Our escaper strategy variants that tolerate input encoding are also safe in
// the original context (e.g. for the filter argument 'contao_html' we will
// return ['contao_html', 'html']).
if (\in_array($value, ['contao_html', 'contao_html_attr'], true)) {
return [$value, substr($value, 7)];
}

// Our escaper strategy variants that tolerate input encoding are also safe in
// the original context (e.g. for the filter argument 'contao_html' we will
// return ['contao_html', 'html']).
if (\in_array($value, ['contao_html', 'contao_html_attr'], true)) {
return [$value, substr($value, 7)];
return [$value];
}

return [];
}

return twig_escape_filter_is_safe($filterArgs);
return ['html'];
};

return [
Expand Down
5 changes: 2 additions & 3 deletions core-bundle/src/Twig/Interop/ContaoEscaper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
namespace Contao\CoreBundle\Twig\Interop;

use Contao\StringUtil;
use Twig\Environment;
use Twig\Error\RuntimeError;

/**
Expand All @@ -33,7 +32,7 @@ final class ContaoEscaper
*
* @see twig_escape_filter
*/
public function escapeHtml(Environment $environment, mixed $string, string|null $charset): string
public function escapeHtml(mixed $string, string|null $charset): string
{
if (null !== $charset && 'UTF-8' !== strtoupper($charset)) {
throw new RuntimeError(sprintf('The "contao_html" escape filter does not support the %s charset, use UTF-8 instead.', $charset));
Expand All @@ -50,7 +49,7 @@ public function escapeHtml(Environment $environment, mixed $string, string|null
*
* @see twig_escape_filter
*/
public function escapeHtmlAttr(Environment $environment, mixed $string, string|null $charset): string
public function escapeHtmlAttr(mixed $string, string|null $charset): string
{
if (null !== $charset && 'UTF-8' !== strtoupper($charset)) {
throw new RuntimeError(sprintf('The "contao_html_attr" escape filter does not support the %s charset, use UTF-8 instead.', $charset));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ public function testDoesNotStoreTheRefererIfTheBackEndSessionCannotBeModified():
$request->setSession($session);

$request->attributes->set('_scope', ContaoCoreBundle::SCOPE_BACKEND);
$request->attributes->set('_store_referrer', false);

$listener = $this->getListener($this->createMock(User::class));
$listener($this->getResponseEvent($request));
Expand Down
Loading

0 comments on commit 2be2bf9

Please sign in to comment.