]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Working on shaarli/Shaarli#224 228/head
authorArthurHoaro <arthur@hoa.ro>
Thu, 11 Jun 2015 11:53:27 +0000 (13:53 +0200)
committerArthurHoaro <arthur@hoa.ro>
Tue, 23 Jun 2015 14:35:36 +0000 (16:35 +0200)
I reviewed character escaping everywhere with the following ideas:

  * use a single common function to escape user data: `escape` using `htmlspecialchars`.
  * sanitize fields in `index.php` after reading them from datastore and before sending them to templates.
   It means no escaping function in Twig templates.
    2 reasons:
    * it reduces risks of security issue for future user made templates
    * more readable templates
  * sanitize user configuration fields after loading them.

12 files changed:
application/LinkDB.php
index.php
tpl/daily.html
tpl/dailyrss.html
tpl/editlink.html
tpl/import.html
tpl/linklist.html
tpl/loginform.html
tpl/page.footer.html
tpl/page.header.html
tpl/picwall.html
tpl/tagcloud.html

index 137f42e5d5cde66aa1fb1d3eb9dc116e796ddfb9..0f7c5bfed2d9c61bdf95acae617e05abf9000beb 100644 (file)
@@ -245,6 +245,11 @@ class LinkDB implements Iterator, Countable, ArrayAccess
         foreach ($this->links as $link) {
             $this->urls[$link['url']] = $link['linkdate'];
         }
+
+        // Escape links data
+        foreach($this->links as &$link) { 
+            sanitizeLink($link); 
+        }
     }
 
     /**
index 5aa7116fe087404ff2048a0cc2068c8ac71d7107..39b01a2eb0eb3c3457a78da481f459367220d538 100644 (file)
--- a/index.php
+++ b/index.php
@@ -98,7 +98,7 @@ header("Pragma: no-cache");
 if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>');
 
 // Handling of old config file which do not have the new parameters.
-if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl());
+if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(indexUrl());
 if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get();
 if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']='';
 if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false;
@@ -111,6 +111,9 @@ if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?';
 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']) : '';
 
 // a token depending of deployment salt, user password, and the current ip
 define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt']));
@@ -272,6 +275,17 @@ function nl2br_escaped($html)
     return str_replace('>','&gt;',str_replace('<','&lt;',nl2br($html)));
 }
 
+function escape($str) {
+    return htmlspecialchars($str, ENT_COMPAT, 'UTF-8', false);
+}
+
+function sanitizeLink(&$link) {
+    $link['url'] = escape($link['url']); // useful?
+    $link['title'] = escape($link['title']);
+    $link['description'] = escape($link['description']);
+    $link['tags'] = escape($link['tags']);
+}
+
 // In a string, converts URLs to clickable links.
 // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
 function text2clickable($url)
@@ -651,8 +665,8 @@ class pageBuilder
     private function initialize()
     {
         $this->tpl = new RainTPL;
-        $this->tpl->assign('newversion',checkUpdate());
-        $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
+        $this->tpl->assign('newversion',escape(checkUpdate()));
+        $this->tpl->assign('feedurl',escape(indexUrl()));
         $searchcrits=''; // Search criteria
         if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
         elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
@@ -716,15 +730,15 @@ function showRSS()
         $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
     }
 
-    $pageaddr=htmlspecialchars(indexUrl());
+    $pageaddr=escape(indexUrl());
     echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">';
-    echo '<channel><title>'.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>';
+    echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
     echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n";
     if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
     {
         echo '<!-- PubSubHubbub Discovery -->';
-        echo '<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />';
-        echo '<link rel="self" href="'.htmlspecialchars($pageaddr).'?do=rss" xmlns="http://www.w3.org/2005/Atom" />';
+        echo '<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />';
+        echo '<link rel="self" href="'.$pageaddr.'?do=rss" xmlns="http://www.w3.org/2005/Atom" />';
         echo '<!-- End Of PubSubHubbub Discovery -->';
     }
     $i=0;
@@ -734,16 +748,16 @@ function showRSS()
         $link = $linksToDisplay[$keys[$i]];
         $guid = $pageaddr.'?'.smallHash($link['linkdate']);
         $rfc822date = linkdate2rfc822($link['linkdate']);
-        $absurl = htmlspecialchars($link['url']);
+        $absurl = $link['url'];
         if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl;  // make permalink URL absolute
         if ($usepermalinks===true)
-            echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>';
+            echo '<item><title>'.$link['title'].'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>';
         else
-            echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>';
-        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>\n";
+            echo '<item><title>'.$link['title'].'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>';
+        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.escape($rfc822date)."</pubDate>\n";
         if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
         {
-            foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.htmlspecialchars($pageaddr).'">'.htmlspecialchars($tag).'</category>'."\n"; }
+            foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.$pageaddr.'">'.$tag.'</category>'."\n"; }
         }
 
         // Add permalink in description
@@ -751,10 +765,10 @@ function showRSS()
         // If user wants permalinks first, put the final link in description
         if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
         if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
-        echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$descriptionlink.']]></description>'."\n</item>\n";
+        echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink.']]></description>'."\n</item>\n";
         $i++;
     }
-    echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->';
+    echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->';
 
     $cache->cache(ob_get_contents());
     ob_end_flush();
@@ -779,7 +793,6 @@ function showATOM()
 
     $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
 
-
     // Optionally filter the results:
     $linksToDisplay=array();
     if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
@@ -792,7 +805,7 @@ function showATOM()
         $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
     }
 
-    $pageaddr=htmlspecialchars(indexUrl());
+    $pageaddr=escape(indexUrl());
     $latestDate = '';
     $entries='';
     $i=0;
@@ -803,44 +816,44 @@ function showATOM()
         $guid = $pageaddr.'?'.smallHash($link['linkdate']);
         $iso8601date = linkdate2iso8601($link['linkdate']);
         $latestDate = max($latestDate,$iso8601date);
-        $absurl = htmlspecialchars($link['url']);
+        $absurl = $link['url'];
         if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl;  // make permalink URL absolute
-        $entries.='<entry><title>'.htmlspecialchars($link['title']).'</title>';
+        $entries.='<entry><title>'.$link['title'].'</title>';
         if ($usepermalinks===true)
             $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>';
         else
             $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>';
-        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.htmlspecialchars($iso8601date).'</updated>';
+        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.escape($iso8601date).'</updated>';
 
         // Add permalink in description
-        $descriptionlink = htmlspecialchars('(<a href="'.$guid.'">Permalink</a>)');
+        $descriptionlink = '(<a href="'.$guid.'">Permalink</a>)';
         // If user wants permalinks first, put the final link in description
-        if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(<a href="'.$absurl.'">Link</a>)');
-        if (strlen($link['description'])>0) $descriptionlink = '&lt;br&gt;'.$descriptionlink;
+        if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
+        if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
 
-        $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."</content>\n";
+        $entries.='<content type="html"><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink."]]></content>\n";
         if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)
         {
             foreach(explode(' ',$link['tags']) as $tag)
-                { $entries.='<category scheme="'.htmlspecialchars($pageaddr,ENT_QUOTES).'" term="'.htmlspecialchars($tag,ENT_QUOTES).'" />'."\n"; }
+                { $entries.='<category scheme="'.$pageaddr.'" term="'.$tag.'" />'."\n"; }
         }
         $entries.="</entry>\n";
         $i++;
     }
     $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">';
-    $feed.='<title>'.htmlspecialchars($GLOBALS['title']).'</title>';
-    if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.htmlspecialchars($latestDate).'</updated>';
-    $feed.='<link rel="self" href="'.htmlspecialchars(serverUrl().$_SERVER["REQUEST_URI"]).'" />';
+    $feed.='<title>'.$GLOBALS['title'].'</title>';
+    if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.escape($latestDate).'</updated>';
+    $feed.='<link rel="self" href="'.escape(serverUrl().$_SERVER["REQUEST_URI"]).'" />';
     if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
     {
         $feed.='<!-- PubSubHubbub Discovery -->';
-        $feed.='<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" />';
+        $feed.='<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" />';
         $feed.='<!-- End Of PubSubHubbub Discovery -->';
     }
-    $feed.='<author><name>'.htmlspecialchars($pageaddr).'</name><uri>'.htmlspecialchars($pageaddr).'</uri></author>';
-    $feed.='<id>'.htmlspecialchars($pageaddr).'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
+    $feed.='<author><name>'.$pageaddr.'</name><uri>'.$pageaddr.'</uri></author>';
+    $feed.='<id>'.$pageaddr.'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
     $feed.=$entries;
-    $feed.='</feed><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->';
+    $feed.='</feed><!-- Cached version of '.escape(pageUrl()).' -->';
     echo $feed;
 
     $cache->cache(ob_get_contents());
@@ -882,18 +895,18 @@ function showDailyRSS()
 
     // Build the RSS feed.
     header('Content-Type: application/rss+xml; charset=utf-8');
-    $pageaddr=htmlspecialchars(indexUrl());
+    $pageaddr=escape(indexUrl());
     echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
-    echo '<channel><title>Daily - '.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>';
+    echo '<channel><title>Daily - '.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
     echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n";
 
     foreach($days as $day=>$linkdates) // For each day.
     {
         $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
         $rfc822date = linkdate2rfc822($day.'_000000');
-        $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day);  // Absolute URL of the corresponding "Daily" page.
-        echo '<item><title>'.htmlspecialchars($GLOBALS['title'].' - '.$daydate).'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
-        echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>";
+        $absurl=escape(indexUrl().'?do=daily&day='.$day);  // Absolute URL of the corresponding "Daily" page.
+        echo '<item><title>'.$GLOBALS['title'].' - '.$daydate.'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
+        echo '<pubDate>'.escape($rfc822date)."</pubDate>";
 
         // Build the HTML body of this RSS entry.
         $html='';
@@ -903,7 +916,7 @@ function showDailyRSS()
         foreach($linkdates as $linkdate)
         {
             $l = $LINKSDB[$linkdate];
-            $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($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
@@ -917,7 +930,7 @@ function showDailyRSS()
         echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n";
 
     }
-    echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->';
+    echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->';
 
     $cache->cache(ob_get_contents());
     ob_end_flush();
@@ -929,7 +942,6 @@ function showDaily()
 {
     $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
 
-
     $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
     if (isset($_GET['day'])) $day=$_GET['day'];
 
@@ -948,10 +960,11 @@ function showDaily()
     // We pre-format some fields for proper output.
     foreach($linksToDisplay as $key=>$link)
     {
+
         $taglist = explode(' ',$link['tags']);
         uasort($taglist, 'strcasecmp');
         $linksToDisplay[$key]['taglist']=$taglist;
-        $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
+        $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
         $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);
         $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']);
     }
@@ -1002,7 +1015,7 @@ function renderPage()
         $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
         $PAGE = new pageBuilder;
         $PAGE->assign('token',$token);
-        $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:''));
+        $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
         $PAGE->renderPage('loginform');
         exit;
     }
@@ -1030,7 +1043,7 @@ function renderPage()
         // Get only links which have a thumbnail.
         foreach($links as $link)
         {
-            $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES);
+            $permalink='?'.escape(smallhash($link['linkdate']));
             $thumb=lazyThumbnail($link['url'],$permalink);
             if ($thumb!='') // Only output links which have a thumbnail.
             {
@@ -1239,8 +1252,8 @@ function renderPage()
             $PAGE = new pageBuilder;
             $PAGE->assign('linkcount',count($LINKSDB));
             $PAGE->assign('token',getToken());
-            $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
-            $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
+            $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] );
+            $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] );
             list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
             $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template?
             $PAGE->assign('timezone_js',$timezone_js);
@@ -1400,7 +1413,7 @@ function renderPage()
         $PAGE->assign('link',$link);
         $PAGE->assign('link_is_new',false);
         $PAGE->assign('token',getToken()); // XSRF protection.
-        $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
+        $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''));
         $PAGE->assign('tags', $LINKSDB->allTags());
         $PAGE->renderPage('editlink');
         exit;
@@ -1524,10 +1537,10 @@ HTML;
                ($exportWhat=='private' && $link['private']!=0) ||
                ($exportWhat=='public' && $link['private']==0))
             {
-                echo '<DT><A HREF="'.htmlspecialchars($link['url']).'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"';
-                if ($link['tags']!='') echo ' TAGS="'.htmlspecialchars(str_replace(' ',',',$link['tags'])).'"';
-                echo '>'.htmlspecialchars($link['title'])."</A>\n";
-                if ($link['description']!='') echo '<DD>'.htmlspecialchars($link['description'])."\n";
+                echo '<DT><A HREF="'.$link['url'].'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"';
+                if ($link['tags']!='') echo ' TAGS="'.str_replace(' ',',',$link['tags']).'"';
+                echo '>'.$link['title']."</A>\n";
+                if ($link['description']!='') echo '<DD>'.$link['description']."\n";
             }
         }
                 exit;
@@ -1540,7 +1553,7 @@ HTML;
         if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0))
         {
             $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] );
-            echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept ('.getMaxFileSize().' bytes). Please upload in smaller chunks.");document.location=\''.htmlspecialchars($returnurl).'\';</script>';
+            echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept ('.getMaxFileSize().' bytes). Please upload in smaller chunks.");document.location=\''.escape($returnurl).'\';</script>';
             exit;
         }
         if (!tokenOk($_POST['token'])) die('Wrong token.');
@@ -1663,13 +1676,13 @@ function buildLinkList($PAGE,$LINKSDB)
     if (isset($_GET['searchterm'])) // Fulltext search
     {
         $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm']));
-        $search_crits=htmlspecialchars(trim($_GET['searchterm']));
+        $search_crits=escape(trim($_GET['searchterm']));
         $search_type='fulltext';
     }
     elseif (isset($_GET['searchtags'])) // Search by tag
     {
         $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
-        $search_crits=explode(' ',trim($_GET['searchtags']));
+        $search_crits=explode(' ',escape(trim($_GET['searchtags'])));
         $search_type='tags';
     }
     elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL
@@ -1721,7 +1734,7 @@ function buildLinkList($PAGE,$LINKSDB)
     while ($i<$end && $i<count($keys))
     {
         $link = $linksToDisplay[$keys[$i]];
-        $link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
+        $link['description']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
         $title=$link['title'];
         $classLi =  $i%2!=0 ? '' : 'publicLinkHightLight';
         $link['class'] = ($link['private']==0 ? $classLi : 'private');
@@ -1867,7 +1880,7 @@ function computeThumbnail($url,$href=false)
             if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
         }
         $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
-        return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
+        return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
                      'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
     }
 
@@ -1878,7 +1891,7 @@ function computeThumbnail($url,$href=false)
     if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
     {
         $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
-        return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
+        return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
                      'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
     }
     return array(); // No thumbnail.
@@ -1897,11 +1910,11 @@ function thumbnail($url,$href=false)
     $t = computeThumbnail($url,$href);
     if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
 
-    $html='<a href="'.htmlspecialchars($t['href']).'"><img src="'.htmlspecialchars($t['src']).'"';
-    if (!empty($t['width']))  $html.=' width="'.htmlspecialchars($t['width']).'"';
-    if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
-    if (!empty($t['style']))  $html.=' style="'.htmlspecialchars($t['style']).'"';
-    if (!empty($t['alt']))    $html.=' alt="'.htmlspecialchars($t['alt']).'"';
+    $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"';
+    if (!empty($t['width']))  $html.=' width="'.escape($t['width']).'"';
+    if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
+    if (!empty($t['style']))  $html.=' style="'.escape($t['style']).'"';
+    if (!empty($t['alt']))    $html.=' alt="'.escape($t['alt']).'"';
     $html.='></a>';
     return $html;
 }
@@ -1917,23 +1930,23 @@ function lazyThumbnail($url,$href=false)
     $t = computeThumbnail($url,$href);
     if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
 
-    $html='<a href="'.htmlspecialchars($t['href']).'">';
+    $html='<a href="'.escape($t['href']).'">';
 
     // Lazy image
-    $html.='<img class="b-lazy" src="#" data-src="'.htmlspecialchars($t['src']).'"';
+    $html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"';
 
-    if (!empty($t['width']))  $html.=' width="'.htmlspecialchars($t['width']).'"';
-    if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
-    if (!empty($t['style']))  $html.=' style="'.htmlspecialchars($t['style']).'"';
-    if (!empty($t['alt']))    $html.=' alt="'.htmlspecialchars($t['alt']).'"';
+    if (!empty($t['width']))  $html.=' width="'.escape($t['width']).'"';
+    if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
+    if (!empty($t['style']))  $html.=' style="'.escape($t['style']).'"';
+    if (!empty($t['alt']))    $html.=' alt="'.escape($t['alt']).'"';
     $html.='>';
 
     // No-JavaScript fallback.
-    $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"';
-    if (!empty($t['width']))  $html.=' width="'.htmlspecialchars($t['width']).'"';
-    if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
-    if (!empty($t['style']))  $html.=' style="'.htmlspecialchars($t['style']).'"';
-    if (!empty($t['alt']))    $html.=' alt="'.htmlspecialchars($t['alt']).'"';
+    $html.='<noscript><img src="'.escape($t['src']).'"';
+    if (!empty($t['width']))  $html.=' width="'.escape($t['width']).'"';
+    if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
+    if (!empty($t['style']))  $html.=' style="'.escape($t['style']).'"';
+    if (!empty($t['alt']))    $html.=' alt="'.escape($t['alt']).'"';
     $html.='></noscript></a>';
 
     return $html;
@@ -1983,7 +1996,7 @@ function install()
         $GLOBALS['login'] = $_POST['setlogin'];
         $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
         $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
-        $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] );
+        $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] );
         $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
         writeConfig();
         echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>';
@@ -2210,7 +2223,7 @@ function genThumbnail()
         // This is more complex: we have to perform a HTTP request, then parse the result.
         // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
         $vid = substr(parse_url($url,PHP_URL_PATH),1);
-        list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5);
+        list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.escape($vid).'.php',5);
         if (strpos($httpstatus,'200 OK')!==false)
         {
             $t = unserialize($data);
index 0f7624903e2dc17f2f3fb47c85a7278868289396..38aa40125d60285230f4fda875c18fcfdb895888 100644 (file)
                         {if="$link.tags"}
                             <div class="dailyEntryTags">
                                 {loop="link.taglist"}
-                                    {$value|htmlspecialchars} -
+                                    {$value} -
                                 {/loop}
                             </div>
                         {/if}
                         <div class="dailyEntryTitle">
-                            <a href="{$link.url}">{$link.title|htmlspecialchars}</a>
+                            <a href="{$link.url}">{$link.title}</a>
                         </div>
                         {if="$link.thumbnail"}
                             <div class="dailyEntryThumbnail">{$link.thumbnail}</div>
index a9b11e1826a5a14c82c84cc0a209017a7a135801..1b7ab8e944559e38c5198fec35525eccde9c8b81 100644 (file)
@@ -1,7 +1,7 @@
 {loop="links"}
-       <h3><a href="{$value.url}">{$value.title|htmlspecialchars}</a></h3>
-       <small>{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags|htmlspecialchars}{/if}<br>
-       {$value.url|htmlspecialchars}</small><br>
+       <h3><a href="{$value.url}">{$value.title}</a></h3>
+       <small>{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
+       {$value.url}</small><br>
        {if="$value.thumbnail"}{$value.thumbnail}{/if}<br>
        {if="$value.description"}{$value.formatedDescription}{/if}
        <br><br><hr>
index 0276f0886acc377fa8727a4bd2bc37dfad1d3896..6737c4120f40a75d5dadc8c0a8e1f081e9fe98af 100644 (file)
        <div id="editlinkform">
            <form method="post" name="linkform">
                <input type="hidden" name="lf_linkdate" value="{$link.linkdate}">
-               <label for="lf_url"><i>URL</i></label><br><input type="text" name="lf_url" id="lf_url" value="{$link.url|htmlspecialchars}" class="lf_input"><br>
-            <label for="lf_title"><i>Title</i></label><br><input type="text" name="lf_title" id="lf_title" value="{$link.title|htmlspecialchars}" class="lf_input"><br>
-            <label for="lf_description"><i>Description</i></label><br><textarea name="lf_description" id="lf_description" rows="4" cols="25">{$link.description|htmlspecialchars}</textarea><br>
+               <label for="lf_url"><i>URL</i></label><br><input type="text" name="lf_url" id="lf_url" value="{$link.url}" class="lf_input"><br>
+            <label for="lf_title"><i>Title</i></label><br><input type="text" name="lf_title" id="lf_title" value="{$link.title}" class="lf_input"><br>
+            <label for="lf_description"><i>Description</i></label><br><textarea name="lf_description" id="lf_description" rows="4" cols="25">{$link.description}</textarea><br>
             <label for="lf_tags"><i>Tags</i></label><br>
-            <input type="text" id="lf_tags" name="lf_tags" id="lf_tags" value="{$link.tags|htmlspecialchars}" class="lf_input"
+            <input type="text" id="lf_tags" name="lf_tags" id="lf_tags" value="{$link.tags}" class="lf_input"
                 data-list="{loop="$tags"}{$key}, {/loop}" data-multiple autocomplete="off" ><br>
                {if="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"}
             <input type="checkbox" checked="checked" name="lf_private" id="lf_private">
@@ -32,7 +32,7 @@
                <input type="submit" value="Cancel" name="cancel_edit" class="bigbutton">
                {if="!$link_is_new"}<input type="submit" value="Delete" name="delete_link" class="bigbutton delete" onClick="return confirmDeleteLink();">{/if}
                <input type="hidden" name="token" value="{$token}">
-               {if="$http_referer"}<input type="hidden" name="returnurl" value="{$http_referer|htmlspecialchars}">{/if}
+               {if="$http_referer"}<input type="hidden" name="returnurl" value="{$http_referer}">{/if}
            </form>
        </div>
 </div>
index 9ac3c2f97d58ef5d4c598a97eb5879c0aebbe7a3..6c4f9421e7c64c46f0f0edbe3bf6ec8a5393c94a 100644 (file)
@@ -5,11 +5,11 @@
 <div id="pageheader">
        {include="page.header"}
        <div id="uploaddiv">
-       Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...) (Max: {$maxfilesize|htmlspecialchars} bytes).
+       Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...) (Max: {$maxfilesize} bytes).
        <form method="POST" action="?do=upload" enctype="multipart/form-data" name="uploadform" id="uploadform">
            <input type="hidden" name="token" value="{$token}">
            <input type="file" name="filetoupload">
-           <input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize|htmlspecialchars}">
+           <input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize}">
            <input type="submit" name="import_file" value="Import" class="bigbutton"><br>
            <input type="checkbox" name="private" id="private"><label for="private">&nbsp;Import all links as private</label><br>
            <input type="checkbox" name="overwrite" id="overwrite"><label for="overwrite">&nbsp;Overwrite existing links</label>
index a59a9e510abcc2ae9725a150631a9fcd46bfb5db..daf870603a6484000adf626d419097d1743e2b0e 100644 (file)
@@ -33,7 +33,7 @@
         {if="$search_type=='tags'"}
             <div id="searchcriteria">{$result_count} results for tags <i>
             {loop="search_crits"}
-                <span class="linktag" title="Remove tag"><a href="?removetag={$value|htmlspecialchars}">{$value|htmlspecialchars} <span class="remove">x</span></a></span>
+                <span class="linktag" title="Remove tag"><a href="?removetag={$value}">{$value} <span class="remove">x</span></a></span>
             {/loop}</i></div>
         {/if}
     {/if}
@@ -50,7 +50,7 @@
                         <input type="hidden" name="token" value="{$token}"><input type="hidden" name="delete_link"><input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" class="button_delete" onClick="return confirmDeleteLink();"></form>
                     </div>
                 {/if}
-                <span class="linktitle"><a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
+                <span class="linktitle"><a href="{$redirector}{$value.url}">{$value.title}</a></span>
                 <br>
                 {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if}
                 {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
                     <span class="linkdate" title="Short link here"><a href="?{$value.linkdate|smallHash}">permalink</a> - </span>
                 {/if}
                 {if="$GLOBALS['config']['ARCHIVE_ORG']"}
-                <span class="linkarchive"><a href="https://web.archive.org/web/{$value.url|htmlspecialchars}">archive</a> - </span>
+                <span class="linkarchive"><a href="https://web.archive.org/web/{$value.url}">archive</a> - </span>
                 {/if}
                 <div class="linkqrcode"><a href="http://qrfree.kaywa.com/?l=1&amp;s=8&amp;d={$scripturl|urlencode}%3F{$value.linkdate|smallHash}"
                     onclick="return showQrCode(this);" class="qrcode" data-permalink="{$scripturl}?{$value.linkdate|smallHash}">
                    <img src="images/qrcode.png#" alt="QR-Code" title="{function="strftime('%c', $value.timestamp)"}"></a></div> -
-                <a href="{$value.url|htmlspecialchars}"><span class="linkurl" title="Short link">{$value.url|htmlspecialchars}</span></a><br>
+                <a href="{$value.url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br>
                 {if="$value.tags"}
                     <div class="linktaglist">
-                    {loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value|htmlspecialchars}</a></span> {/loop}
+                    {loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value}</a></span> {/loop}
                     </div>
                 {/if}
             </div>
index 91b948ddbca52fb54e4f74faa11ccb8777893546..678375fda08f70c73270d5e904cd3aef85c0b66b 100644 (file)
@@ -17,7 +17,7 @@
     <input type="checkbox" name="longlastingsession" id="longlastingsession" tabindex="3">
     Stay signed in (Do not check on public computers)</label>
     <input type="hidden" name="token" value="{$token}">
-    {if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl|htmlspecialchars}">{/if}
+    {if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if}
     </form>
 {/if}
     </div>
index 42c621b962cb6b9bd1ef4505eb1fc5b58e18fd6c..8143669d87d6dd503587b1fc324809f1f2142806 100644 (file)
@@ -2,7 +2,7 @@
     <b><a href="https://github.com/shaarli/Shaarli">Shaarli</a></b> - The personal, minimalist, super-fast, no-database delicious clone by the <a href="https://github.com/shaarli/Shaarli">Shaarli</a> community - <a href="doc/Home.html">Help/documentation</a>
 </div>
 {if="$newversion"}
-    <div id="newversion"><span id="version_id">&#x25CF;</span> Shaarli {$newversion|htmlspecialchars} is <a href="https://github.com/shaarli/Shaarli/releases">available</a>.</div>
+    <div id="newversion"><span id="version_id">&#x25CF;</span> Shaarli {$newversion} is <a href="https://github.com/shaarli/Shaarli/releases">available</a>.</div>
 {/if}
 {if="isLoggedIn()"}
 <script>function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script>
index 0fd65e401271d5f09d0d2a6243d3851444c2c1bb..2d186aa25a06fe2a5a367aa79d4582042ef15c14 100644 (file)
@@ -8,7 +8,7 @@
 <div id="menu">
   <ul>
       <li><span id="shaarli_title">
-        <a href="{$titleLink}">{$shaarlititle|htmlspecialchars}</a>
+        <a href="{$titleLink}">{$shaarlititle}</a>
     </span>
     </li>
   
index e686afe18a806272aea673dbf41c1eeb4ee28247..9a2a47154b9103efe5f03db5bec34a6ab7fec3aa 100644 (file)
@@ -9,7 +9,7 @@
         <div id="picwall_container">
             {loop="linksToDisplay"}
             <div class="picwall_pictureframe">
-                   {$value.thumbnail}<a href="{$value.url}"><span class="info">{$value.title|htmlspecialchars}</span></a>
+                   {$value.thumbnail}<a href="{$value.url}"><span class="info">{$value.title}</span></a>
             </div>
             {/loop}
         </div>
index 97205e2b07f743b760ae11668ea553022f9f5cae..092f229413ed32a610b908005204f74702fdd3b5 100644 (file)
@@ -6,7 +6,7 @@
 <div class="center">
     <div id="cloudtag">
         {loop="tags"}
-        <span class="count">{$value.count}</span><a href="?searchtags={$key|urlencode}" style="font-size:{$value.size}pt;">{$key|htmlspecialchars}</a>
+        <span class="count">{$value.count}</span><a href="?searchtags={$key|urlencode}" style="font-size:{$value.size}pt;">{$key}</a>
         {/loop}
     </div>
 </div>