Skip to content
Closed
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
101 changes: 97 additions & 4 deletions src/Illuminate/Routing/UrlGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,109 @@ public function previous($fallback = false)
}

/**
* Get the previous path info for the request.
* Get the previous path for the request.
*
* @param mixed $fallback
* @param bool $securityCheck Whether to check for potential security vulnerabilities
* @return string
*/
public function previousPath($fallback = false)
public function previousPath($fallback = false, $securityCheck = false)
{
$previousPath = str_replace($this->to('/'), '', rtrim(preg_replace('/\?.*/', '', $this->previous($fallback)), '/'));
if (! $securityCheck) {
$previousPath = str_replace($this->to('/'), '', rtrim(preg_replace('/\?.*/', '', $this->previous($fallback)), '/'));

return $previousPath === '' ? '/' : $previousPath;
return $previousPath === '' ? '/' : $previousPath;
}

$referrer = $this->request->headers->get('referer');

if (! $referrer) {
$referrer = $this->getPreviousUrlFromSession();
}

if (! $referrer) {
return $this->getPathFromUrl($fallback);
}

return $this->getSecurePreviousPath($referrer, $fallback);
}

/**
* Get the secure previous path with security checks.
*
* @param string $referrer
* @param mixed $fallback
* @return string
*/
protected function getSecurePreviousPath($referrer, $fallback = false): string
{
if ($this->isDangerousUrl($referrer)) {
return $this->getPathFromUrl($fallback);
}

$previous = $this->to($referrer);
$previousUrlComponents = parse_url($previous);
$appUrlComponents = parse_url($this->to('/'));

if (! $this->isSameOrigin($previousUrlComponents, $appUrlComponents)) {
$previous = $fallback ? $this->to($fallback) : $this->to('/');
}

return $this->getPathFromUrl($previous);
}

/**
* Check for dangerous schemes like javascript, data, or file.
*
* @param string $url
* @return bool
*/
protected function isDangerousUrl($url)
{
// will return true if the URL starts with javascript, data, or file
return preg_match('/^(javascript|data|file):/i', $url);
}

/**
* Determine if two URLs are from the same origin, matching host, scheme, and port.
*
* @param array|false $urlOneComponents
* @param array|false $urlTwoComponents
* @return bool
*/
protected function isSameOrigin($urlOneComponents, $urlTwoComponents)
{
if ($urlOneComponents === false || $urlTwoComponents === false) {
return false;
}

$hostOne = $urlOneComponents['host'] ?? null;
$hostTwo = $urlTwoComponents['host'] ?? null;
$schemeOne = $urlOneComponents['scheme'] ?? null;
$schemeTwo = $urlTwoComponents['scheme'] ?? null;
$portOne = $urlOneComponents['port'] ?? null;
$portTwo = $urlTwoComponents['port'] ?? null;

if (! $hostOne || ! $hostTwo || ! $schemeOne || ! $schemeTwo) {
return false;
}

return strtolower($hostOne) === strtolower($hostTwo) &&
$schemeOne === $schemeTwo &&
$portOne === $portTwo;
}

/**
* Extract path from a URL.
*
* @param mixed $url
* @return string
*/
protected function getPathFromUrl($url)
{
$path = $url ? parse_url($this->to($url), PHP_URL_PATH) ?? '/' : '/';

return rtrim($path, '/') ?: '/';
}

/**
Expand Down
Loading
Loading