From: VirtualTam Date: Sun, 12 Jul 2015 17:56:13 +0000 (+0200) Subject: Merge pull request #257 from ArthurHoaro/tag-http-referer X-Git-Tag: v0.5.0~6 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=5b0ebbc5de06b8a0e9679b78b45d0dc755db7986;hp=-c;p=github%2Fshaarli%2FShaarli.git Merge pull request #257 from ArthurHoaro/tag-http-referer Prevent redirection loop everytime we rely on HTTP_REFERER --- 5b0ebbc5de06b8a0e9679b78b45d0dc755db7986 diff --combined index.php index b705146a,8e1552c1..bf0b99e0 --- a/index.php +++ b/index.php @@@ -11,8 -11,7 +11,8 @@@ date_default_timezone_set('UTC'); // ----------------------------------------------------------------------------------------------- -// Hardcoded parameter (These parameters can be overwritten by creating the file /data/options.php) +// Hardcoded parameter (These parameters can be overwritten by editing the file /data/config.php) +// You should not touch any code below (or at your own risks!) $GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password) $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file. @@@ -37,6 -36,10 +37,6 @@@ $GLOBALS['config']['ARCHIVE_ORG'] = fal $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; // Enable RSS permalinks by default. This corresponds to the default behavior of shaarli before this was added as an option. $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false; // ----------------------------------------------------------------------------------------------- -// You should not touch below (or at your own risks!) -// Optional config file. -if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); - define('shaarli_version','0.0.45beta'); // http://server.com/x/shaarli --> /shaarli/ define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); @@@ -63,15 -66,9 +63,15 @@@ checkphpversion() error_reporting(E_ALL^E_WARNING); // See all error except warnings. //error_reporting(-1); // See all errors (for debugging only) +// User configuration +if (is_file($GLOBALS['config']['CONFIG_FILE'])) { + require_once $GLOBALS['config']['CONFIG_FILE']; +} + // Shaarli library require_once 'application/LinkDB.php'; require_once 'application/Utils.php'; +require_once 'application/Config.php'; include "inc/rain.tpl.class.php"; //include Rain TPL raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory @@@ -103,15 -100,15 +103,15 @@@ if (empty($GLOBALS['title'])) $GLOBALS[ if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; -if (empty($GLOBALS['disablejquery'])) $GLOBALS['disablejquery']=false; if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; // I really need to rewrite Shaarli with a proper configuation manager. // Run config screen if first run: -if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); +if (! is_file($GLOBALS['config']['CONFIG_FILE'])) { + install(); +} -require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. $GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : ''; $GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : ''; $GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : ''; @@@ -859,18 -856,15 +859,18 @@@ function showATOM( // Daily RSS feed: 1 RSS entry per day giving all the links on that day. // Gives the last 7 days (which have links). // This RSS feed cannot be filtered. -function showDailyRSS() -{ +function showDailyRSS() { // Cache system $query = $_SERVER["QUERY_STRING"]; - $cache = new pageCache(pageUrl(),startsWith($query,'do=dailyrss') && !isLoggedIn()); - $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } - // If cached was not found (or not usable), then read the database and build the response: + $cache = new pageCache(pageUrl(), startsWith($query, 'do=dailyrss') && !isLoggedIn()); + $cached = $cache->cachedVersion(); + if (!empty($cached)) { + echo $cached; + exit; + } -// Read links from database (and filter private links if used it not logged in). + // If cached was not found (or not usable), then read the database and build the response: + // Read links from database (and filter private links if used it not logged in). $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'], @@@ -880,75 -874,60 +880,75 @@@ /* Some Shaarlies may have very few links, so we need to look back in time (rsort()) until we have enough days ($nb_of_days). */ - $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; } + $linkdates = array(); + foreach ($LINKSDB as $linkdate => $value) { + $linkdates[] = $linkdate; + } rsort($linkdates); - $nb_of_days=7; // We take 7 days. - $today=Date('Ymd'); - $days=array(); - foreach($linkdates as $linkdate) - { - $day=substr($linkdate,0,8); // Extract day (without time) - if (strcmp($day,$today)<0) - { - if (empty($days[$day])) $days[$day]=array(); - $days[$day][]=$linkdate; + $nb_of_days = 7; // We take 7 days. + $today = Date('Ymd'); + $days = array(); + + foreach ($linkdates as $linkdate) { + $day = substr($linkdate, 0, 8); // Extract day (without time) + if (strcmp($day,$today) < 0) { + if (empty($days[$day])) { + $days[$day] = array(); + } + $days[$day][] = $linkdate; + } + + if (count($days) > $nb_of_days) { + break; // Have we collected enough days? } - if (count($days)>$nb_of_days) break; // Have we collected enough days? } // Build the RSS feed. header('Content-Type: application/rss+xml; charset=utf-8'); - $pageaddr=escape(indexUrl()); + $pageaddr = escape(indexUrl()); echo ''; - echo 'Daily - '.$GLOBALS['title'].''.$pageaddr.''; - echo 'Daily shared linksen-en'.$pageaddr.''."\n"; - - foreach($days as $day=>$linkdates) // For each day. - { - $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date + echo ''; + echo 'Daily - '. $GLOBALS['title'] . ''; + echo ''. $pageaddr .''; + echo 'Daily shared links'; + echo 'en-en'; + echo ''. $pageaddr .''. PHP_EOL; + + // For each day. + foreach ($days as $day => $linkdates) { + $daydate = linkdate2timestamp($day.'_000000'); // Full text date $rfc822date = linkdate2rfc822($day.'_000000'); - $absurl=escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. - echo ''.$GLOBALS['title'].' - '.$daydate.''.$absurl.''.$absurl.''; - echo ''.escape($rfc822date).""; + $absurl = escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. // Build the HTML body of this RSS entry. - $html=''; - $href=''; - $links=array(); + $html = ''; + $href = ''; + $links = array(); + // We pre-format some fields for proper output. - foreach($linkdates as $linkdate) - { + foreach ($linkdates as $linkdate) { $l = $LINKSDB[$linkdate]; - $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($l['description']))); + $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable($l['description']))); $l['thumbnail'] = thumbnail($l['url']); $l['timestamp'] = linkdate2timestamp($l['linkdate']); - if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute - $links[$linkdate]=$l; + if (startsWith($l['url'], '?')) { + $l['url'] = indexUrl() . $l['url']; // make permalink URL absolute + } + $links[$linkdate] = $l; } + // Then build the HTML for this day: $tpl = new RainTPL; - $tpl->assign('links',$links); - $html = $tpl->draw('dailyrss',$return_string=true); - echo "\n"; - echo ''."\n\n\n"; + $tpl->assign('title', $GLOBALS['title']); + $tpl->assign('daydate', $daydate); + $tpl->assign('absurl', $absurl); + $tpl->assign('links', $links); + $tpl->assign('rfc822date', escape($rfc822date)); + $html = $tpl->draw('dailyrss', $return_string=true); + echo $html . PHP_EOL; } - echo ''; + echo ''; $cache->cache(ob_get_contents()); ob_end_flush(); @@@ -1120,13 -1099,14 +1120,18 @@@ function renderPage( 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); + // 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. // Each tag is always separated by a space - $current_tags = explode(' ', $params['searchtags']); + if (isset($params['searchtags'])) { + $current_tags = explode(' ', $params['searchtags']); + } else { + $current_tags = array(); + } $addtag = true; foreach ($current_tags as $value) { if ($value === $_GET['addtag']) { @@@ -1148,16 -1128,29 +1153,29 @@@ } // -------- 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. - 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); - if (isset($params['searchtags'])) - { + 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); + + // Prevent redirection loop + if (isset($params['removetag'])) { + unset($params['removetag']); + } + + if (isset($params['searchtags'])) { $tags = explode(' ',$params['searchtags']); $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) } header('Location: ?'.http_build_query($params)); @@@ -1165,33 -1158,24 +1183,24 @@@ } // -------- User wants to change the number of links per page (linksperpage=...) - if (isset($_GET['linksperpage'])) - { - if (is_numeric($_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) - $referer = $_SERVER['HTTP_REFERER']; - header('Location: '.$referer); + if (isset($_GET['linksperpage'])) { + if (is_numeric($_GET['linksperpage'])) { + $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); + } + + header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage'))); exit; } // -------- User wants to see only private links (toggle) - if (isset($_GET['privateonly'])) - { - if (empty($_SESSION['privateonly'])) - { - $_SESSION['privateonly']=1; // See only private links - } - else - { + if (isset($_GET['privateonly'])) { + if (empty($_SESSION['privateonly'])) { + $_SESSION['privateonly'] = 1; // See only private links + } else { unset($_SESSION['privateonly']); // See all links } - // 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) - $referer = $_SERVER['HTTP_REFERER']; - header('Location: '.$referer); + + header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly'))); exit; } @@@ -1245,19 -1229,7 +1254,19 @@@ // Save new password $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); - writeConfig(); + try { + writeConfig($GLOBALS, isLoggedIn()); + } + catch(Exception $e) { + error_log( + 'ERROR while writing config file after changing password.' . PHP_EOL . + $e->getMessage() + ); + + // TODO: do not handle exceptions/errors in JS. + echo ''; + exit; + } echo ''; exit; } @@@ -1286,23 -1258,12 +1295,23 @@@ $GLOBALS['titleLink']=$_POST['titleLink']; $GLOBALS['redirector']=$_POST['redirector']; $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); - $GLOBALS['disablejquery']=!empty($_POST['disablejquery']); $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); - writeConfig(); + try { + writeConfig($GLOBALS, isLoggedIn()); + } + catch(Exception $e) { + error_log( + 'ERROR while writing config file after configuration update.' . PHP_EOL . + $e->getMessage() + ); + + // TODO: do not handle exceptions/errors in JS. + echo ''; + exit; + } echo ''; exit; } @@@ -1384,7 -1345,6 +1393,7 @@@ { if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. + $tags = implode(' ', array_unique(explode(' ', $tags))); // Remove duplicates. $linkdate=$_POST['lf_linkdate']; $url = trim($_POST['lf_url']); if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?') && !startsWith($url,'javascript:')) @@@ -1398,10 -1358,10 +1407,10 @@@ // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; } - $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); - $returnurl .= '#'.smallHash($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 - header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on. + $returnurl = ( !empty($_POST['returnurl']) ? escape($_POST['returnurl']) : '?' ); + $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. + $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); + header('Location: '. $location); // After saving the link, redirect to the page the user was on. exit; } @@@ -1412,6 -1372,7 +1421,7 @@@ if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; } $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); $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. exit; } @@@ -1444,18 -1405,15 +1454,15 @@@ // redirect is not satisfied, and only then redirect to / $location = "?"; // Self redirection - if (count($_GET) == 0 || - isset($_GET['page']) || - isset($_GET['searchterm']) || - isset($_GET['searchtags'])) { - + if (count($_GET) == 0 + || isset($_GET['page']) + || isset($_GET['searchterm']) + || isset($_GET['searchtags']) + ) { if (isset($_POST['returnurl'])) { $location = $_POST['returnurl']; // Handle redirects given by the form - } - - if ($location === "?" && - isset($_SERVER['HTTP_REFERER'])) { // Handle HTTP_REFERER in case we're not coming from the same place. - $location = $_SERVER['HTTP_REFERER']; + } else { + $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link')); } } @@@ -1756,7 -1714,7 +1763,7 @@@ function buildLinkList($PAGE,$LINKSDB { header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); echo '

404 Not found.

Oh crap. The link you are trying to reach does not exist or has been deleted.'; - echo '
You would mind clicking here?'; + echo '
Would you mind clicking here?'; exit; } $search_type='permalink'; @@@ -2062,19 -2020,7 +2069,19 @@@ function install( $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] ); $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); - writeConfig(); + try { + writeConfig($GLOBALS, isLoggedIn()); + } + catch(Exception $e) { + error_log( + 'ERROR while writing config file after installation.' . PHP_EOL . + $e->getMessage() + ); + + // TODO: do not handle exceptions/errors in JS. + echo ''; + exit; + } echo ''; exit; } @@@ -2188,7 -2134,30 +2195,7 @@@ if (!function_exists('json_encode')) } } -// Re-write configuration file according to globals. -// Requires some $GLOBALS to be set (login,hash,salt,title). -// If the config file cannot be saved, an error message is displayed and the user is redirected to "Tools" menu. -// (otherwise, the function simply returns.) -function writeConfig() -{ - if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. - $config=''; - if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0) - { - echo ''; - exit; - } -} + /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. @@@ -2417,15 -2386,6 +2424,15 @@@ function invalidateCaches( pageCache::purgeCache(); // Purge page cache shared by sessions. } +try { + mergeDeprecatedConfig($GLOBALS, isLoggedIn()); +} catch(Exception $e) { + error_log( + 'ERROR while merging deprecated options.php file.' . PHP_EOL . + $e->getMessage() + ); +} + if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }