diff options
author | VirtualTam <tamisier.aurelien@gmail.com> | 2015-07-12 19:56:13 +0200 |
---|---|---|
committer | VirtualTam <tamisier.aurelien@gmail.com> | 2015-07-12 19:56:13 +0200 |
commit | 5b0ebbc5de06b8a0e9679b78b45d0dc755db7986 (patch) | |
tree | ed6a7f6c7ea02d0942d32c31637553976e978c5f | |
parent | 1dcbe29611a4ba4b4b2d37954105c1fc8da33496 (diff) | |
parent | 775803a05cdba9d7fc1b37af4b15ecd80a8cbcc2 (diff) | |
download | Shaarli-5b0ebbc5de06b8a0e9679b78b45d0dc755db7986.tar.gz Shaarli-5b0ebbc5de06b8a0e9679b78b45d0dc755db7986.tar.zst Shaarli-5b0ebbc5de06b8a0e9679b78b45d0dc755db7986.zip |
Merge pull request #257 from ArthurHoaro/tag-http-referer
Prevent redirection loop everytime we rely on HTTP_REFERER
-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 | } | ||
@@ -1120,6 +1120,11 @@ function renderPage() | |||
1120 | if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER | 1120 | if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER |
1121 | parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); | 1121 | parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); |
1122 | 1122 | ||
1123 | // Prevent redirection loop | ||
1124 | if (isset($params['addtag'])) { | ||
1125 | unset($params['addtag']); | ||
1126 | } | ||
1127 | |||
1123 | // Check if this tag is already in the search query and ignore it if it is. | 1128 | // Check if this tag is already in the search query and ignore it if it is. |
1124 | // Each tag is always separated by a space | 1129 | // Each tag is always separated by a space |
1125 | if (isset($params['searchtags'])) { | 1130 | if (isset($params['searchtags'])) { |
@@ -1148,16 +1153,29 @@ function renderPage() | |||
1148 | } | 1153 | } |
1149 | 1154 | ||
1150 | // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) | 1155 | // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) |
1151 | if (isset($_GET['removetag'])) | 1156 | if (isset($_GET['removetag'])) { |
1152 | { | ||
1153 | // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. | 1157 | // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. |
1154 | if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER | 1158 | if (empty($_SERVER['HTTP_REFERER'])) { |
1155 | parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); | 1159 | header('Location: ?'); |
1156 | if (isset($params['searchtags'])) | 1160 | exit; |
1157 | { | 1161 | } |
1162 | |||
1163 | // In case browser does not send HTTP_REFERER | ||
1164 | parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); | ||
1165 | |||
1166 | // Prevent redirection loop | ||
1167 | if (isset($params['removetag'])) { | ||
1168 | unset($params['removetag']); | ||
1169 | } | ||
1170 | |||
1171 | if (isset($params['searchtags'])) { | ||
1158 | $tags = explode(' ',$params['searchtags']); | 1172 | $tags = explode(' ',$params['searchtags']); |
1159 | $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. | 1173 | $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. |
1160 | if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags); | 1174 | if (count($tags)==0) { |
1175 | unset($params['searchtags']); | ||
1176 | } else { | ||
1177 | $params['searchtags'] = implode(' ',$tags); | ||
1178 | } | ||
1161 | unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) | 1179 | unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) |
1162 | } | 1180 | } |
1163 | header('Location: ?'.http_build_query($params)); | 1181 | header('Location: ?'.http_build_query($params)); |
@@ -1165,33 +1183,24 @@ function renderPage() | |||
1165 | } | 1183 | } |
1166 | 1184 | ||
1167 | // -------- User wants to change the number of links per page (linksperpage=...) | 1185 | // -------- User wants to change the number of links per page (linksperpage=...) |
1168 | if (isset($_GET['linksperpage'])) | 1186 | if (isset($_GET['linksperpage'])) { |
1169 | { | 1187 | if (is_numeric($_GET['linksperpage'])) { |
1170 | if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } | 1188 | $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); |
1171 | // Make sure the referrer is Shaarli itself. | 1189 | } |
1172 | $referer = '?'; | 1190 | |
1173 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) | 1191 | header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage'))); |
1174 | $referer = $_SERVER['HTTP_REFERER']; | ||
1175 | header('Location: '.$referer); | ||
1176 | exit; | 1192 | exit; |
1177 | } | 1193 | } |
1178 | 1194 | ||
1179 | // -------- User wants to see only private links (toggle) | 1195 | // -------- User wants to see only private links (toggle) |
1180 | if (isset($_GET['privateonly'])) | 1196 | if (isset($_GET['privateonly'])) { |
1181 | { | 1197 | if (empty($_SESSION['privateonly'])) { |
1182 | if (empty($_SESSION['privateonly'])) | 1198 | $_SESSION['privateonly'] = 1; // See only private links |
1183 | { | 1199 | } else { |
1184 | $_SESSION['privateonly']=1; // See only private links | ||
1185 | } | ||
1186 | else | ||
1187 | { | ||
1188 | unset($_SESSION['privateonly']); // See all links | 1200 | unset($_SESSION['privateonly']); // See all links |
1189 | } | 1201 | } |
1190 | // Make sure the referrer is Shaarli itself. | 1202 | |
1191 | $referer = '?'; | 1203 | header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly'))); |
1192 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) | ||
1193 | $referer = $_SERVER['HTTP_REFERER']; | ||
1194 | header('Location: '.$referer); | ||
1195 | exit; | 1204 | exit; |
1196 | } | 1205 | } |
1197 | 1206 | ||
@@ -1398,10 +1407,10 @@ function renderPage() | |||
1398 | 1407 | ||
1399 | // If we are called from the bookmarklet, we must close the popup: | 1408 | // If we are called from the bookmarklet, we must close the popup: |
1400 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1409 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
1401 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1410 | $returnurl = ( !empty($_POST['returnurl']) ? escape($_POST['returnurl']) : '?' ); |
1402 | $returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited. | 1411 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. |
1403 | if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead | 1412 | $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); |
1404 | header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on. | 1413 | header('Location: '. $location); // After saving the link, redirect to the page the user was on. |
1405 | exit; | 1414 | exit; |
1406 | } | 1415 | } |
1407 | 1416 | ||
@@ -1412,6 +1421,7 @@ function renderPage() | |||
1412 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1421 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
1413 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1422 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); |
1414 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. | 1423 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. |
1424 | $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); | ||
1415 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. | 1425 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. |
1416 | exit; | 1426 | exit; |
1417 | } | 1427 | } |
@@ -1444,18 +1454,15 @@ function renderPage() | |||
1444 | // redirect is not satisfied, and only then redirect to / | 1454 | // redirect is not satisfied, and only then redirect to / |
1445 | $location = "?"; | 1455 | $location = "?"; |
1446 | // Self redirection | 1456 | // Self redirection |
1447 | if (count($_GET) == 0 || | 1457 | if (count($_GET) == 0 |
1448 | isset($_GET['page']) || | 1458 | || isset($_GET['page']) |
1449 | isset($_GET['searchterm']) || | 1459 | || isset($_GET['searchterm']) |
1450 | isset($_GET['searchtags'])) { | 1460 | || isset($_GET['searchtags']) |
1451 | 1461 | ) { | |
1452 | if (isset($_POST['returnurl'])) { | 1462 | if (isset($_POST['returnurl'])) { |
1453 | $location = $_POST['returnurl']; // Handle redirects given by the form | 1463 | $location = $_POST['returnurl']; // Handle redirects given by the form |
1454 | } | 1464 | } else { |
1455 | 1465 | $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link')); | |
1456 | if ($location === "?" && | ||
1457 | isset($_SERVER['HTTP_REFERER'])) { // Handle HTTP_REFERER in case we're not coming from the same place. | ||
1458 | $location = $_SERVER['HTTP_REFERER']; | ||
1459 | } | 1466 | } |
1460 | } | 1467 | } |
1461 | 1468 | ||
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 | ?> | ||