Remove ResponseRenderer::disable from UrlRedirector class
Creates a new Response object instead of using the response from ResponseRenderer class. Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
parent
27f5a8aaf5
commit
98b3eda545
@ -3,3 +3,4 @@
|
||||
window.location = '{{ url|escape('js') }}';
|
||||
};
|
||||
</script>
|
||||
{{ t('Taking you to the target site.') }}
|
||||
|
||||
@ -103,7 +103,7 @@ class Application
|
||||
$requestHandler->add(new RequestProblemChecking($this->template, $this->responseFactory));
|
||||
$requestHandler->add(new CurrentServerGlobalSetting($this->config));
|
||||
$requestHandler->add(new ThemeInitialization());
|
||||
$requestHandler->add(new UrlRedirection($this->config));
|
||||
$requestHandler->add(new UrlRedirection($this->config, $this->template, $this->responseFactory));
|
||||
$requestHandler->add(new SetupPageRedirection($this->config, $this->responseFactory));
|
||||
$requestHandler->add(new MinimumCommonRedirection($this->config, $this->responseFactory));
|
||||
$requestHandler->add(new LanguageAndThemeCookieSaving($this->config));
|
||||
|
||||
@ -6,6 +6,9 @@ namespace PhpMyAdmin\Http\Middleware;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Container\ContainerBuilder;
|
||||
use PhpMyAdmin\Http\Factory\ResponseFactory;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Theme\ThemeManager;
|
||||
use PhpMyAdmin\UrlRedirector;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
@ -13,12 +16,13 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
use function is_string;
|
||||
|
||||
final class UrlRedirection implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(private readonly Config $config)
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Config $config,
|
||||
private readonly Template $template,
|
||||
private readonly ResponseFactory $responseFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
@ -32,11 +36,8 @@ final class UrlRedirection implements MiddlewareInterface
|
||||
$themeManager = $container->get(ThemeManager::class);
|
||||
$this->config->loadUserPreferences($themeManager, true);
|
||||
|
||||
return UrlRedirector::redirect($this->getUrlParam($request->getQueryParams()['url'] ?? null));
|
||||
}
|
||||
$urlRedirector = new UrlRedirector(ResponseRenderer::getInstance(), $this->template, $this->responseFactory);
|
||||
|
||||
private function getUrlParam(mixed $url): string
|
||||
{
|
||||
return is_string($url) ? $url : '';
|
||||
return $urlRedirector->redirect($request->getQueryParams()['url'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -428,21 +428,26 @@ class ResponseRenderer
|
||||
throw new ExitException($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid relative path redirect problems in case user entered URL
|
||||
* like /phpmyadmin/index.php/ which some web servers happily accept.
|
||||
*/
|
||||
public function fixRelativeUrlForRedirect(string $url): string
|
||||
{
|
||||
if (! str_starts_with($url, '.')) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return $this->config->getRootPath() . substr($url, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param non-empty-string $url
|
||||
* @psalm-param StatusCodeInterface::STATUS_* $statusCode
|
||||
*/
|
||||
public function redirect(string $url, int $statusCode = StatusCodeInterface::STATUS_FOUND): void
|
||||
{
|
||||
/**
|
||||
* Avoid relative path redirect problems in case user entered URL
|
||||
* like /phpmyadmin/index.php/ which some web servers happily accept.
|
||||
*/
|
||||
if (str_starts_with($url, '.')) {
|
||||
$url = $this->config->getRootPath() . substr($url, 2);
|
||||
}
|
||||
|
||||
$this->addHeader('Location', $url);
|
||||
$this->addHeader('Location', $this->fixRelativeUrlForRedirect($url));
|
||||
$this->setStatusCode($statusCode);
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Container\ContainerBuilder;
|
||||
use Fig\Http\Message\StatusCodeInterface;
|
||||
use PhpMyAdmin\Http\Factory\ResponseFactory;
|
||||
use PhpMyAdmin\Http\Response;
|
||||
|
||||
use function __;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
@ -15,37 +16,36 @@ use function preg_match;
|
||||
*/
|
||||
final class UrlRedirector
|
||||
{
|
||||
public static function redirect(string $url): Response
|
||||
public function __construct(
|
||||
private readonly ResponseRenderer $response,
|
||||
private readonly Template $template,
|
||||
private readonly ResponseFactory $responseFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function redirect(mixed $urlParam): Response
|
||||
{
|
||||
$container = ContainerBuilder::getContainer();
|
||||
|
||||
// Only output the http headers
|
||||
$response = ResponseRenderer::getInstance();
|
||||
$response->getHeader()->sendHttpHeaders();
|
||||
$response->disable();
|
||||
$response = $this->responseFactory->createResponse();
|
||||
foreach ($this->response->getHeader()->getHttpHeaders() as $name => $value) {
|
||||
$response = $response->withHeader($name, $value);
|
||||
}
|
||||
|
||||
$url = is_string($urlParam) ? $urlParam : '';
|
||||
if (
|
||||
$url === ''
|
||||
|| ! preg_match('/^https:\/\/[^\n\r]*$/', $url)
|
||||
|| ! Core::isAllowedDomain($url)
|
||||
) {
|
||||
$response->redirect('./');
|
||||
$response = $response->withHeader('Location', $this->response->fixRelativeUrlForRedirect('./'));
|
||||
|
||||
return $response->response();
|
||||
return $response->withStatus(StatusCodeInterface::STATUS_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript redirection is necessary. Because if header() is used then web browser sometimes does not change
|
||||
* the HTTP_REFERER field and so with old URL as Referer, token also goes to external site.
|
||||
*
|
||||
* @var Template $template
|
||||
*/
|
||||
$template = $container->get('template');
|
||||
echo $template->render('javascript/redirect', ['url' => $url]);
|
||||
// Display redirecting msg on screen.
|
||||
// Do not display the value of $_GET['url'] to avoid showing injected content
|
||||
echo __('Taking you to the target site.');
|
||||
|
||||
return $response->response();
|
||||
return $response->write($this->template->render('javascript/redirect', ['url' => $url]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,43 +6,44 @@ namespace PhpMyAdmin\Tests;
|
||||
|
||||
use Fig\Http\Message\StatusCodeInterface;
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Http\Factory\ResponseFactory;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Tests\Stubs\ResponseRenderer;
|
||||
use PhpMyAdmin\UrlRedirector;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use ReflectionProperty;
|
||||
|
||||
#[CoversClass(UrlRedirector::class)]
|
||||
final class UrlRedirectorTest extends AbstractTestCase
|
||||
{
|
||||
public function testRedirectWithDisallowedUrl(): void
|
||||
{
|
||||
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$config = Config::getInstance();
|
||||
$config->settings['PmaAbsoluteUri'] = 'http://localhost/phpmyadmin';
|
||||
|
||||
$response = UrlRedirector::redirect('https://user:pass@example.com/');
|
||||
$urlRedirector = new UrlRedirector(new ResponseRenderer(), new Template(), ResponseFactory::create());
|
||||
|
||||
$response = $urlRedirector->redirect('https://user:pass@example.com/');
|
||||
self::assertSame('/phpmyadmin/', $response->getHeaderLine('Location'));
|
||||
self::assertSame(StatusCodeInterface::STATUS_FOUND, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testRedirectWithAllowedUrl(): void
|
||||
{
|
||||
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
|
||||
$GLOBALS['lang'] = 'en';
|
||||
$_SERVER['SERVER_NAME'] = 'localhost';
|
||||
|
||||
UrlRedirector::redirect('https://phpmyadmin.net/');
|
||||
$output = self::getActualOutputForAssertion();
|
||||
$expected = <<<'HTML'
|
||||
<script>
|
||||
window.onload = function () {
|
||||
window.location = 'https\u003A\/\/phpmyadmin.net\/';
|
||||
};
|
||||
</script>
|
||||
Taking you to the target site.
|
||||
HTML;
|
||||
$urlRedirector = new UrlRedirector(new ResponseRenderer(), new Template(), ResponseFactory::create());
|
||||
|
||||
self::assertSame($expected, $output);
|
||||
$response = $urlRedirector->redirect('https://phpmyadmin.net/');
|
||||
$expected = <<<'HTML'
|
||||
<script>
|
||||
window.onload = function () {
|
||||
window.location = 'https\u003A\/\/phpmyadmin.net\/';
|
||||
};
|
||||
</script>
|
||||
Taking you to the target site.
|
||||
|
||||
HTML;
|
||||
|
||||
self::assertSame($expected, (string) $response->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user