Prevent redirection loop everytime we rely on HTTP_REFERER:
* search tag * delete tag * pagination * display privates only * delete link * new/edit/cancel link return page Move location generation to Utils.php + unit tests. Fixes #256 ninja
This commit is contained in:
parent
7f1dfd1c12
commit
775803a05c
3 changed files with 108 additions and 44 deletions
|
@ -84,4 +84,36 @@ function checkDateFormat($format, $string)
|
||||||
$date = DateTime::createFromFormat($format, $string);
|
$date = DateTime::createFromFormat($format, $string);
|
||||||
return $date && $date->format($string) == $string;
|
return $date && $date->format($string) == $string;
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
/**
|
||||||
|
* Generate a header location from HTTP_REFERER.
|
||||||
|
* Make sure the referer is Shaarli itself and prevent redirection loop.
|
||||||
|
*
|
||||||
|
* @param string $referer - HTTP_REFERER.
|
||||||
|
* @param string $host - Server HOST.
|
||||||
|
* @param array $loopTerms - Contains list of term to prevent redirection loop.
|
||||||
|
*
|
||||||
|
* @return string $referer - final referer.
|
||||||
|
*/
|
||||||
|
function generateLocation($referer, $host, $loopTerms = array())
|
||||||
|
{
|
||||||
|
$final_referer = '?';
|
||||||
|
|
||||||
|
// No referer if it contains any value in $loopCriteria.
|
||||||
|
foreach ($loopTerms as $value) {
|
||||||
|
if (strpos($referer, $value) !== false) {
|
||||||
|
return $final_referer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove port from HTTP_HOST
|
||||||
|
if ($pos = strpos($host, ':')) {
|
||||||
|
$host = substr($host, 0, $pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($referer) && strpos(parse_url($referer, PHP_URL_HOST), $host) !== false) {
|
||||||
|
$final_referer = $referer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $final_referer;
|
||||||
|
}
|
||||||
|
|
87
index.php
87
index.php
|
@ -1099,6 +1099,11 @@ function renderPage()
|
||||||
if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER
|
if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER
|
||||||
parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
|
parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
|
||||||
|
|
||||||
|
// Prevent redirection loop
|
||||||
|
if (isset($params['addtag'])) {
|
||||||
|
unset($params['addtag']);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if this tag is already in the search query and ignore it if it is.
|
// Check if this tag is already in the search query and ignore it if it is.
|
||||||
// Each tag is always separated by a space
|
// Each tag is always separated by a space
|
||||||
$current_tags = explode(' ', $params['searchtags']);
|
$current_tags = explode(' ', $params['searchtags']);
|
||||||
|
@ -1123,16 +1128,29 @@ function renderPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
|
// -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
|
||||||
if (isset($_GET['removetag']))
|
if (isset($_GET['removetag'])) {
|
||||||
{
|
|
||||||
// Get previous URL (http_referer) and remove the tag from the searchtags parameters in query.
|
// Get previous URL (http_referer) and remove the tag from the searchtags parameters in query.
|
||||||
if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER
|
if (empty($_SERVER['HTTP_REFERER'])) {
|
||||||
|
header('Location: ?');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case browser does not send HTTP_REFERER
|
||||||
parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
|
parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
|
||||||
if (isset($params['searchtags']))
|
|
||||||
{
|
// Prevent redirection loop
|
||||||
|
if (isset($params['removetag'])) {
|
||||||
|
unset($params['removetag']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['searchtags'])) {
|
||||||
$tags = explode(' ',$params['searchtags']);
|
$tags = explode(' ',$params['searchtags']);
|
||||||
$tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags.
|
$tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags.
|
||||||
if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags);
|
if (count($tags)==0) {
|
||||||
|
unset($params['searchtags']);
|
||||||
|
} else {
|
||||||
|
$params['searchtags'] = implode(' ',$tags);
|
||||||
|
}
|
||||||
unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
|
unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
|
||||||
}
|
}
|
||||||
header('Location: ?'.http_build_query($params));
|
header('Location: ?'.http_build_query($params));
|
||||||
|
@ -1140,33 +1158,24 @@ function renderPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- User wants to change the number of links per page (linksperpage=...)
|
// -------- User wants to change the number of links per page (linksperpage=...)
|
||||||
if (isset($_GET['linksperpage']))
|
if (isset($_GET['linksperpage'])) {
|
||||||
{
|
if (is_numeric($_GET['linksperpage'])) {
|
||||||
if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); }
|
$_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage']));
|
||||||
// Make sure the referrer is Shaarli itself.
|
}
|
||||||
$referer = '?';
|
|
||||||
if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
|
header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage')));
|
||||||
$referer = $_SERVER['HTTP_REFERER'];
|
|
||||||
header('Location: '.$referer);
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- User wants to see only private links (toggle)
|
// -------- User wants to see only private links (toggle)
|
||||||
if (isset($_GET['privateonly']))
|
if (isset($_GET['privateonly'])) {
|
||||||
{
|
if (empty($_SESSION['privateonly'])) {
|
||||||
if (empty($_SESSION['privateonly']))
|
|
||||||
{
|
|
||||||
$_SESSION['privateonly'] = 1; // See only private links
|
$_SESSION['privateonly'] = 1; // See only private links
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
unset($_SESSION['privateonly']); // See all links
|
unset($_SESSION['privateonly']); // See all links
|
||||||
}
|
}
|
||||||
// Make sure the referrer is Shaarli itself.
|
|
||||||
$referer = '?';
|
header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly')));
|
||||||
if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
|
|
||||||
$referer = $_SERVER['HTTP_REFERER'];
|
|
||||||
header('Location: '.$referer);
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1349,10 +1358,10 @@ function renderPage()
|
||||||
|
|
||||||
// If we are called from the bookmarklet, we must close the popup:
|
// If we are called from the bookmarklet, we must close the popup:
|
||||||
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
|
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
|
||||||
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
|
$returnurl = ( !empty($_POST['returnurl']) ? escape($_POST['returnurl']) : '?' );
|
||||||
$returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited.
|
$returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
|
||||||
if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead
|
$location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
|
||||||
header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on.
|
header('Location: '. $location); // After saving the link, redirect to the page the user was on.
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,6 +1372,7 @@ function renderPage()
|
||||||
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
|
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
|
||||||
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
|
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
|
||||||
$returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
|
$returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
|
||||||
|
$returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
|
||||||
header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
|
header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
@ -1395,18 +1405,15 @@ function renderPage()
|
||||||
// redirect is not satisfied, and only then redirect to /
|
// redirect is not satisfied, and only then redirect to /
|
||||||
$location = "?";
|
$location = "?";
|
||||||
// Self redirection
|
// Self redirection
|
||||||
if (count($_GET) == 0 ||
|
if (count($_GET) == 0
|
||||||
isset($_GET['page']) ||
|
|| isset($_GET['page'])
|
||||||
isset($_GET['searchterm']) ||
|
|| isset($_GET['searchterm'])
|
||||||
isset($_GET['searchtags'])) {
|
|| isset($_GET['searchtags'])
|
||||||
|
) {
|
||||||
if (isset($_POST['returnurl'])) {
|
if (isset($_POST['returnurl'])) {
|
||||||
$location = $_POST['returnurl']; // Handle redirects given by the form
|
$location = $_POST['returnurl']; // Handle redirects given by the form
|
||||||
}
|
} else {
|
||||||
|
$location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link'));
|
||||||
if ($location === "?" &&
|
|
||||||
isset($_SERVER['HTTP_REFERER'])) { // Handle HTTP_REFERER in case we're not coming from the same place.
|
|
||||||
$location = $_SERVER['HTTP_REFERER'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,5 +93,30 @@ public function testCheckInvalidDateFormat()
|
||||||
$this->assertFalse(checkDateFormat('Y-m-d', '2015-06'));
|
$this->assertFalse(checkDateFormat('Y-m-d', '2015-06'));
|
||||||
$this->assertFalse(checkDateFormat('Ymd', 'DeLorean'));
|
$this->assertFalse(checkDateFormat('Ymd', 'DeLorean'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test generate location with valid data.
|
||||||
|
*/
|
||||||
|
public function testGenerateLocation() {
|
||||||
|
$ref = 'http://localhost/?test';
|
||||||
|
$this->assertEquals($ref, generateLocation($ref, 'localhost'));
|
||||||
|
$ref = 'http://localhost:8080/?test';
|
||||||
|
$this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test generate location - anti loop.
|
||||||
|
*/
|
||||||
|
public function testGenerateLocationLoop() {
|
||||||
|
$ref = 'http://localhost/?test';
|
||||||
|
$this->assertEquals('?', generateLocation($ref, 'localhost', ['test']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test generate location - from other domain.
|
||||||
|
*/
|
||||||
|
public function testGenerateLocationOut() {
|
||||||
|
$ref = 'http://somewebsite.com/?test';
|
||||||
|
$this->assertEquals('?', generateLocation($ref, 'localhost'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|
Loading…
Reference in a new issue