commit 05ad5e0fccfb637832fba114aa5a30c557d810d1
Author: Patrik Harag <patrikharag@gmail.com>
Date:   Sun Apr 21 15:36:10 2019 +0200

    Refactor file uploading (#7267)
    
    * More robust file filtering (takes case of file extension into account)
    * Support for different extensions (depends on module/converter)

diff --git a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/UploadFiles.java b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/UploadFiles.java
index a365526..44bd59c 100644
--- a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/UploadFiles.java
+++ b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/UploadFiles.java
@@ -1,9 +1,11 @@
 package cz.zcu.kiv.offscreen.servlets;
 
+import cz.zcu.kiv.imiger.spi.IModule;
 import cz.zcu.kiv.offscreen.modularization.ModuleProvider;
 import cz.zcu.kiv.offscreen.storage.FileLoader;
 import cz.zcu.kiv.offscreen.user.DataAccessException;
 import cz.zcu.kiv.offscreen.user.dao.DiagramDAO;
+import org.apache.commons.fileupload.FileUploadException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -13,14 +15,13 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
-/**
- *
- * @author Jindra PavlĂ­kovĂˇ <jindra.pav2@seznam.cz>
- */
 public class UploadFiles extends BaseServlet {
     private static final Logger logger = LogManager.getLogger();
 
@@ -59,24 +60,57 @@ public class UploadFiles extends BaseServlet {
     @Override
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         logger.debug("Processing request");
-        Map<String, String> data = new FileLoader().loadFile(request);
+        try {
+            FileLoader fileLoader = new FileLoader(request);
+            Map<String, String> formFields = fileLoader.loadFormFields();
+            String fileType = formFields.get("fileFormat");
+            String fileName = formFields.get("filename");
 
-        if(!data.containsKey("file") || !data.containsKey("fileFormat")) {
-            request.setAttribute("errorMessage", "<strong>Invalid request!</strong><br/>");
-            logger.debug("Invalid request");
-            doGet(request, response);
+            if (fileType == null || fileName == null) {
+                throw new IllegalArgumentException("Missing parameter");
+            }
 
-        } else if (StringUtils.isBlank(data.get("file"))) {
-            request.setAttribute("errorMessage", "<strong>Unsupported file</strong><br/>");
-            logger.debug("Empty diagram string");
-            doGet(request, response);
-        } else {
-            request.getSession().setAttribute("diagram_string", data.get("file"));
-            request.getSession().setAttribute("diagram_type", data.get("fileFormat"));
-            request.getSession().setAttribute("diagram_filename", data.get("filename"));
+            Pattern pattern = getFileNamePatternForType(fileType);
+            Matcher matcher = pattern.matcher(fileName);
+            if (!matcher.matches()) {
+                throw new IllegalArgumentException(
+                        "Filename '" + fileName + "' does not match file type pattern: " + pattern);
+            }
+
+            String fileContent = fileLoader.loadFileAsString(fileName);
+            if (fileContent == null || StringUtils.isBlank(fileContent)) {
+                throw new IllegalArgumentException("Empty file!");
+            }
+
+            request.getSession().setAttribute("diagram_string", fileContent);
+            request.getSession().setAttribute("diagram_type", fileType);
+            request.getSession().setAttribute("diagram_filename", fileName);
             response.sendRedirect(getServletContext().getInitParameter("APP_HOME_URL") + "graph");
             logger.debug("send redirect to /graph");
+
+        } catch (IllegalArgumentException | UnsupportedEncodingException e) {
+            logger.debug("Invalid request");
+            request.setAttribute("errorMessage", "<strong>" + e.getMessage() + "</strong><br/>");
+            doGet(request, response);
+        } catch (FileUploadException e) {
+            logger.debug("Invalid request");
+            request.setAttribute("errorMessage", "<strong>File upload failed!</strong><br/>");
+            doGet(request, response);
         }
         logger.debug("Request processed");
     }
+
+    private Pattern getFileNamePatternForType(String fileType) {
+        if (fileType.equals("raw")) {
+            return Pattern.compile("(?s).+\\.json");
+        } else {
+            IModule module = ModuleProvider.getInstance().getModules().get(fileType);
+            if (module != null) {
+                return module.getFileNamePattern();
+            } else {
+                throw new IllegalArgumentException("No loader available for type: " + fileType);
+            }
+        }
+    }
+
 }
diff --git a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/storage/FileLoader.java b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/storage/FileLoader.java
index e669093..4dfc8dc 100644
--- a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/storage/FileLoader.java
+++ b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/storage/FileLoader.java
@@ -1,12 +1,12 @@
 package cz.zcu.kiv.offscreen.storage;
 
 import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUploadException;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
 
 import javax.servlet.http.HttpServletRequest;
+import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -14,9 +14,16 @@ import java.util.Map;
 public class FileLoader {
 
     private static final int MAX_FILE_SIZE = 512000000;
-    private static final String[] ACCEPTED_EXTENSIONS_FILE = {"json", "dot"};
 
-    private static final Logger logger = LogManager.getLogger();
+    private final List<FileItem> fileItems;
+
+    public FileLoader(HttpServletRequest request) throws FileUploadException {
+        DiskFileItemFactory factory = new DiskFileItemFactory();
+        ServletFileUpload upload = new ServletFileUpload(factory);
+        upload.setSizeMax(MAX_FILE_SIZE);
+
+        this.fileItems = upload.parseRequest(request);
+    }
 
     /**
      * Get multipart data from request which was send and return it as a map where key is field name from form and
@@ -24,53 +31,25 @@ public class FileLoader {
      *
      * @return loaded multipart data in map or empty map.
      */
-    public Map<String, String> loadFile(HttpServletRequest request){
-
-        DiskFileItemFactory factory = new DiskFileItemFactory();
-
-        ServletFileUpload upload = new ServletFileUpload(factory);
-        upload.setSizeMax(MAX_FILE_SIZE);
-
+    public Map<String, String> loadFormFields() throws FileUploadException {
         Map<String, String> resultMap = new HashMap<>();
-
-        try {
-
-            List<FileItem> fileItems = upload.parseRequest(request);
-            for (FileItem item : fileItems) {
-                if (item.isFormField()) {
-                    resultMap.put(item.getFieldName(), item.getString());
-                } else {
-                    resultMap.put("filename", item.getName());
-                    if (isAcceptedExtension(item.getName()) && item.getSize() > 0) {
-                        logger.debug(item.getName() + " - " + item.getContentType());
-                        resultMap.put(item.getFieldName(), item.getString("UTF-8"));
-                    } else {
-                        resultMap.put(item.getFieldName(), "");
-                    }
-                }
+        for (FileItem item : fileItems) {
+            if (item.isFormField()) {
+                resultMap.put(item.getFieldName(), item.getString());
+            } else {
+                resultMap.put("filename", item.getName());
             }
-
-        } catch (Exception ex) {
-            logger.error("Can not load file from request: ", ex);
         }
         return resultMap;
     }
 
-    /**
-     * Check if input string ends with allowed extension.
-     *
-     * @param componentName all name of file
-     * @return true - if extension is allowed, false - otherwise.
-     */
-    private boolean isAcceptedExtension(String componentName) {
-        boolean accepted = false;
-        for(String extension : ACCEPTED_EXTENSIONS_FILE) {
-            accepted = componentName.endsWith(extension);
-
-            if(accepted) {
-                break;
+    public String loadFileAsString(String name) throws UnsupportedEncodingException {
+        for (FileItem item : fileItems) {
+            if (!item.isFormField() && item.getName().equals(name)) {
+                return item.getString("UTF-8");
             }
         }
-        return accepted;
+        return null;
     }
+
 }
diff --git a/sources/imiger-dot-converter/src/main/java/cz/zcu/kiv/imiger/plugin/dot/DOT.java b/sources/imiger-dot-converter/src/main/java/cz/zcu/kiv/imiger/plugin/dot/DOT.java
index d9d0b62..2de2bc9 100644
--- a/sources/imiger-dot-converter/src/main/java/cz/zcu/kiv/imiger/plugin/dot/DOT.java
+++ b/sources/imiger-dot-converter/src/main/java/cz/zcu/kiv/imiger/plugin/dot/DOT.java
@@ -7,6 +7,7 @@ import cz.zcu.kiv.imiger.plugin.dot.loader.BaseDOTLoader;
 import cz.zcu.kiv.imiger.plugin.dot.loader.DigraphDOTLoader;
 import cz.zcu.kiv.imiger.spi.IModule;
 import cz.zcu.kiv.imiger.vo.Graph;
+import java.util.regex.Pattern;
 
 /**
  * IModule implementation for DOT converter.
@@ -23,6 +24,11 @@ public class DOT implements IModule {
         return "DOT file";
     }
 
+    @Override
+    public Pattern getFileNamePattern() {
+        return Pattern.compile("(?s).+\\.(dot|gv)");
+    }
+
     /**
      * Retrieves DOT file which has to be converted to raw JSON that
      * IMiGEr support.
@@ -39,9 +45,7 @@ public class DOT implements IModule {
         if(!graph.getVertices().isEmpty()) {
             Gson gson = new Gson();
             return gson.toJson(graph, Graph.class);
-        }
-
-        else {
+        } else {
             return "";
         }
     }
diff --git a/sources/imiger-module/src/main/java/cz/zcu/kiv/imiger/spi/IModule.java b/sources/imiger-module/src/main/java/cz/zcu/kiv/imiger/spi/IModule.java
index b9fc2cb..ff169f1 100644
--- a/sources/imiger-module/src/main/java/cz/zcu/kiv/imiger/spi/IModule.java
+++ b/sources/imiger-module/src/main/java/cz/zcu/kiv/imiger/spi/IModule.java
@@ -1,5 +1,7 @@
 package cz.zcu.kiv.imiger.spi;
 
+import java.util.regex.Pattern;
+
 /**
  * Service Provider Interface (SPI) that must be implemented by all modules.
  */
@@ -9,6 +11,13 @@ public interface IModule {
      */
     String getModuleName();
 
+    /**
+     * Returns diagram file name pattern.
+     *
+     * @return pattern
+     */
+    Pattern getFileNamePattern();
+
     /**
      * Converts input string in any format to raw JSON processable by IMiGEr.
      *
diff --git a/sources/imiger-plugin-template/src/main/java/cz/zcu/kiv/imiger/plugin/template/Converter.java b/sources/imiger-plugin-template/src/main/java/cz/zcu/kiv/imiger/plugin/template/Converter.java
index 557fcc1..c0b876f 100644
--- a/sources/imiger-plugin-template/src/main/java/cz/zcu/kiv/imiger/plugin/template/Converter.java
+++ b/sources/imiger-plugin-template/src/main/java/cz/zcu/kiv/imiger/plugin/template/Converter.java
@@ -3,6 +3,7 @@ package cz.zcu.kiv.imiger.plugin.template;
 import com.google.gson.Gson;
 import cz.zcu.kiv.imiger.spi.IModule;
 import cz.zcu.kiv.imiger.vo.Graph;
+import java.util.regex.Pattern;
 
 public class Converter implements IModule {
     @Override
@@ -10,6 +11,11 @@ public class Converter implements IModule {
         return "Module Template";
     }
 
+    @Override
+    public Pattern getFileNamePattern() {
+        return Pattern.compile("(?s).+\\.json");
+    }
+
     /**
      * Convert input file to RAW JSON and return it.
      */
diff --git a/sources/imiger-spade-converter/src/main/java/cz/zcu/kiv/imiger/plugin/spade/Spade.java b/sources/imiger-spade-converter/src/main/java/cz/zcu/kiv/imiger/plugin/spade/Spade.java
index b732131..6943087 100644
--- a/sources/imiger-spade-converter/src/main/java/cz/zcu/kiv/imiger/plugin/spade/Spade.java
+++ b/sources/imiger-spade-converter/src/main/java/cz/zcu/kiv/imiger/plugin/spade/Spade.java
@@ -5,6 +5,7 @@ import cz.zcu.kiv.imiger.vo.Graph;
 import cz.zcu.kiv.imiger.plugin.spade.graph.GraphManager;
 import cz.zcu.kiv.imiger.plugin.spade.graph.loader.GraphJSONDataLoader;
 import cz.zcu.kiv.imiger.plugin.spade.graph.loader.JSONConfigLoader;
+import java.util.regex.Pattern;
 import net.sf.json.JSONObject;
 
 public class Spade implements IModule {
@@ -13,6 +14,11 @@ public class Spade implements IModule {
         return "Spade JSON";
     }
 
+    @Override
+    public Pattern getFileNamePattern() {
+        return Pattern.compile("(?s).+\\.json");
+    }
+
     /**
      * Convert input spade JSON to RAW JSON.
      *
