diff options
author | ArthurHoaro <arthur@hoa.ro> | 2015-07-06 10:22:00 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2015-07-12 17:43:13 +0200 |
commit | 775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2 (patch) | |
tree | 9a161fb97e69880f3ac8a034714418428937db6b | |
parent | 7f1dfd1c12a143b324fbe68213a49de0586febfa (diff) | |
download | Shaarli-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.php | 34 | ||||
-rw-r--r-- | index.php | 91 | ||||
-rw-r--r-- | tests/UtilsTest.php | 27 |
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 | */ | ||
98 | function 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 | } | ||
@@ -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 | ?> | ||