aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2015-07-06 10:22:00 +0200
committerArthurHoaro <arthur@hoa.ro>2015-07-12 17:43:13 +0200
commit775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2 (patch)
tree9a161fb97e69880f3ac8a034714418428937db6b
parent7f1dfd1c12a143b324fbe68213a49de0586febfa (diff)
downloadShaarli-775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2.tar.gz
Shaarli-775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2.tar.zst
Shaarli-775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2.zip
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
-rw-r--r--application/Utils.php34
-rw-r--r--index.php91
-rw-r--r--tests/UtilsTest.php27
3 files changed, 108 insertions, 44 deletions
diff --git a/application/Utils.php b/application/Utils.php
index a1e97b35..658b97bc 100644
--- a/application/Utils.php
+++ b/application/Utils.php
@@ -84,4 +84,36 @@ function checkDateFormat($format, $string)
84 $date = DateTime::createFromFormat($format, $string); 84 $date = DateTime::createFromFormat($format, $string);
85 return $date && $date->format($string) == $string; 85 return $date && $date->format($string) == $string;
86} 86}
87?> 87
88/**
89 * Generate a header location from HTTP_REFERER.
90 * Make sure the referer is Shaarli itself and prevent redirection loop.
91 *
92 * @param string $referer - HTTP_REFERER.
93 * @param string $host - Server HOST.
94 * @param array $loopTerms - Contains list of term to prevent redirection loop.
95 *
96 * @return string $referer - final referer.
97 */
98function generateLocation($referer, $host, $loopTerms = array())
99{
100 $final_referer = '?';
101
102 // No referer if it contains any value in $loopCriteria.
103 foreach ($loopTerms as $value) {
104 if (strpos($referer, $value) !== false) {
105 return $final_referer;
106 }
107 }
108
109 // Remove port from HTTP_HOST
110 if ($pos = strpos($host, ':')) {
111 $host = substr($host, 0, $pos);
112 }
113
114 if (!empty($referer) && strpos(parse_url($referer, PHP_URL_HOST), $host) !== false) {
115 $final_referer = $referer;
116 }
117
118 return $final_referer;
119}
diff --git a/index.php b/index.php
index 5771dd88..8e1552c1 100644
--- a/index.php
+++ b/index.php
@@ -1099,6 +1099,11 @@ function renderPage()
1099 if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER 1099 if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER
1100 parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); 1100 parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
1101 1101
1102 // Prevent redirection loop
1103 if (isset($params['addtag'])) {
1104 unset($params['addtag']);
1105 }
1106
1102 // Check if this tag is already in the search query and ignore it if it is. 1107 // Check if this tag is already in the search query and ignore it if it is.
1103 // Each tag is always separated by a space 1108 // Each tag is always separated by a space
1104 $current_tags = explode(' ', $params['searchtags']); 1109 $current_tags = explode(' ', $params['searchtags']);
@@ -1123,16 +1128,29 @@ function renderPage()
1123 } 1128 }
1124 1129
1125 // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) 1130 // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
1126 if (isset($_GET['removetag'])) 1131 if (isset($_GET['removetag'])) {
1127 {
1128 // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. 1132 // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query.
1129 if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER 1133 if (empty($_SERVER['HTTP_REFERER'])) {
1130 parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); 1134 header('Location: ?');
1131 if (isset($params['searchtags'])) 1135 exit;
1132 { 1136 }
1137
1138 // In case browser does not send HTTP_REFERER
1139 parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
1140
1141 // Prevent redirection loop
1142 if (isset($params['removetag'])) {
1143 unset($params['removetag']);
1144 }
1145
1146 if (isset($params['searchtags'])) {
1133 $tags = explode(' ',$params['searchtags']); 1147 $tags = explode(' ',$params['searchtags']);
1134 $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. 1148 $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags.
1135 if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags); 1149 if (count($tags)==0) {
1150 unset($params['searchtags']);
1151 } else {
1152 $params['searchtags'] = implode(' ',$tags);
1153 }
1136 unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) 1154 unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
1137 } 1155 }
1138 header('Location: ?'.http_build_query($params)); 1156 header('Location: ?'.http_build_query($params));
@@ -1140,33 +1158,24 @@ function renderPage()
1140 } 1158 }
1141 1159
1142 // -------- User wants to change the number of links per page (linksperpage=...) 1160 // -------- User wants to change the number of links per page (linksperpage=...)
1143 if (isset($_GET['linksperpage'])) 1161 if (isset($_GET['linksperpage'])) {
1144 { 1162 if (is_numeric($_GET['linksperpage'])) {
1145 if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } 1163 $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage']));
1146 // Make sure the referrer is Shaarli itself. 1164 }
1147 $referer = '?'; 1165
1148 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) 1166 header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage')));
1149 $referer = $_SERVER['HTTP_REFERER'];
1150 header('Location: '.$referer);
1151 exit; 1167 exit;
1152 } 1168 }
1153 1169
1154 // -------- User wants to see only private links (toggle) 1170 // -------- User wants to see only private links (toggle)
1155 if (isset($_GET['privateonly'])) 1171 if (isset($_GET['privateonly'])) {
1156 { 1172 if (empty($_SESSION['privateonly'])) {
1157 if (empty($_SESSION['privateonly'])) 1173 $_SESSION['privateonly'] = 1; // See only private links
1158 { 1174 } else {
1159 $_SESSION['privateonly']=1; // See only private links
1160 }
1161 else
1162 {
1163 unset($_SESSION['privateonly']); // See all links 1175 unset($_SESSION['privateonly']); // See all links
1164 } 1176 }
1165 // Make sure the referrer is Shaarli itself. 1177
1166 $referer = '?'; 1178 header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly')));
1167 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
1168 $referer = $_SERVER['HTTP_REFERER'];
1169 header('Location: '.$referer);
1170 exit; 1179 exit;
1171 } 1180 }
1172 1181
@@ -1349,10 +1358,10 @@ function renderPage()
1349 1358
1350 // If we are called from the bookmarklet, we must close the popup: 1359 // If we are called from the bookmarklet, we must close the popup:
1351 if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } 1360 if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
1352 $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); 1361 $returnurl = ( !empty($_POST['returnurl']) ? escape($_POST['returnurl']) : '?' );
1353 $returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited. 1362 $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
1354 if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead 1363 $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
1355 header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on. 1364 header('Location: '. $location); // After saving the link, redirect to the page the user was on.
1356 exit; 1365 exit;
1357 } 1366 }
1358 1367
@@ -1363,6 +1372,7 @@ function renderPage()
1363 if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } 1372 if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
1364 $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); 1373 $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
1365 $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. 1374 $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
1375 $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
1366 header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. 1376 header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
1367 exit; 1377 exit;
1368 } 1378 }
@@ -1395,18 +1405,15 @@ function renderPage()
1395 // redirect is not satisfied, and only then redirect to / 1405 // redirect is not satisfied, and only then redirect to /
1396 $location = "?"; 1406 $location = "?";
1397 // Self redirection 1407 // Self redirection
1398 if (count($_GET) == 0 || 1408 if (count($_GET) == 0
1399 isset($_GET['page']) || 1409 || isset($_GET['page'])
1400 isset($_GET['searchterm']) || 1410 || isset($_GET['searchterm'])
1401 isset($_GET['searchtags'])) { 1411 || isset($_GET['searchtags'])
1402 1412 ) {
1403 if (isset($_POST['returnurl'])) { 1413 if (isset($_POST['returnurl'])) {
1404 $location = $_POST['returnurl']; // Handle redirects given by the form 1414 $location = $_POST['returnurl']; // Handle redirects given by the form
1405 } 1415 } else {
1406 1416 $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link'));
1407 if ($location === "?" &&
1408 isset($_SERVER['HTTP_REFERER'])) { // Handle HTTP_REFERER in case we're not coming from the same place.
1409 $location = $_SERVER['HTTP_REFERER'];
1410 } 1417 }
1411 } 1418 }
1412 1419
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 90392dfb..8355c7f8 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -93,5 +93,30 @@ class UtilsTest extends PHPUnit_Framework_TestCase
93 $this->assertFalse(checkDateFormat('Y-m-d', '2015-06')); 93 $this->assertFalse(checkDateFormat('Y-m-d', '2015-06'));
94 $this->assertFalse(checkDateFormat('Ymd', 'DeLorean')); 94 $this->assertFalse(checkDateFormat('Ymd', 'DeLorean'));
95 } 95 }
96
97 /**
98 * Test generate location with valid data.
99 */
100 public function testGenerateLocation() {
101 $ref = 'http://localhost/?test';
102 $this->assertEquals($ref, generateLocation($ref, 'localhost'));
103 $ref = 'http://localhost:8080/?test';
104 $this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
105 }
106
107 /**
108 * Test generate location - anti loop.
109 */
110 public function testGenerateLocationLoop() {
111 $ref = 'http://localhost/?test';
112 $this->assertEquals('?', generateLocation($ref, 'localhost', ['test']));
113 }
114
115 /**
116 * Test generate location - from other domain.
117 */
118 public function testGenerateLocationOut() {
119 $ref = 'http://somewebsite.com/?test';
120 $this->assertEquals('?', generateLocation($ref, 'localhost'));
121 }
96} 122}
97?>