Ver código fonte

【新特性】支持限制预览源站点,保护预览服务不被滥用

陈精华 5 anos atrás
pai
commit
2144b776b1

+ 4 - 0
jodconverter-web/src/main/config/application.properties

@@ -40,6 +40,10 @@ cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
 #base.url = https://file.keking.cn
 base.url = ${KK_BASE_URL:default}
 
+#信任站点,多个用','隔开,设置了之后,会限制只能预览来自信任站点列表的文件,默认不限制
+#trust.host = file.keking.cn,kkfileview.keking.cn
+trust.host = ${KK_TRUST_HOST:default}
+
 #是否启用缓存
 cache.enabled = ${KK_CACHE_ENABLED:true}
 

+ 39 - 0
jodconverter-web/src/main/java/cn/keking/config/ConfigConstants.java

@@ -5,6 +5,9 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.io.File;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * @auther: chenjh
@@ -23,8 +26,19 @@ public class ConfigConstants {
     private static String ftpControlEncoding;
     private static String fileDir = OfficeUtils.getHomePath() + File.separator + "file" + File.separator;
     private static String baseUrl;
+    private static String trustHost;
+    private static Set<String> trustHostSet;
 
+    public static final String DEFAULT_CACHE_ENABLED = "true";
+    public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd";
+    public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv";
     public static final String DEFAULT_FILE_DIR_VALUE = "default";
+    public static final String DEFAULT_FTP_USERNAME = null;
+    public static final String DEFAULT_FTP_PASSWORD = null;
+    public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8";
+    public static final String DEFAULT_OFFICE_PREVIEW_TYPE = "image";
+    public static final String DEFAULT_BASE_URL = "default";
+    public static final String DEFAULT_TRUST_HOST = "default";
 
     public static Boolean isCacheEnabled() {
         return cacheEnabled;
@@ -104,4 +118,29 @@ public class ConfigConstants {
         }
     }
 
+    static String getTrustHost() {
+        return trustHost;
+    }
+
+    @Value("${trust.host:default}")
+    static void setTrustHost(String trustHost) {
+        ConfigConstants.trustHost = trustHost;
+        Set<String> trustHostSet;
+        if (DEFAULT_TRUST_HOST.equals(trustHost.toLowerCase())) {
+            trustHostSet = new HashSet<>();
+        } else {
+            String[] trustHostArray = trustHost.toLowerCase().split(",");
+            trustHostSet = new HashSet<>(Arrays.asList(trustHostArray));
+            ConfigConstants.setTrustHostSet(trustHostSet);
+        }
+        ConfigConstants.setTrustHostSet(trustHostSet);
+    }
+
+    public static Set<String> getTrustHostSet() {
+        return trustHostSet;
+    }
+
+    private static void setTrustHostSet(Set<String> trustHostSet) {
+        ConfigConstants.trustHostSet = trustHostSet;
+    }
 }

+ 11 - 17
jodconverter-web/src/main/java/cn/keking/config/ConfigRefreshComponent.java

@@ -22,15 +22,6 @@ public class ConfigRefreshComponent {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRefreshComponent.class);
 
-    public static final String DEFAULT_CACHE_ENABLED = "true";
-    public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd";
-    public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv";
-
-    public static final String DEFAULT_FTP_USERNAME = null;
-    public static final String DEFAULT_FTP_PASSWORD = null;
-    public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8";
-    public static final String DEFAULT_BASE_URL = "default";
-
     @PostConstruct
     void refresh() {
         Thread configRefreshThread = new Thread(new ConfigRefreshThread());
@@ -53,21 +44,23 @@ public class ConfigRefreshComponent {
                 String ftpControlEncoding;
                 String configFilePath = OfficeUtils.getCustomizedConfigPath();
                 String baseUrl;
+                String trustHost;
                 while (true) {
                     FileReader fileReader = new FileReader(configFilePath);
                     BufferedReader bufferedReader = new BufferedReader(fileReader);
                     properties.load(bufferedReader);
                     OfficeUtils.restorePropertiesFromEnvFormat(properties);
-                    cacheEnabled = new Boolean(properties.getProperty("cache.enabled", DEFAULT_CACHE_ENABLED));
-                    text = properties.getProperty("simText", DEFAULT_TXT_TYPE);
-                    media = properties.getProperty("media", DEFAULT_MEDIA_TYPE);
-                    officePreviewType = properties.getProperty("office.preview.type", OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE);
-                    ftpUsername = properties.getProperty("ftp.username", DEFAULT_FTP_USERNAME);
-                    ftpPassword = properties.getProperty("ftp.password", DEFAULT_FTP_PASSWORD);
-                    ftpControlEncoding = properties.getProperty("ftp.control.encoding", DEFAULT_FTP_CONTROL_ENCODING);
+                    cacheEnabled = new Boolean(properties.getProperty("cache.enabled", ConfigConstants.DEFAULT_CACHE_ENABLED));
+                    text = properties.getProperty("simText", ConfigConstants.DEFAULT_TXT_TYPE);
+                    media = properties.getProperty("media", ConfigConstants.DEFAULT_MEDIA_TYPE);
+                    officePreviewType = properties.getProperty("office.preview.type", ConfigConstants.DEFAULT_OFFICE_PREVIEW_TYPE);
+                    ftpUsername = properties.getProperty("ftp.username", ConfigConstants.DEFAULT_FTP_USERNAME);
+                    ftpPassword = properties.getProperty("ftp.password", ConfigConstants.DEFAULT_FTP_PASSWORD);
+                    ftpControlEncoding = properties.getProperty("ftp.control.encoding", ConfigConstants.DEFAULT_FTP_CONTROL_ENCODING);
                     textArray = text.split(",");
                     mediaArray = media.split(",");
-                    baseUrl = properties.getProperty("base.url", DEFAULT_BASE_URL);
+                    baseUrl = properties.getProperty("base.url", ConfigConstants.DEFAULT_BASE_URL);
+                    trustHost = properties.getProperty("trust.host", ConfigConstants.DEFAULT_TRUST_HOST);
                     ConfigConstants.setCacheEnabled(cacheEnabled);
                     ConfigConstants.setSimText(textArray);
                     ConfigConstants.setMedia(mediaArray);
@@ -76,6 +69,7 @@ public class ConfigRefreshComponent {
                     ConfigConstants.setFtpPassword(ftpPassword);
                     ConfigConstants.setFtpControlEncoding(ftpControlEncoding);
                     ConfigConstants.setBaseUrl(baseUrl);
+                    ConfigConstants.setTrustHost(trustHost);
                     bufferedReader.close();
                     fileReader.close();
                     Thread.sleep(1000L);

+ 0 - 23
jodconverter-web/src/main/java/cn/keking/filters/FilterConfiguration.java

@@ -1,23 +0,0 @@
-package cn.keking.filters;
-
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-/**
- *
- * @author yudian-it
- * @date 2017/11/30
- */
-@Configuration
-public class FilterConfiguration {
-
-    @Bean
-    public FilterRegistrationBean getChinesePathFilter(){
-        ChinesePathFilter filter = new ChinesePathFilter();
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        return registrationBean;
-    }
-}

+ 2 - 5
jodconverter-web/src/main/java/cn/keking/web/controller/OnlinePreviewController.java

@@ -1,6 +1,5 @@
 package cn.keking.web.controller;
 
-import cn.keking.config.ConfigConstants;
 import cn.keking.model.FileAttribute;
 import cn.keking.service.FilePreview;
 import cn.keking.service.FilePreviewFactory;
@@ -34,16 +33,14 @@ public class OnlinePreviewController {
     private static final Logger LOGGER = LoggerFactory.getLogger(OnlinePreviewController.class);
 
     @Autowired
-    FilePreviewFactory previewFactory;
+    private FilePreviewFactory previewFactory;
 
     @Autowired
-    CacheService cacheService;
+    private CacheService cacheService;
 
     @Autowired
     private FileUtils fileUtils;
 
-    private String fileDir = ConfigConstants.getFileDir();
-
     /**
      * @param url
      * @param model

+ 2 - 3
jodconverter-web/src/main/java/cn/keking/filters/ChinesePathFilter.java

@@ -1,7 +1,6 @@
-package cn.keking.filters;
+package cn.keking.web.filter;
 
 import cn.keking.config.ConfigConstants;
-import cn.keking.config.ConfigRefreshComponent;
 
 import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
@@ -29,7 +28,7 @@ public class ChinesePathFilter implements Filter {
                 .append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
         localBaseUrl = pathBuilder.toString();
         String baseUrlTmp = ConfigConstants.getBaseUrl();
-        if (baseUrlTmp != null && !ConfigRefreshComponent.DEFAULT_BASE_URL.equals(baseUrlTmp.toLowerCase())) {
+        if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equals(baseUrlTmp.toLowerCase())) {
             if (!baseUrlTmp.endsWith("/")) {
                 baseUrlTmp = baseUrlTmp.concat("/");
             }

+ 41 - 0
jodconverter-web/src/main/java/cn/keking/web/filter/FilterConfiguration.java

@@ -0,0 +1,41 @@
+package cn.keking.web.filter;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/30
+ */
+@Configuration
+public class FilterConfiguration {
+
+
+    @Bean
+    public FilterRegistrationBean getChinesePathFilter() {
+        ChinesePathFilter filter = new ChinesePathFilter();
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        return registrationBean;
+    }
+
+    @Bean
+    public FilterRegistrationBean getTrustHostFilter() {
+        Set<String> filterUri = new HashSet<>();
+        filterUri.add("/onlinePreview");
+        filterUri.add("/picturesPreview");
+        filterUri.add("/getCorsFile");
+        filterUri.add("/addTask");
+        TrustHostFilter filter = new TrustHostFilter();
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        registrationBean.setUrlPatterns(filterUri);
+        return registrationBean;
+    }
+}

+ 75 - 0
jodconverter-web/src/main/java/cn/keking/web/filter/TrustHostFilter.java

@@ -0,0 +1,75 @@
+package cn.keking.web.filter;
+
+import cn.keking.config.ConfigConstants;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.FileCopyUtils;
+
+import javax.servlet.*;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author chenjh
+ * @since 2020/2/18 19:13
+ */
+public class TrustHostFilter implements Filter {
+
+    private String notTrustHost;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        ClassPathResource classPathResource = new ClassPathResource("web/notTrustHost.html");
+        try {
+            classPathResource.getInputStream();
+            byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
+            this.notTrustHost = new String(bytes, StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        String url = getSourceUrl(request);
+        String host = getHost(url);
+        if (!ConfigConstants.getTrustHostSet().isEmpty() && !ConfigConstants.getTrustHostSet().contains(host)) {
+            String html = this.notTrustHost.replace("${current_host}", host);
+            response.getWriter().write(html);
+            response.getWriter().close();
+        }
+        chain.doFilter(request, response);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+
+    private String getSourceUrl(ServletRequest request) {
+        String url = request.getParameter("url");
+        String currentUrl = request.getParameter("currentUrl");
+        String urlPath = request.getParameter("urlPath");
+        if (StringUtils.isNotBlank(url)) {
+            return url;
+        }
+        if (StringUtils.isNotBlank(currentUrl)) {
+            return currentUrl;
+        }
+        if (StringUtils.isNotBlank(urlPath)) {
+            return urlPath;
+        }
+        return null;
+    }
+
+    private String getHost(String urlStr) {
+        try {
+            URL url = new URL(urlStr);
+            return url.getHost().toLowerCase();
+        } catch (MalformedURLException e) {
+        }
+        return null;
+    }
+}

+ 41 - 0
jodconverter-web/src/main/resources/web/notTrustHost.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <meta charset="utf-8" />
+    <style type="text/css">
+        body {
+            margin: 0 auto;
+            width: 900px;
+            background-color: #CCB;
+        }
+        .container {
+            width: 700px;
+            height: 700px;
+            margin: 0 auto;
+        }
+        img {
+            width: auto;
+            height: auto;
+            max-width: 100%;
+            max-height: 100%;
+            padding-bottom: 36px;
+        }
+        p {
+            display: block;
+            font-size: 20px;
+            color: blue;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <img src="images/sorry.jpg" />
+    <p>
+        预览源文件来自不受信任的站点:<span style="color: red; display: inline;">${current_host}</span> ,请联系管理员 <br>
+        有任何疑问,请加&nbsp;<a href="https://jq.qq.com/?_wv=1027&k=5c0UAtu">官方QQ群:613025121</a>&nbsp;咨询
+    </p>
+</div>
+</body>
+
+</html>