From 661e6a6d01c1d760d1ee5192b3ba521d9cc568c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= <johannes@kyriasis.com>
Date: Mon, 12 Jun 2017 02:03:38 +0200
Subject: [PATCH 1/2] HtmlUtils: Allow language- classes on code blocks through
 the sanitizer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is required to be able to specify the highlight language in fenced
blocks like the following:

    ```python
    print("foo")
    ```

Signed-off-by: Johannes Löthberg <johannes@kyriasis.com>
---
 src/HtmlUtils.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js
index aec32092ed..a32d05e4ff 100644
--- a/src/HtmlUtils.js
+++ b/src/HtmlUtils.js
@@ -124,6 +124,7 @@ var sanitizeHtmlParams = {
         // would make sense if we did
         img: ['src'],
         ol: ['start'],
+        code: ['class'], // We don't actually allow all classes, we filter them in transformTags
     },
     // Lots of these won't come up by default because we don't allow them
     selfClosing: ['img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta'],
@@ -165,6 +166,19 @@ var sanitizeHtmlParams = {
             attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
             return { tagName: tagName, attribs : attribs };
         },
+        'code': function(tagName, attribs) {
+            if (typeof attribs.class !== 'undefined') {
+                // Filter out all classes other than ones starting with language- for syntax highlighting.
+                let classes = attribs.class.split(/\s+/).filter(function(cl) {
+                    return cl.startsWith('language-');
+                });
+                attribs.class = classes.join(' ');
+            }
+            return {
+                tagName: tagName,
+                attribs: attribs,
+            };
+        },
         '*': function(tagName, attribs) {
             // Delete any style previously assigned, style is an allowedTag for font and span
             // because attributes are stripped after transforming

From 48c32172fd10d9fc2109cde4013300e420cbc0e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= <johannes@kyriasis.com>
Date: Mon, 12 Jun 2017 02:13:10 +0200
Subject: [PATCH 2/2] TextualBody: only highlight code block if language was
 specified
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The highlight.js autodetection is finicky and often wrong, so disable
highlighting unless the language was explicitly specified, or if the
user has explicitly enabled it in the settings.

Fixes vector-im/riot-web#508.

Signed-off-by: Johannes Löthberg <johannes@kyriasis.com>
---
 src/components/structures/UserSettings.js    |  4 ++++
 src/components/views/messages/TextualBody.js | 14 +++++++++++++-
 src/i18n/strings/en_EN.json                  |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js
index ef574d2ed6..bfbb9831b0 100644
--- a/src/components/structures/UserSettings.js
+++ b/src/components/structures/UserSettings.js
@@ -93,6 +93,10 @@ const SETTINGS_LABELS = [
         id: 'disableMarkdown',
         label: 'Disable markdown formatting',
     },
+    {
+        id: 'enableSyntaxHighlightLanguageDetection',
+        label: 'Enable automatic language detection for syntax highlighting',
+    },
 /*
     {
         id: 'useFixedWidthFont',
diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js
index d5a1977cdd..190b1341c3 100644
--- a/src/components/views/messages/TextualBody.js
+++ b/src/components/views/messages/TextualBody.js
@@ -29,6 +29,7 @@ import Modal from '../../../Modal';
 import SdkConfig from '../../../SdkConfig';
 import dis from '../../../dispatcher';
 import { _t } from '../../../languageHandler';
+import UserSettingsStore from "../../../UserSettingsStore";
 
 linkifyMatrix(linkify);
 
@@ -90,7 +91,18 @@ module.exports = React.createClass({
                 setTimeout(() => {
                     if (this._unmounted) return;
                     for (let i = 0; i < blocks.length; i++) {
-                        highlight.highlightBlock(blocks[i]);
+                        if (UserSettingsStore.getSyncedSetting("enableSyntaxHighlightLanguageDetection", false)) {
+                            highlight.highlightBlock(blocks[i])
+                        } else {
+                            // Only syntax highlight if there's a class starting with language-
+                            let classes = blocks[i].className.split(/\s+/).filter(function (cl) {
+                                return cl.startsWith('language-');
+                            });
+
+                            if (classes.length != 0) {
+                                highlight.highlightBlock(blocks[i]);
+                            }
+                        }
                     }
                 }, 10);
             }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 59853b6e93..6cf2c63785 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -268,6 +268,7 @@
   "Email address (optional)": "Email address (optional)",
   "Email, name or matrix ID": "Email, name or matrix ID",
   "Emoji": "Emoji",
+  "Enable automatic language detection for syntax highlighting": "Enable automatic language detection for syntax highlighting",
   "Enable encryption": "Enable encryption",
   "Enable Notifications": "Enable Notifications",
   "enabled": "enabled",