[CORE][Router][Form] Add Router::sanitizeLocalURL and use it in Form::forceRedirect
This commit is contained in:
parent
f540711948
commit
9a9eed1457
@ -47,7 +47,6 @@ use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\Form\FormInterface as SymfFormInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* This class converts our own form representation to Symfony's
|
||||
@ -221,18 +220,14 @@ abstract class Form
|
||||
public static function forceRedirect(SymfFormInterface $form, Request $request): RedirectResponse
|
||||
{
|
||||
$next = $form->get('_next')->getData();
|
||||
try {
|
||||
if ($pos = mb_strrpos($next, '#')) {
|
||||
$fragment = mb_substr($next, $pos);
|
||||
$next = mb_substr($next, 0, $pos);
|
||||
}
|
||||
Router::match($next);
|
||||
return new RedirectResponse(url: $next . ($fragment ?? ''));
|
||||
} catch (ResourceNotFoundException $e) {
|
||||
$url = Router::sanitizeLocalURL($next, ['next' => false]);
|
||||
if (!\is_null($url)) {
|
||||
return new RedirectResponse(url: $url);
|
||||
} else {
|
||||
$user = Common::user();
|
||||
$user_id = !\is_null($user) ? $user->getId() : '(not logged in)';
|
||||
Log::warning("Suspicious activity: User with ID {$user_id} submitted a form where the `_next` parameter is not a valid local URL ({$next})");
|
||||
throw new ClientException(_m('Invalid form submission'), $e);
|
||||
throw new ClientException(_m('Invalid form submission'), previous: $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ declare(strict_types = 1);
|
||||
namespace App\Core\Router;
|
||||
|
||||
use App\Core\Log;
|
||||
use App\Util\Common;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Routing\Router as SymfonyRouter;
|
||||
|
||||
@ -89,6 +91,26 @@ abstract class Router
|
||||
return self::$router->generate($id, $args, $type);
|
||||
}
|
||||
|
||||
public static function sanitizeLocalURL(string $url, array $unset_query_args = []): ?string
|
||||
{
|
||||
try {
|
||||
$parts = parse_url($url);
|
||||
if ($parts === false || (isset($parts['host']) && $parts['host'] !== Common::config('site', 'server'))) {
|
||||
return null;
|
||||
}
|
||||
self::match($parts['path']);
|
||||
if ($unset_query_args !== [] && isset($parts['query'])) {
|
||||
$args = [];
|
||||
parse_str($parts['query'], $args);
|
||||
$args = array_diff_key($args, $unset_query_args);
|
||||
$parts['query'] = http_build_query($args);
|
||||
}
|
||||
return $parts['path'] . (empty($parts['query']) ? '' : ('?' . $parts['query'])) . (empty($parts['fragment']) ? '' : ('#' . $parts['fragment']));
|
||||
} catch (ResourceNotFoundException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function match($url) throws Symfony\Component\Routing\Exception\ResourceNotFoundException
|
||||
*/
|
||||
|
@ -148,11 +148,10 @@ abstract class Common
|
||||
return self::ensureLoggedIn()->getId();
|
||||
}
|
||||
|
||||
public static function ensureLoggedIn(): LocalUser
|
||||
public static function ensureLoggedIn(?Request $request = null): LocalUser
|
||||
{
|
||||
if (($user = self::user()) == null) {
|
||||
throw new NoLoggedInUser(self::getRequest());
|
||||
// TODO Maybe redirect to login page and back
|
||||
if (\is_null($user = self::user())) {
|
||||
throw new NoLoggedInUser($request ?? self::getRequest());
|
||||
} else {
|
||||
return $user;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user