Jelajahi Sumber

fix #2837 Removed scriptlet usage in Admin Design page for better code maintainability.

Shinsuke Sugaya 11 bulan lalu
induk
melakukan
e55ecd72fe

+ 19 - 3
src/main/java/org/codelibs/fess/app/web/admin/design/AdminDesignAction.java

@@ -22,6 +22,7 @@ import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
+import java.util.regex.Pattern;
 
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.LogManager;
@@ -47,6 +48,10 @@ import org.lastaflute.web.ruts.process.ActionRuntime;
  */
  */
 public class AdminDesignAction extends FessAdminAction {
 public class AdminDesignAction extends FessAdminAction {
 
 
+    private static final String CACHE_AND_SESSION_INVALIDATE_STATEMENT = "<!--CACHE_AND_SESSION_INVALIDATE-->";
+
+    private static final String TRY_STATEMENT = "<!--TRY-->";
+
     public static final String ROLE = "admin-design";
     public static final String ROLE = "admin-design";
 
 
     private static final Logger logger = LogManager.getLogger(AdminDesignAction.class);
     private static final Logger logger = LogManager.getLogger(AdminDesignAction.class);
@@ -237,7 +242,7 @@ public class AdminDesignAction extends FessAdminAction {
         final String jspType = "view";
         final String jspType = "view";
         final File jspFile = getJspFile(form.fileName, jspType);
         final File jspFile = getJspFile(form.fileName, jspType);
         try {
         try {
-            form.content = new String(FileUtil.readBytes(jspFile), Constants.UTF_8);
+            form.content = encodeJsp(new String(FileUtil.readBytes(jspFile), Constants.UTF_8));
         } catch (final UnsupportedEncodingException e) {
         } catch (final UnsupportedEncodingException e) {
             throw new FessSystemException("Invalid encoding", e);
             throw new FessSystemException("Invalid encoding", e);
         }
         }
@@ -251,7 +256,7 @@ public class AdminDesignAction extends FessAdminAction {
         final String jspType = "orig/view";
         final String jspType = "orig/view";
         final File jspFile = getJspFile(form.fileName, jspType);
         final File jspFile = getJspFile(form.fileName, jspType);
         try {
         try {
-            form.content = new String(FileUtil.readBytes(jspFile), Constants.UTF_8);
+            form.content = encodeJsp(new String(FileUtil.readBytes(jspFile), Constants.UTF_8));
         } catch (final UnsupportedEncodingException e) {
         } catch (final UnsupportedEncodingException e) {
             throw new FessSystemException("Invalid encoding", e);
             throw new FessSystemException("Invalid encoding", e);
         }
         }
@@ -272,7 +277,7 @@ public class AdminDesignAction extends FessAdminAction {
         validate(form, messages -> {}, () -> asEditHtml(form));
         validate(form, messages -> {}, () -> asEditHtml(form));
         verifyToken(() -> asEditHtml(form));
         verifyToken(() -> asEditHtml(form));
         try {
         try {
-            write(jspFile.getAbsolutePath(), form.content.getBytes(Constants.UTF_8));
+            write(jspFile.getAbsolutePath(), decodeJsp(form.content).getBytes(Constants.UTF_8));
             saveInfo(messages -> messages.addSuccessUpdateDesignJspFile(GLOBAL, jspFile.getAbsolutePath()));
             saveInfo(messages -> messages.addSuccessUpdateDesignJspFile(GLOBAL, jspFile.getAbsolutePath()));
         } catch (final Exception e) {
         } catch (final Exception e) {
             logger.warn("Failed to update {}", form.fileName, e);
             logger.warn("Failed to update {}", form.fileName, e);
@@ -351,4 +356,15 @@ public class AdminDesignAction extends FessAdminAction {
             data.register("displayFileName", getJspFile(form.fileName, "view").getAbsolutePath());
             data.register("displayFileName", getJspFile(form.fileName, "view").getAbsolutePath());
         });
         });
     }
     }
+
+    public static String decodeJsp(final String value) {
+        return value.replaceAll("<%(?![@-])([\\s\\S]*?)%>", "&lt;%$1%&gt;").replaceAll("<%=([\\s\\S]*?)%>", "&lt;%=$1%&gt;")
+                .replaceAll(TRY_STATEMENT, "<% try{ %>")
+                .replaceAll(CACHE_AND_SESSION_INVALIDATE_STATEMENT, "<% }catch(Exception e){session.invalidate();} %>");
+    }
+
+    public static String encodeJsp(final String value) {
+        return value.replaceAll(Pattern.quote("<% try{ %>"), TRY_STATEMENT)
+                .replaceAll(Pattern.quote("<% }catch(Exception e){session.invalidate();} %>"), CACHE_AND_SESSION_INVALIDATE_STATEMENT);
+    }
 }
 }

+ 0 - 4
src/main/resources/fess.xml

@@ -95,10 +95,6 @@
 			<arg>"errorSystem"</arg>
 			<arg>"errorSystem"</arg>
 			<arg>"error/system.jsp"</arg>
 			<arg>"error/system.jsp"</arg>
 		</postConstruct>
 		</postConstruct>
-		<postConstruct name="addDesignJspFileName">
-			<arg>"errorRedirect"</arg>
-			<arg>"error/redirect.jsp"</arg>
-		</postConstruct>
 		<postConstruct name="addDesignJspFileName">
 		<postConstruct name="addDesignJspFileName">
 			<arg>"errorBadRequest"</arg>
 			<arg>"errorBadRequest"</arg>
 			<arg>"error/badRequest.jsp"</arg>
 			<arg>"error/badRequest.jsp"</arg>

+ 2 - 2
src/main/webapp/WEB-INF/view/error/badRequest.jsp

@@ -24,7 +24,7 @@
 		</div>
 		</div>
 	</main>
 	</main>
 	<jsp:include page="../footer.jsp" />
 	<jsp:include page="../footer.jsp" />
-	<input type="hidden" id="contextPath" value="<%=request.getContextPath()%>" />
+	<input type="hidden" id="contextPath" value="${pageContext.request.contextPath}" />
 	<script type="text/javascript"
 	<script type="text/javascript"
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
@@ -32,4 +32,4 @@
 	<script type="text/javascript" src="${fe:url('/js/search.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/search.js')}"></script>
 </body>
 </body>
 </html>
 </html>
-<% }catch(Exception e){ session.invalidate();}%>
+<% }catch(Exception e){session.invalidate();} %>

+ 1 - 1
src/main/webapp/WEB-INF/view/error/error.jsp

@@ -28,7 +28,7 @@
 		</div>
 		</div>
 	</main>
 	</main>
 	<jsp:include page="../footer.jsp" />
 	<jsp:include page="../footer.jsp" />
-	<input type="hidden" id="contextPath" value="<%=request.getContextPath()%>" />
+	<input type="hidden" id="contextPath" value="${pageContext.request.contextPath}" />
 	<script type="text/javascript"
 	<script type="text/javascript"
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>

+ 1 - 1
src/main/webapp/WEB-INF/view/error/notFound.jsp

@@ -26,7 +26,7 @@
 		</div>
 		</div>
 	</main>
 	</main>
 	<jsp:include page="../footer.jsp" />
 	<jsp:include page="../footer.jsp" />
-	<input type="hidden" id="contextPath" value="<%=request.getContextPath()%>" />
+	<input type="hidden" id="contextPath" value="${pageContext.request.contextPath}" />
 	<script type="text/javascript"
 	<script type="text/javascript"
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>

+ 2 - 2
src/main/webapp/WEB-INF/view/error/system.jsp

@@ -24,7 +24,7 @@
 		</div>
 		</div>
 	</main>
 	</main>
 	<jsp:include page="../footer.jsp" />
 	<jsp:include page="../footer.jsp" />
-	<input type="hidden" id="contextPath" value="<%=request.getContextPath()%>" />
+	<input type="hidden" id="contextPath" value="${pageContext.request.contextPath}" />
 	<script type="text/javascript"
 	<script type="text/javascript"
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 		src="${fe:url('/js/jquery-3.6.3.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/bootstrap.min.js')}"></script>
@@ -32,4 +32,4 @@
 	<script type="text/javascript" src="${fe:url('/js/search.js')}"></script>
 	<script type="text/javascript" src="${fe:url('/js/search.js')}"></script>
 </body>
 </body>
 </html>
 </html>
-<% }catch(Exception e){ session.invalidate();}%>
+<% }catch(Exception e){session.invalidate();} %>

+ 42 - 0
src/test/java/org/codelibs/fess/app/web/admin/design/AdminDesignActionTest.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2024 CodeLibs Project and the Others.
+ *
+ * Licensed 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.
+ */
+package org.codelibs.fess.app.web.admin.design;
+
+import org.codelibs.fess.unit.UnitFessTestCase;
+
+public class AdminDesignActionTest extends UnitFessTestCase {
+    public void test_decodeJsp() {
+        assertEquals("&lt;% a %&gt;", AdminDesignAction.decodeJsp("<% a %>"));
+        assertEquals("&lt;%= a %&gt;", AdminDesignAction.decodeJsp("<%= a %>"));
+        assertEquals("&lt;% a\nb %&gt;", AdminDesignAction.decodeJsp("<% a\nb %>"));
+        assertEquals("&lt;%= a\nb %&gt;", AdminDesignAction.decodeJsp("<%= a\nb %>"));
+        assertEquals("<% a", AdminDesignAction.decodeJsp("<% a"));
+        assertEquals("<%= a", AdminDesignAction.decodeJsp("<%= a"));
+        assertEquals("<% try{ %>", AdminDesignAction.decodeJsp("<!--TRY-->"));
+        assertEquals("<% }catch(Exception e){session.invalidate();} %>",
+                AdminDesignAction.decodeJsp("<!--CACHE_AND_SESSION_INVALIDATE-->"));
+        assertEquals("&lt;% a %&gt; %>", AdminDesignAction.decodeJsp("<% a %> %>"));
+        assertEquals("&lt;% a %&gt; <%", AdminDesignAction.decodeJsp("<% a %> <%"));
+        assertEquals("&lt;% <% a %&gt;", AdminDesignAction.decodeJsp("<% <% a %>"));
+        assertEquals("%> &lt;% a %&gt;", AdminDesignAction.decodeJsp("%> <% a %>"));
+    }
+
+    public void test_encodeJsp() {
+        assertEquals("<!--TRY-->", AdminDesignAction.encodeJsp("<% try{ %>"));
+        assertEquals("<!--CACHE_AND_SESSION_INVALIDATE-->",
+                AdminDesignAction.encodeJsp("<% }catch(Exception e){session.invalidate();} %>"));
+    }
+}