diff options
author | ArthurHoaro <arthur@hoa.ro> | 2015-06-11 13:53:27 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2015-06-23 16:35:36 +0200 |
commit | 5f85fcd863fe261921953ea3bd1742f3e1b7cf68 (patch) | |
tree | 5615922c1c696ec04cc60625a8d401b2b297a462 /index.php | |
parent | 0923a2bc1b097bf1def882722db489d83d95c423 (diff) | |
download | Shaarli-5f85fcd863fe261921953ea3bd1742f3e1b7cf68.tar.gz Shaarli-5f85fcd863fe261921953ea3bd1742f3e1b7cf68.tar.zst Shaarli-5f85fcd863fe261921953ea3bd1742f3e1b7cf68.zip |
Working on shaarli/Shaarli#224
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.
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 159 |
1 files changed, 86 insertions, 73 deletions
@@ -98,7 +98,7 @@ header("Pragma: no-cache"); | |||
98 | if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>'); | 98 | if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>'); |
99 | 99 | ||
100 | // Handling of old config file which do not have the new parameters. | 100 | // Handling of old config file which do not have the new parameters. |
101 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); | 101 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(indexUrl()); |
102 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); | 102 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); |
103 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; | 103 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; |
104 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; | 104 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; |
@@ -111,6 +111,9 @@ if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; | |||
111 | if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); | 111 | if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); |
112 | 112 | ||
113 | require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. | 113 | require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. |
114 | $GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : ''; | ||
115 | $GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : ''; | ||
116 | $GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : ''; | ||
114 | 117 | ||
115 | // a token depending of deployment salt, user password, and the current ip | 118 | // a token depending of deployment salt, user password, and the current ip |
116 | define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); | 119 | define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); |
@@ -272,6 +275,17 @@ function nl2br_escaped($html) | |||
272 | return str_replace('>','>',str_replace('<','<',nl2br($html))); | 275 | return str_replace('>','>',str_replace('<','<',nl2br($html))); |
273 | } | 276 | } |
274 | 277 | ||
278 | function escape($str) { | ||
279 | return htmlspecialchars($str, ENT_COMPAT, 'UTF-8', false); | ||
280 | } | ||
281 | |||
282 | function sanitizeLink(&$link) { | ||
283 | $link['url'] = escape($link['url']); // useful? | ||
284 | $link['title'] = escape($link['title']); | ||
285 | $link['description'] = escape($link['description']); | ||
286 | $link['tags'] = escape($link['tags']); | ||
287 | } | ||
288 | |||
275 | // In a string, converts URLs to clickable links. | 289 | // In a string, converts URLs to clickable links. |
276 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 | 290 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 |
277 | function text2clickable($url) | 291 | function text2clickable($url) |
@@ -651,8 +665,8 @@ class pageBuilder | |||
651 | private function initialize() | 665 | private function initialize() |
652 | { | 666 | { |
653 | $this->tpl = new RainTPL; | 667 | $this->tpl = new RainTPL; |
654 | $this->tpl->assign('newversion',checkUpdate()); | 668 | $this->tpl->assign('newversion',escape(checkUpdate())); |
655 | $this->tpl->assign('feedurl',htmlspecialchars(indexUrl())); | 669 | $this->tpl->assign('feedurl',escape(indexUrl())); |
656 | $searchcrits=''; // Search criteria | 670 | $searchcrits=''; // Search criteria |
657 | if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']); | 671 | if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']); |
658 | elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']); | 672 | elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']); |
@@ -716,15 +730,15 @@ function showRSS() | |||
716 | $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; | 730 | $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; |
717 | } | 731 | } |
718 | 732 | ||
719 | $pageaddr=htmlspecialchars(indexUrl()); | 733 | $pageaddr=escape(indexUrl()); |
720 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">'; | 734 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">'; |
721 | echo '<channel><title>'.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>'; | 735 | echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>'; |
722 | echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n"; | 736 | echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n"; |
723 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | 737 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) |
724 | { | 738 | { |
725 | echo '<!-- PubSubHubbub Discovery -->'; | 739 | echo '<!-- PubSubHubbub Discovery -->'; |
726 | echo '<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />'; | 740 | echo '<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />'; |
727 | echo '<link rel="self" href="'.htmlspecialchars($pageaddr).'?do=rss" xmlns="http://www.w3.org/2005/Atom" />'; | 741 | echo '<link rel="self" href="'.$pageaddr.'?do=rss" xmlns="http://www.w3.org/2005/Atom" />'; |
728 | echo '<!-- End Of PubSubHubbub Discovery -->'; | 742 | echo '<!-- End Of PubSubHubbub Discovery -->'; |
729 | } | 743 | } |
730 | $i=0; | 744 | $i=0; |
@@ -734,16 +748,16 @@ function showRSS() | |||
734 | $link = $linksToDisplay[$keys[$i]]; | 748 | $link = $linksToDisplay[$keys[$i]]; |
735 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); | 749 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); |
736 | $rfc822date = linkdate2rfc822($link['linkdate']); | 750 | $rfc822date = linkdate2rfc822($link['linkdate']); |
737 | $absurl = htmlspecialchars($link['url']); | 751 | $absurl = $link['url']; |
738 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute | 752 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute |
739 | if ($usepermalinks===true) | 753 | if ($usepermalinks===true) |
740 | echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>'; | 754 | echo '<item><title>'.$link['title'].'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>'; |
741 | else | 755 | else |
742 | echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>'; | 756 | echo '<item><title>'.$link['title'].'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>'; |
743 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>\n"; | 757 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.escape($rfc822date)."</pubDate>\n"; |
744 | if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification) | 758 | if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification) |
745 | { | 759 | { |
746 | foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.htmlspecialchars($pageaddr).'">'.htmlspecialchars($tag).'</category>'."\n"; } | 760 | foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.$pageaddr.'">'.$tag.'</category>'."\n"; } |
747 | } | 761 | } |
748 | 762 | ||
749 | // Add permalink in description | 763 | // Add permalink in description |
@@ -751,10 +765,10 @@ function showRSS() | |||
751 | // If user wants permalinks first, put the final link in description | 765 | // If user wants permalinks first, put the final link in description |
752 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; | 766 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; |
753 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | 767 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; |
754 | echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$descriptionlink.']]></description>'."\n</item>\n"; | 768 | echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink.']]></description>'."\n</item>\n"; |
755 | $i++; | 769 | $i++; |
756 | } | 770 | } |
757 | echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; | 771 | echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->'; |
758 | 772 | ||
759 | $cache->cache(ob_get_contents()); | 773 | $cache->cache(ob_get_contents()); |
760 | ob_end_flush(); | 774 | ob_end_flush(); |
@@ -779,7 +793,6 @@ function showATOM() | |||
779 | 793 | ||
780 | $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). | 794 | $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). |
781 | 795 | ||
782 | |||
783 | // Optionally filter the results: | 796 | // Optionally filter the results: |
784 | $linksToDisplay=array(); | 797 | $linksToDisplay=array(); |
785 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); | 798 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); |
@@ -792,7 +805,7 @@ function showATOM() | |||
792 | $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; | 805 | $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; |
793 | } | 806 | } |
794 | 807 | ||
795 | $pageaddr=htmlspecialchars(indexUrl()); | 808 | $pageaddr=escape(indexUrl()); |
796 | $latestDate = ''; | 809 | $latestDate = ''; |
797 | $entries=''; | 810 | $entries=''; |
798 | $i=0; | 811 | $i=0; |
@@ -803,44 +816,44 @@ function showATOM() | |||
803 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); | 816 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); |
804 | $iso8601date = linkdate2iso8601($link['linkdate']); | 817 | $iso8601date = linkdate2iso8601($link['linkdate']); |
805 | $latestDate = max($latestDate,$iso8601date); | 818 | $latestDate = max($latestDate,$iso8601date); |
806 | $absurl = htmlspecialchars($link['url']); | 819 | $absurl = $link['url']; |
807 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute | 820 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute |
808 | $entries.='<entry><title>'.htmlspecialchars($link['title']).'</title>'; | 821 | $entries.='<entry><title>'.$link['title'].'</title>'; |
809 | if ($usepermalinks===true) | 822 | if ($usepermalinks===true) |
810 | $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>'; | 823 | $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>'; |
811 | else | 824 | else |
812 | $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>'; | 825 | $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>'; |
813 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.htmlspecialchars($iso8601date).'</updated>'; | 826 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.escape($iso8601date).'</updated>'; |
814 | 827 | ||
815 | // Add permalink in description | 828 | // Add permalink in description |
816 | $descriptionlink = htmlspecialchars('(<a href="'.$guid.'">Permalink</a>)'); | 829 | $descriptionlink = '(<a href="'.$guid.'">Permalink</a>)'; |
817 | // If user wants permalinks first, put the final link in description | 830 | // If user wants permalinks first, put the final link in description |
818 | if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(<a href="'.$absurl.'">Link</a>)'); | 831 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; |
819 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | 832 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; |
820 | 833 | ||
821 | $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."</content>\n"; | 834 | $entries.='<content type="html"><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink."]]></content>\n"; |
822 | if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) | 835 | if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) |
823 | { | 836 | { |
824 | foreach(explode(' ',$link['tags']) as $tag) | 837 | foreach(explode(' ',$link['tags']) as $tag) |
825 | { $entries.='<category scheme="'.htmlspecialchars($pageaddr,ENT_QUOTES).'" term="'.htmlspecialchars($tag,ENT_QUOTES).'" />'."\n"; } | 838 | { $entries.='<category scheme="'.$pageaddr.'" term="'.$tag.'" />'."\n"; } |
826 | } | 839 | } |
827 | $entries.="</entry>\n"; | 840 | $entries.="</entry>\n"; |
828 | $i++; | 841 | $i++; |
829 | } | 842 | } |
830 | $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; | 843 | $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; |
831 | $feed.='<title>'.htmlspecialchars($GLOBALS['title']).'</title>'; | 844 | $feed.='<title>'.$GLOBALS['title'].'</title>'; |
832 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.htmlspecialchars($latestDate).'</updated>'; | 845 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.escape($latestDate).'</updated>'; |
833 | $feed.='<link rel="self" href="'.htmlspecialchars(serverUrl().$_SERVER["REQUEST_URI"]).'" />'; | 846 | $feed.='<link rel="self" href="'.escape(serverUrl().$_SERVER["REQUEST_URI"]).'" />'; |
834 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | 847 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) |
835 | { | 848 | { |
836 | $feed.='<!-- PubSubHubbub Discovery -->'; | 849 | $feed.='<!-- PubSubHubbub Discovery -->'; |
837 | $feed.='<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" />'; | 850 | $feed.='<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" />'; |
838 | $feed.='<!-- End Of PubSubHubbub Discovery -->'; | 851 | $feed.='<!-- End Of PubSubHubbub Discovery -->'; |
839 | } | 852 | } |
840 | $feed.='<author><name>'.htmlspecialchars($pageaddr).'</name><uri>'.htmlspecialchars($pageaddr).'</uri></author>'; | 853 | $feed.='<author><name>'.$pageaddr.'</name><uri>'.$pageaddr.'</uri></author>'; |
841 | $feed.='<id>'.htmlspecialchars($pageaddr).'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. | 854 | $feed.='<id>'.$pageaddr.'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. |
842 | $feed.=$entries; | 855 | $feed.=$entries; |
843 | $feed.='</feed><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; | 856 | $feed.='</feed><!-- Cached version of '.escape(pageUrl()).' -->'; |
844 | echo $feed; | 857 | echo $feed; |
845 | 858 | ||
846 | $cache->cache(ob_get_contents()); | 859 | $cache->cache(ob_get_contents()); |
@@ -882,18 +895,18 @@ function showDailyRSS() | |||
882 | 895 | ||
883 | // Build the RSS feed. | 896 | // Build the RSS feed. |
884 | header('Content-Type: application/rss+xml; charset=utf-8'); | 897 | header('Content-Type: application/rss+xml; charset=utf-8'); |
885 | $pageaddr=htmlspecialchars(indexUrl()); | 898 | $pageaddr=escape(indexUrl()); |
886 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; | 899 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; |
887 | echo '<channel><title>Daily - '.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>'; | 900 | echo '<channel><title>Daily - '.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>'; |
888 | echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n"; | 901 | echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n"; |
889 | 902 | ||
890 | foreach($days as $day=>$linkdates) // For each day. | 903 | foreach($days as $day=>$linkdates) // For each day. |
891 | { | 904 | { |
892 | $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date | 905 | $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date |
893 | $rfc822date = linkdate2rfc822($day.'_000000'); | 906 | $rfc822date = linkdate2rfc822($day.'_000000'); |
894 | $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. | 907 | $absurl=escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. |
895 | echo '<item><title>'.htmlspecialchars($GLOBALS['title'].' - '.$daydate).'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>'; | 908 | echo '<item><title>'.$GLOBALS['title'].' - '.$daydate.'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>'; |
896 | echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>"; | 909 | echo '<pubDate>'.escape($rfc822date)."</pubDate>"; |
897 | 910 | ||
898 | // Build the HTML body of this RSS entry. | 911 | // Build the HTML body of this RSS entry. |
899 | $html=''; | 912 | $html=''; |
@@ -903,7 +916,7 @@ function showDailyRSS() | |||
903 | foreach($linkdates as $linkdate) | 916 | foreach($linkdates as $linkdate) |
904 | { | 917 | { |
905 | $l = $LINKSDB[$linkdate]; | 918 | $l = $LINKSDB[$linkdate]; |
906 | $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description'])))); | 919 | $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($l['description']))); |
907 | $l['thumbnail'] = thumbnail($l['url']); | 920 | $l['thumbnail'] = thumbnail($l['url']); |
908 | $l['timestamp'] = linkdate2timestamp($l['linkdate']); | 921 | $l['timestamp'] = linkdate2timestamp($l['linkdate']); |
909 | if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute | 922 | if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute |
@@ -917,7 +930,7 @@ function showDailyRSS() | |||
917 | echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n"; | 930 | echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n"; |
918 | 931 | ||
919 | } | 932 | } |
920 | echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; | 933 | echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->'; |
921 | 934 | ||
922 | $cache->cache(ob_get_contents()); | 935 | $cache->cache(ob_get_contents()); |
923 | ob_end_flush(); | 936 | ob_end_flush(); |
@@ -929,7 +942,6 @@ function showDaily() | |||
929 | { | 942 | { |
930 | $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). | 943 | $LINKSDB = new LinkDB(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). |
931 | 944 | ||
932 | |||
933 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 945 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
934 | if (isset($_GET['day'])) $day=$_GET['day']; | 946 | if (isset($_GET['day'])) $day=$_GET['day']; |
935 | 947 | ||
@@ -948,10 +960,11 @@ function showDaily() | |||
948 | // We pre-format some fields for proper output. | 960 | // We pre-format some fields for proper output. |
949 | foreach($linksToDisplay as $key=>$link) | 961 | foreach($linksToDisplay as $key=>$link) |
950 | { | 962 | { |
963 | |||
951 | $taglist = explode(' ',$link['tags']); | 964 | $taglist = explode(' ',$link['tags']); |
952 | uasort($taglist, 'strcasecmp'); | 965 | uasort($taglist, 'strcasecmp'); |
953 | $linksToDisplay[$key]['taglist']=$taglist; | 966 | $linksToDisplay[$key]['taglist']=$taglist; |
954 | $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); | 967 | $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description']))); |
955 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); | 968 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); |
956 | $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); | 969 | $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); |
957 | } | 970 | } |
@@ -1002,7 +1015,7 @@ function renderPage() | |||
1002 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. | 1015 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. |
1003 | $PAGE = new pageBuilder; | 1016 | $PAGE = new pageBuilder; |
1004 | $PAGE->assign('token',$token); | 1017 | $PAGE->assign('token',$token); |
1005 | $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); | 1018 | $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); |
1006 | $PAGE->renderPage('loginform'); | 1019 | $PAGE->renderPage('loginform'); |
1007 | exit; | 1020 | exit; |
1008 | } | 1021 | } |
@@ -1030,7 +1043,7 @@ function renderPage() | |||
1030 | // Get only links which have a thumbnail. | 1043 | // Get only links which have a thumbnail. |
1031 | foreach($links as $link) | 1044 | foreach($links as $link) |
1032 | { | 1045 | { |
1033 | $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); | 1046 | $permalink='?'.escape(smallhash($link['linkdate'])); |
1034 | $thumb=lazyThumbnail($link['url'],$permalink); | 1047 | $thumb=lazyThumbnail($link['url'],$permalink); |
1035 | if ($thumb!='') // Only output links which have a thumbnail. | 1048 | if ($thumb!='') // Only output links which have a thumbnail. |
1036 | { | 1049 | { |
@@ -1239,8 +1252,8 @@ function renderPage() | |||
1239 | $PAGE = new pageBuilder; | 1252 | $PAGE = new pageBuilder; |
1240 | $PAGE->assign('linkcount',count($LINKSDB)); | 1253 | $PAGE->assign('linkcount',count($LINKSDB)); |
1241 | $PAGE->assign('token',getToken()); | 1254 | $PAGE->assign('token',getToken()); |
1242 | $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); | 1255 | $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] ); |
1243 | $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); | 1256 | $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] ); |
1244 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); | 1257 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); |
1245 | $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template? | 1258 | $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template? |
1246 | $PAGE->assign('timezone_js',$timezone_js); | 1259 | $PAGE->assign('timezone_js',$timezone_js); |
@@ -1400,7 +1413,7 @@ function renderPage() | |||
1400 | $PAGE->assign('link',$link); | 1413 | $PAGE->assign('link',$link); |
1401 | $PAGE->assign('link_is_new',false); | 1414 | $PAGE->assign('link_is_new',false); |
1402 | $PAGE->assign('token',getToken()); // XSRF protection. | 1415 | $PAGE->assign('token',getToken()); // XSRF protection. |
1403 | $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); | 1416 | $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : '')); |
1404 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1417 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1405 | $PAGE->renderPage('editlink'); | 1418 | $PAGE->renderPage('editlink'); |
1406 | exit; | 1419 | exit; |
@@ -1524,10 +1537,10 @@ HTML; | |||
1524 | ($exportWhat=='private' && $link['private']!=0) || | 1537 | ($exportWhat=='private' && $link['private']!=0) || |
1525 | ($exportWhat=='public' && $link['private']==0)) | 1538 | ($exportWhat=='public' && $link['private']==0)) |
1526 | { | 1539 | { |
1527 | echo '<DT><A HREF="'.htmlspecialchars($link['url']).'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"'; | 1540 | echo '<DT><A HREF="'.$link['url'].'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"'; |
1528 | if ($link['tags']!='') echo ' TAGS="'.htmlspecialchars(str_replace(' ',',',$link['tags'])).'"'; | 1541 | if ($link['tags']!='') echo ' TAGS="'.str_replace(' ',',',$link['tags']).'"'; |
1529 | echo '>'.htmlspecialchars($link['title'])."</A>\n"; | 1542 | echo '>'.$link['title']."</A>\n"; |
1530 | if ($link['description']!='') echo '<DD>'.htmlspecialchars($link['description'])."\n"; | 1543 | if ($link['description']!='') echo '<DD>'.$link['description']."\n"; |
1531 | } | 1544 | } |
1532 | } | 1545 | } |
1533 | exit; | 1546 | exit; |
@@ -1540,7 +1553,7 @@ HTML; | |||
1540 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) | 1553 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) |
1541 | { | 1554 | { |
1542 | $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); | 1555 | $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); |
1543 | 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>'; | 1556 | 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>'; |
1544 | exit; | 1557 | exit; |
1545 | } | 1558 | } |
1546 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | 1559 | if (!tokenOk($_POST['token'])) die('Wrong token.'); |
@@ -1663,13 +1676,13 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1663 | if (isset($_GET['searchterm'])) // Fulltext search | 1676 | if (isset($_GET['searchterm'])) // Fulltext search |
1664 | { | 1677 | { |
1665 | $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); | 1678 | $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); |
1666 | $search_crits=htmlspecialchars(trim($_GET['searchterm'])); | 1679 | $search_crits=escape(trim($_GET['searchterm'])); |
1667 | $search_type='fulltext'; | 1680 | $search_type='fulltext'; |
1668 | } | 1681 | } |
1669 | elseif (isset($_GET['searchtags'])) // Search by tag | 1682 | elseif (isset($_GET['searchtags'])) // Search by tag |
1670 | { | 1683 | { |
1671 | $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 1684 | $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
1672 | $search_crits=explode(' ',trim($_GET['searchtags'])); | 1685 | $search_crits=explode(' ',escape(trim($_GET['searchtags']))); |
1673 | $search_type='tags'; | 1686 | $search_type='tags'; |
1674 | } | 1687 | } |
1675 | elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL | 1688 | 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) | |||
1721 | while ($i<$end && $i<count($keys)) | 1734 | while ($i<$end && $i<count($keys)) |
1722 | { | 1735 | { |
1723 | $link = $linksToDisplay[$keys[$i]]; | 1736 | $link = $linksToDisplay[$keys[$i]]; |
1724 | $link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); | 1737 | $link['description']=nl2br(keepMultipleSpaces(text2clickable($link['description']))); |
1725 | $title=$link['title']; | 1738 | $title=$link['title']; |
1726 | $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; | 1739 | $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; |
1727 | $link['class'] = ($link['private']==0 ? $classLi : 'private'); | 1740 | $link['class'] = ($link['private']==0 ? $classLi : 'private'); |
@@ -1867,7 +1880,7 @@ function computeThumbnail($url,$href=false) | |||
1867 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | 1880 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. |
1868 | } | 1881 | } |
1869 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1882 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1870 | return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), | 1883 | return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1871 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1884 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1872 | } | 1885 | } |
1873 | 1886 | ||
@@ -1878,7 +1891,7 @@ function computeThumbnail($url,$href=false) | |||
1878 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | 1891 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') |
1879 | { | 1892 | { |
1880 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1893 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1881 | return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), | 1894 | return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1882 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1895 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1883 | } | 1896 | } |
1884 | return array(); // No thumbnail. | 1897 | return array(); // No thumbnail. |
@@ -1897,11 +1910,11 @@ function thumbnail($url,$href=false) | |||
1897 | $t = computeThumbnail($url,$href); | 1910 | $t = computeThumbnail($url,$href); |
1898 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1911 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1899 | 1912 | ||
1900 | $html='<a href="'.htmlspecialchars($t['href']).'"><img src="'.htmlspecialchars($t['src']).'"'; | 1913 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; |
1901 | if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; | 1914 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; |
1902 | if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; | 1915 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; |
1903 | if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; | 1916 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; |
1904 | if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; | 1917 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; |
1905 | $html.='></a>'; | 1918 | $html.='></a>'; |
1906 | return $html; | 1919 | return $html; |
1907 | } | 1920 | } |
@@ -1917,23 +1930,23 @@ function lazyThumbnail($url,$href=false) | |||
1917 | $t = computeThumbnail($url,$href); | 1930 | $t = computeThumbnail($url,$href); |
1918 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1931 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1919 | 1932 | ||
1920 | $html='<a href="'.htmlspecialchars($t['href']).'">'; | 1933 | $html='<a href="'.escape($t['href']).'">'; |
1921 | 1934 | ||
1922 | // Lazy image | 1935 | // Lazy image |
1923 | $html.='<img class="b-lazy" src="#" data-src="'.htmlspecialchars($t['src']).'"'; | 1936 | $html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"'; |
1924 | 1937 | ||
1925 | if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; | 1938 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; |
1926 | if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; | 1939 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; |
1927 | if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; | 1940 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; |
1928 | if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; | 1941 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; |
1929 | $html.='>'; | 1942 | $html.='>'; |
1930 | 1943 | ||
1931 | // No-JavaScript fallback. | 1944 | // No-JavaScript fallback. |
1932 | $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"'; | 1945 | $html.='<noscript><img src="'.escape($t['src']).'"'; |
1933 | if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; | 1946 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; |
1934 | if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; | 1947 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; |
1935 | if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; | 1948 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; |
1936 | if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; | 1949 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; |
1937 | $html.='></noscript></a>'; | 1950 | $html.='></noscript></a>'; |
1938 | 1951 | ||
1939 | return $html; | 1952 | return $html; |
@@ -1983,7 +1996,7 @@ function install() | |||
1983 | $GLOBALS['login'] = $_POST['setlogin']; | 1996 | $GLOBALS['login'] = $_POST['setlogin']; |
1984 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1997 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. |
1985 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1998 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); |
1986 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); | 1999 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] ); |
1987 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 2000 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); |
1988 | writeConfig(); | 2001 | writeConfig(); |
1989 | echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; | 2002 | 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() | |||
2210 | // This is more complex: we have to perform a HTTP request, then parse the result. | 2223 | // This is more complex: we have to perform a HTTP request, then parse the result. |
2211 | // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 | 2224 | // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 |
2212 | $vid = substr(parse_url($url,PHP_URL_PATH),1); | 2225 | $vid = substr(parse_url($url,PHP_URL_PATH),1); |
2213 | list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5); | 2226 | list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.escape($vid).'.php',5); |
2214 | if (strpos($httpstatus,'200 OK')!==false) | 2227 | if (strpos($httpstatus,'200 OK')!==false) |
2215 | { | 2228 | { |
2216 | $t = unserialize($data); | 2229 | $t = unserialize($data); |