You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by mb...@apache.org on 2021/08/08 21:52:15 UTC

[roller] 01/03: Added EscapeSourceCodePlugin, a WeblogEntryPlugin to escape angle brackes from code within pre tags.

This is an automated email from the ASF dual-hosted git repository.

mbien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/roller.git

commit 09489e6c3630fac21ff6b40c8195eecca2de1b78
Author: Michael Bien <mb...@gmail.com>
AuthorDate: Sun Jul 11 09:04:29 2021 +0200

    Added EscapeSourceCodePlugin, a WeblogEntryPlugin to escape angle brackes from code within pre tags.
---
 .../plugins/entry/EscapeSourceCodePlugin.java      |  88 ++++++++++++
 .../roller/weblogger/config/roller.properties      |   3 +-
 .../plugins/entry/EscapeSourceCodePluginTest.java  | 157 +++++++++++++++++++++
 3 files changed, 247 insertions(+), 1 deletion(-)

diff --git a/app/src/main/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePlugin.java b/app/src/main/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePlugin.java
new file mode 100644
index 0000000..845b08e
--- /dev/null
+++ b/app/src/main/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePlugin.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.business.plugins.entry;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.pojos.Weblog;
+import org.apache.roller.weblogger.pojos.WeblogEntry;
+
+
+import static java.util.regex.Pattern.*;
+
+/**
+ * Escapes angle brackets inside pre tags (code tags which follow right after pre are not escaped).
+ */
+public class EscapeSourceCodePlugin implements WeblogEntryPlugin {
+    
+    private static final String LT = "&lt;"; // '<'
+
+    private static final Pattern PRE_PATTERN = Pattern.compile(
+            "<pre\\s*[^>]*>" + "(.*?)" + "</pre\\s*>", MULTILINE | DOTALL | CASE_INSENSITIVE);
+    
+    private static final Pattern CODE_PATTERN = Pattern.compile(
+            "<code\\s*.[^>]*>" + "(.*?)" + "</code\\s*>", MULTILINE | DOTALL | CASE_INSENSITIVE);
+    
+    @Override
+    public String getName() {
+        return "Sourcecode Escaper";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Escapes angle brackets inside pre tags, code tags are retained.";
+    }
+
+    @Override
+    public void init(Weblog weblog) throws WebloggerException {}
+
+    @Override
+    public String render(WeblogEntry entry, String str) {
+        
+        StringBuilder result = new StringBuilder(str.length()+32);
+        
+        Matcher pre_matcher = PRE_PATTERN.matcher(str);
+        
+        while(pre_matcher.find()) {
+            
+            String pre_full = pre_matcher.group(0);
+            String pre_inner = pre_matcher.group(1);
+            
+            Matcher code_matcher = CODE_PATTERN.matcher(pre_inner);
+            
+            if (code_matcher.find()) {
+                String code_inner = code_matcher.group(1);
+                pre_matcher.appendReplacement(result, pre_full.replace(code_inner, escape(code_inner)));
+            } else {
+                pre_matcher.appendReplacement(result, pre_full.replace(pre_inner, escape(pre_inner)));
+            }
+            
+        }
+        pre_matcher.appendTail(result);
+        
+        return result.toString();
+    }
+
+    // we only have to escape the opening angle bracket for valid html/xhtml
+    private static String escape(String code_inner) {
+        return code_inner.replace("<", LT);
+    }
+
+}
diff --git a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
index c82086b..af29d08 100644
--- a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
+++ b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
@@ -548,7 +548,8 @@ guice.backend.module=org.apache.roller.weblogger.business.jpa.JPAWebloggerModule
 plugins.page=\
 org.apache.roller.weblogger.business.plugins.entry.ConvertLineBreaksPlugin \
 ,org.apache.roller.weblogger.business.plugins.entry.ObfuscateEmailPlugin \
-,org.apache.roller.weblogger.business.plugins.entry.SmileysPlugin
+,org.apache.roller.weblogger.business.plugins.entry.SmileysPlugin\
+,org.apache.roller.weblogger.business.plugins.entry.EscapeSourceCodePlugin
 
 
 # The list of configured WeblogEntryEditors available to users
diff --git a/app/src/test/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePluginTest.java b/app/src/test/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePluginTest.java
new file mode 100644
index 0000000..ff7b585
--- /dev/null
+++ b/app/src/test/java/org/apache/roller/weblogger/business/plugins/entry/EscapeSourceCodePluginTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.business.plugins.entry;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author mbien
+ */
+public class EscapeSourceCodePluginTest {
+    
+    @Test
+    public void passthrough() {
+
+        EscapeSourceCodePlugin instance = new EscapeSourceCodePlugin();
+        
+        String input = "Stay a while and listen.";
+        assertEquals(input, instance.render(null, input));
+        
+        input = "<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "    <p>Hello There</p>\n" +
+                "  </body>\n" +
+                "</html>";
+        assertEquals(input, instance.render(null, input));
+        
+        input = "<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "    <pre>Hello There</pre>\n" + // pre
+                "    <code>Hello There</code>\n" + // code
+                "  </body>\n" +
+                "</html>";
+        assertEquals(input, instance.render(null, input));
+        
+    }
+
+    @Test
+    public void substitution1() {
+
+        EscapeSourceCodePlugin instance = new EscapeSourceCodePlugin();
+        
+        String input = "<pre><></pre>";
+        String expected = "<pre>&lt;></pre>";
+        
+        assertEquals(expected, instance.render(null, input));
+        
+    }
+    
+    @Test
+    public void substitution2() {
+
+        EscapeSourceCodePlugin instance = new EscapeSourceCodePlugin();
+        
+        String input = "\n<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "      <pre><code class='language-java'>private final Map<String, List<?>> map = new HashMap<>();</code></pre>\n"+
+                "  </body>\n" +
+                "</html>";
+        
+        String expected = "\n<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "      <pre><code class='language-java'>private final Map&lt;String, List&lt;?>> map = new HashMap&lt;>();</code></pre>\n"+
+                "  </body>\n" +
+                "</html>";
+        assertEquals(expected, instance.render(null, input));
+        
+    }
+    
+    @Test
+    public void substitution3() {
+
+        EscapeSourceCodePlugin instance = new EscapeSourceCodePlugin();
+        
+        String input = "<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "      <h3>some java</h3>\n" +
+                "      <pre>\n" +
+                "          <code class='language-java'>\n"+
+                "              private final Map<String, List<?>> map = new HashMap<>();\n"+
+                "          </code>\n" +
+                "      </pre>\n" +
+                "      <h3>some xml</h3>\n" +
+                "      <pre>\n" +
+                "          <code class='language-xml'>\n"+
+                "              <foo id = '5'>\n"+
+                "                  <bar>asdf</bar>\n"+
+                "              </foo>\n"+
+                "          </code>\n" +
+                "      </pre>\n" +
+                "  </body>\n" +
+                "</html>";
+        
+        String expected = "<!DOCTYPE html>\n" +
+                "<html>\n" +
+                "  <head>\n" +
+                "    <title>Hi!</title>\n" +
+                "  </head>\n" +
+                "  <body>\n" +
+                "      <h3>some java</h3>\n" +
+                "      <pre>\n" +
+                "          <code class='language-java'>\n"+
+                "              private final Map&lt;String, List&lt;?>> map = new HashMap&lt;>();\n"+
+                "          </code>\n" +
+                "      </pre>\n" +
+                "      <h3>some xml</h3>\n" +
+                "      <pre>\n" +
+                "          <code class='language-xml'>\n"+
+                "              &lt;foo id = '5'>\n"+
+                "                  &lt;bar>asdf&lt;/bar>\n"+
+                "              &lt;/foo>\n"+
+                "          </code>\n" +
+                "      </pre>\n" +
+                "  </body>\n" +
+                "</html>";
+        assertEquals(expected, instance.render(null, input));
+        
+    }
+    
+}