From: Arthur Date: Sun, 28 Feb 2016 13:26:46 +0000 (+0100) Subject: Merge pull request #496 from ArthurHoaro/cross-search X-Git-Tag: v0.6.4~2 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=c6744a9e89b62ba94563c43ab33f964ec0b11a17;hp=c51fae92dc7d3080def81a2797e0d683b3e6d82a;p=github%2Fshaarli%2FShaarli.git Merge pull request #496 from ArthurHoaro/cross-search Allow crossed search between terms and tags --- diff --git a/application/Utils.php b/application/Utils.php index 10d60698..3d819716 100644 --- a/application/Utils.php +++ b/application/Utils.php @@ -62,13 +62,29 @@ function endsWith($haystack, $needle, $case=true) } /** - * htmlspecialchars wrapper + * Htmlspecialchars wrapper + * + * @param string $str the string to escape. + * + * @return string escaped. */ function escape($str) { return htmlspecialchars($str, ENT_COMPAT, 'UTF-8', false); } +/** + * Reverse the escape function. + * + * @param string $str the string to unescape. + * + * @return string unescaped string. + */ +function unescape($str) +{ + return htmlspecialchars_decode($str); +} + /** * Link sanitization before templating */ @@ -213,3 +229,28 @@ function space2nbsp($text) function format_description($description, $redirector) { return nl2br(space2nbsp(text2clickable($description, $redirector))); } + +/** + * Sniff browser language to set the locale automatically. + * Note that is may not work on your server if the corresponding locale is not installed. + * + * @param string $headerLocale Locale send in HTTP headers (e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"). + **/ +function autoLocale($headerLocale) +{ + // Default if browser does not send HTTP_ACCEPT_LANGUAGE + $attempts = array('en_US'); + if (isset($headerLocale)) { + // (It's a bit crude, but it works very well. Preferred language is always presented first.) + if (preg_match('/([a-z]{2})-?([a-z]{2})?/i', $headerLocale, $matches)) { + $loc = $matches[1] . (!empty($matches[2]) ? '_' . strtoupper($matches[2]) : ''); + $attempts = array( + $loc.'.UTF-8', $loc, str_replace('_', '-', $loc).'.UTF-8', str_replace('_', '-', $loc), + $loc . '_' . strtoupper($loc).'.UTF-8', $loc . '_' . strtoupper($loc), + $loc . '_' . $loc.'.UTF-8', $loc . '_' . $loc, $loc . '-' . strtoupper($loc).'.UTF-8', + $loc . '-' . strtoupper($loc), $loc . '-' . $loc.'.UTF-8', $loc . '-' . $loc + ); + } + } + setlocale(LC_ALL, $attempts); +} \ No newline at end of file diff --git a/inc/shaarli.css b/inc/shaarli.css index 2e41988e..7a9d9afb 100644 --- a/inc/shaarli.css +++ b/inc/shaarli.css @@ -1151,6 +1151,10 @@ ul.errors { margin: 10px 0; } +#pluginsadmin label { + cursor: pointer; +} + #pluginsadmin .plugin_parameter { padding: 5px 0; border-width: 1px 0; diff --git a/index.php b/index.php index c2bec1db..6712f90e 100644 --- a/index.php +++ b/index.php @@ -268,7 +268,7 @@ $GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redir // 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'])); -autoLocale(); // Sniff browser language and set date format accordingly. +autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']); // Sniff browser language and set date format accordingly. header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. //================================================================================================== @@ -315,26 +315,6 @@ function setup_login_state() { } $userIsLoggedIn = setup_login_state(); - -// ------------------------------------------------------------------------------------------ -// Sniff browser language to display dates in the right format automatically. -// (Note that is may not work on your server if the corresponding local is not installed.) -function autoLocale() -{ - $attempts = array('en_US'); // Default if browser does not send HTTP_ACCEPT_LANGUAGE - if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3" - { // (It's a bit crude, but it works very well. Preferred language is always presented first.) - if (preg_match('/([a-z]{2})-?([a-z]{2})?/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) { - $loc = $matches[1] . (!empty($matches[2]) ? '_' . strtoupper($matches[2]) : ''); - $attempts = array($loc.'.UTF-8', $loc, str_replace('_', '-', $loc).'.UTF-8', str_replace('_', '-', $loc), - $loc . '_' . strtoupper($loc).'.UTF-8', $loc . '_' . strtoupper($loc), - $loc . '_' . $loc.'.UTF-8', $loc . '_' . $loc, $loc . '-' . strtoupper($loc).'.UTF-8', - $loc . '-' . strtoupper($loc), $loc . '-' . $loc.'.UTF-8', $loc . '-' . $loc); - } - } - setlocale(LC_TIME, $attempts); // LC_TIME = Set local for date/time format only. -} - // ------------------------------------------------------------------------------------------ // PubSubHubbub protocol support (if enabled) [UNTESTED] // (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) @@ -1243,11 +1223,12 @@ function renderPage() uksort($tags, function($a, $b) { // Collator is part of PHP intl. if (class_exists('Collator')) { - $c = new Collator(setlocale(LC_ALL, 0)); - return $c->compare($a, $b); - } else { - return strcasecmp($a, $b); + $c = new Collator(setlocale(LC_COLLATE, 0)); + if (!intl_is_failure(intl_get_error_code())) { + return $c->compare($a, $b); + } } + return strcasecmp($a, $b); }); $tagList=array(); diff --git a/plugins/markdown/markdown.php b/plugins/markdown/markdown.php index 3630ef14..a45b6574 100644 --- a/plugins/markdown/markdown.php +++ b/plugins/markdown/markdown.php @@ -117,23 +117,43 @@ function reverse_space2nbsp($description) } /** - * Remove '>' at start of line auto generated by Shaarli core system - * to allow markdown blockquotes. + * Remove dangerous HTML tags (tags, iframe, etc.). + * Doesn't affect content (already escaped by Parsedown). * * @param string $description input description text. * - * @return string $description without HTML links. + * @return string given string escaped. */ -function reset_quote_tags($description) +function sanitize_html($description) { - return preg_replace('/^( *)> /m', '$1> ', $description); + $escapeTags = array( + 'script', + 'style', + 'link', + 'iframe', + 'frameset', + 'frame', + ); + foreach ($escapeTags as $tag) { + $description = preg_replace_callback( + '#<\s*'. $tag .'[^>]*>(.*]*>)?#is', + function ($match) { return escape($match[0]); }, + $description); + } + $description = preg_replace( + '#(<[^>]+)on[a-z]*="[^"]*"#is', + '$1', + $description); + return $description; } /** * Render shaare contents through Markdown parser. * 1. Remove HTML generated by Shaarli core. - * 2. Generate markdown descriptions. - * 3. Wrap description in 'markdown' CSS class. + * 2. Reverse the escape function. + * 3. Generate markdown descriptions. + * 4. Sanitize sensible HTML tags for security. + * 5. Wrap description in 'markdown' CSS class. * * @param string $description input description text. * @@ -147,11 +167,12 @@ function process_markdown($description) $processedDescription = reverse_text2clickable($processedDescription); $processedDescription = reverse_nl2br($processedDescription); $processedDescription = reverse_space2nbsp($processedDescription); - $processedDescription = reset_quote_tags($processedDescription); + $processedDescription = unescape($processedDescription); $processedDescription = $parsedown ->setMarkupEscaped(false) ->setBreaksEnabled(true) ->text($processedDescription); + $processedDescription = sanitize_html($processedDescription); $processedDescription = '
'. $processedDescription . '
'; return $processedDescription; diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php index 455f5ba7..8e1a128a 100644 --- a/tests/plugins/PluginMarkdownTest.php +++ b/tests/plugins/PluginMarkdownTest.php @@ -100,13 +100,18 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase } /** - * Test reset_quote_tags() + * Test sanitize_html(). */ - function testResetQuoteTags() - { - $text = '> quote1'. PHP_EOL . ' > quote2 ' . PHP_EOL . 'noquote'; - $processedText = escape($text); - $reversedText = reset_quote_tags($processedText); - $this->assertEquals($text, $reversedText); + function testSanitizeHtml() { + $input = '< script src="js.js"/>'; + $input .= '< script attr>alert(\'xss\');'; + $input .= ''; + $output = escape($input); + $input .= 'link'; + $output .= 'link'; + $this->assertEquals($output, sanitize_html($input)); + // Do not touch escaped HTML. + $input = escape($input); + $this->assertEquals($input, sanitize_html($input)); } } diff --git a/tpl/pluginsadmin.html b/tpl/pluginsadmin.html index 4f7d091e..5ddcf061 100644 --- a/tpl/pluginsadmin.html +++ b/tpl/pluginsadmin.html @@ -36,7 +36,7 @@ {loop="$enabledPlugins"} - + @@ -48,8 +48,8 @@ - {$key} - {$value.description} + + {/loop} @@ -73,9 +73,9 @@ {loop="$disabledPlugins"} - - {$key} - {$value.description} + + + {/loop} @@ -99,7 +99,7 @@ {loop="$enabledPlugins"} {if="count($value.parameters) > 0"}
-

{$key}

+

{function="str_replace('_', ' ', $key)"}

{loop="$value.parameters"}
@@ -128,4 +128,4 @@ - \ No newline at end of file +