Merge pull request #257 from ArthurHoaro/tag-http-referer

Prevent redirection loop everytime we rely on HTTP_REFERER
This commit is contained in:
VirtualTam 2015-07-12 19:56:13 +02:00
commit 5b0ebbc5de
3 changed files with 108 additions and 44 deletions

View file

@ -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;
}

View file

@ -1120,6 +1120,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
if (isset($params['searchtags'])) { if (isset($params['searchtags'])) {
@ -1148,16 +1153,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));
@ -1165,33 +1183,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;
} }
@ -1398,10 +1407,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;
} }
@ -1412,6 +1421,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;
} }
@ -1444,18 +1454,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'];
} }
} }

View file

@ -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'));
}
} }
?>