/**
* Parse linklist descriptions.
*
- * @param array $data linklist data.
+ * @param array $data linklist data.
+ * @param ConfigManager $conf instance.
*
* @return mixed linklist data parsed in markdown (and converted to HTML).
*/
-function hook_markdown_render_linklist($data)
+function hook_markdown_render_linklist($data, $conf)
{
foreach ($data['links'] as &$value) {
if (!empty($value['tags']) && noMarkdownTag($value['tags'])) {
$value = stripNoMarkdownTag($value);
continue;
}
- $value['description'] = process_markdown($value['description']);
+ $value['description'] = process_markdown(
+ $value['description'],
+ $conf->get('security.markdown_escape', true),
+ $conf->get('security.allowed_protocols')
+ );
}
return $data;
}
* Parse feed linklist descriptions.
*
* @param array $data linklist data.
+ * @param ConfigManager $conf instance.
*
* @return mixed linklist data parsed in markdown (and converted to HTML).
*/
-function hook_markdown_render_feed($data)
+function hook_markdown_render_feed($data, $conf)
{
foreach ($data['links'] as &$value) {
if (!empty($value['tags']) && noMarkdownTag($value['tags'])) {
$value = stripNoMarkdownTag($value);
continue;
}
- $value['description'] = process_markdown($value['description']);
+ $value['description'] = process_markdown(
+ $value['description'],
+ $conf->get('security.markdown_escape', true),
+ $conf->get('security.allowed_protocols')
+ );
}
return $data;
/**
* Parse daily descriptions.
*
- * @param array $data daily data.
+ * @param array $data daily data.
+ * @param ConfigManager $conf instance.
*
* @return mixed daily data parsed in markdown (and converted to HTML).
*/
-function hook_markdown_render_daily($data)
+function hook_markdown_render_daily($data, $conf)
{
// Manipulate columns data
foreach ($data['cols'] as &$value) {
$value2 = stripNoMarkdownTag($value2);
continue;
}
- $value2['formatedDescription'] = process_markdown($value2['formatedDescription']);
+ $value2['formatedDescription'] = process_markdown(
+ $value2['formatedDescription'],
+ $conf->get('security.markdown_escape', true),
+ $conf->get('security.allowed_protocols')
+ );
}
}
function hook_markdown_render_editlink($data)
{
// Load help HTML into a string
- $data['edit_link_plugin'][] = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html');
-
+ $txt = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html');
+ $translations = [
+ t('Description will be rendered with'),
+ t('Markdown syntax documentation'),
+ t('Markdown syntax'),
+ ];
+ $data['edit_link_plugin'][] = vsprintf($txt, $translations);
// Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion.
if (! in_array(NO_MD_TAG, $data['tags'])) {
$data['tags'][NO_MD_TAG] = 0;
return preg_replace('/(^| ) /m', '$1 ', $description);
}
+/**
+ * Replace not whitelisted protocols with http:// in given description.
+ *
+ * @param string $description input description text.
+ * @param array $allowedProtocols list of allowed protocols.
+ *
+ * @return string $description without malicious link.
+ */
+function filter_protocols($description, $allowedProtocols)
+{
+ return preg_replace_callback(
+ '#]\((.*?)\)#is',
+ function ($match) use ($allowedProtocols) {
+ return ']('. whitelist_protocols($match[1], $allowedProtocols) .')';
+ },
+ $description
+ );
+}
+
/**
* Remove dangerous HTML tags (tags, iframe, etc.).
* Doesn't affect <code> content (already escaped by Parsedown).
$description);
}
$description = preg_replace(
- '#(<[^>]+)on[a-z]*="[^"]*"#is',
+ '#(<[^>]+)on[a-z]*="?[^ "]*"?#is',
'$1',
$description);
return $description;
* 5. Wrap description in 'markdown' CSS class.
*
* @param string $description input description text.
+ * @param bool $escape escape HTML entities
*
* @return string HTML processed $description.
*/
-function process_markdown($description)
+function process_markdown($description, $escape = true, $allowedProtocols = [])
{
$parsedown = new Parsedown();
$processedDescription = reverse_nl2br($processedDescription);
$processedDescription = reverse_space2nbsp($processedDescription);
$processedDescription = reverse_text2clickable($processedDescription);
+ $processedDescription = filter_protocols($processedDescription, $allowedProtocols);
$processedDescription = unescape($processedDescription);
$processedDescription = $parsedown
- ->setMarkupEscaped(false)
+ ->setMarkupEscaped($escape)
->setBreaksEnabled(true)
->text($processedDescription);
$processedDescription = sanitize_html($processedDescription);
return $processedDescription;
}
+
+/**
+ * This function is never called, but contains translation calls for GNU gettext extraction.
+ */
+function markdown_dummy_translation()
+{
+ // meta
+ t('Render shaare description with Markdown syntax.<br><strong>Warning</strong>:
+If your shaared descriptions contained HTML tags before enabling the markdown plugin,
+enabling it might break your page.
+See the <a href="https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering">README</a>.');
+}