mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2025-09-18 09:44:37 +08:00
【新特性】支持限制预览源站点,保护预览服务不被滥用
This commit is contained in:
@@ -40,6 +40,10 @@ cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
|
|||||||
#base.url = https://file.keking.cn
|
#base.url = https://file.keking.cn
|
||||||
base.url = ${KK_BASE_URL:default}
|
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}
|
cache.enabled = ${KK_CACHE_ENABLED:true}
|
||||||
|
|
||||||
|
@@ -5,6 +5,9 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @auther: chenjh
|
* @auther: chenjh
|
||||||
@@ -23,8 +26,19 @@ public class ConfigConstants {
|
|||||||
private static String ftpControlEncoding;
|
private static String ftpControlEncoding;
|
||||||
private static String fileDir = OfficeUtils.getHomePath() + File.separator + "file" + File.separator;
|
private static String fileDir = OfficeUtils.getHomePath() + File.separator + "file" + File.separator;
|
||||||
private static String baseUrl;
|
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_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() {
|
public static Boolean isCacheEnabled() {
|
||||||
return cacheEnabled;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,15 +22,6 @@ public class ConfigRefreshComponent {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRefreshComponent.class);
|
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
|
@PostConstruct
|
||||||
void refresh() {
|
void refresh() {
|
||||||
Thread configRefreshThread = new Thread(new ConfigRefreshThread());
|
Thread configRefreshThread = new Thread(new ConfigRefreshThread());
|
||||||
@@ -53,21 +44,23 @@ public class ConfigRefreshComponent {
|
|||||||
String ftpControlEncoding;
|
String ftpControlEncoding;
|
||||||
String configFilePath = OfficeUtils.getCustomizedConfigPath();
|
String configFilePath = OfficeUtils.getCustomizedConfigPath();
|
||||||
String baseUrl;
|
String baseUrl;
|
||||||
|
String trustHost;
|
||||||
while (true) {
|
while (true) {
|
||||||
FileReader fileReader = new FileReader(configFilePath);
|
FileReader fileReader = new FileReader(configFilePath);
|
||||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||||
properties.load(bufferedReader);
|
properties.load(bufferedReader);
|
||||||
OfficeUtils.restorePropertiesFromEnvFormat(properties);
|
OfficeUtils.restorePropertiesFromEnvFormat(properties);
|
||||||
cacheEnabled = new Boolean(properties.getProperty("cache.enabled", DEFAULT_CACHE_ENABLED));
|
cacheEnabled = new Boolean(properties.getProperty("cache.enabled", ConfigConstants.DEFAULT_CACHE_ENABLED));
|
||||||
text = properties.getProperty("simText", DEFAULT_TXT_TYPE);
|
text = properties.getProperty("simText", ConfigConstants.DEFAULT_TXT_TYPE);
|
||||||
media = properties.getProperty("media", DEFAULT_MEDIA_TYPE);
|
media = properties.getProperty("media", ConfigConstants.DEFAULT_MEDIA_TYPE);
|
||||||
officePreviewType = properties.getProperty("office.preview.type", OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE);
|
officePreviewType = properties.getProperty("office.preview.type", ConfigConstants.DEFAULT_OFFICE_PREVIEW_TYPE);
|
||||||
ftpUsername = properties.getProperty("ftp.username", DEFAULT_FTP_USERNAME);
|
ftpUsername = properties.getProperty("ftp.username", ConfigConstants.DEFAULT_FTP_USERNAME);
|
||||||
ftpPassword = properties.getProperty("ftp.password", DEFAULT_FTP_PASSWORD);
|
ftpPassword = properties.getProperty("ftp.password", ConfigConstants.DEFAULT_FTP_PASSWORD);
|
||||||
ftpControlEncoding = properties.getProperty("ftp.control.encoding", DEFAULT_FTP_CONTROL_ENCODING);
|
ftpControlEncoding = properties.getProperty("ftp.control.encoding", ConfigConstants.DEFAULT_FTP_CONTROL_ENCODING);
|
||||||
textArray = text.split(",");
|
textArray = text.split(",");
|
||||||
mediaArray = media.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.setCacheEnabled(cacheEnabled);
|
||||||
ConfigConstants.setSimText(textArray);
|
ConfigConstants.setSimText(textArray);
|
||||||
ConfigConstants.setMedia(mediaArray);
|
ConfigConstants.setMedia(mediaArray);
|
||||||
@@ -76,6 +69,7 @@ public class ConfigRefreshComponent {
|
|||||||
ConfigConstants.setFtpPassword(ftpPassword);
|
ConfigConstants.setFtpPassword(ftpPassword);
|
||||||
ConfigConstants.setFtpControlEncoding(ftpControlEncoding);
|
ConfigConstants.setFtpControlEncoding(ftpControlEncoding);
|
||||||
ConfigConstants.setBaseUrl(baseUrl);
|
ConfigConstants.setBaseUrl(baseUrl);
|
||||||
|
ConfigConstants.setTrustHost(trustHost);
|
||||||
bufferedReader.close();
|
bufferedReader.close();
|
||||||
fileReader.close();
|
fileReader.close();
|
||||||
Thread.sleep(1000L);
|
Thread.sleep(1000L);
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,5 @@
|
|||||||
package cn.keking.web.controller;
|
package cn.keking.web.controller;
|
||||||
|
|
||||||
import cn.keking.config.ConfigConstants;
|
|
||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.service.FilePreview;
|
import cn.keking.service.FilePreview;
|
||||||
import cn.keking.service.FilePreviewFactory;
|
import cn.keking.service.FilePreviewFactory;
|
||||||
@@ -34,16 +33,14 @@ public class OnlinePreviewController {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(OnlinePreviewController.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(OnlinePreviewController.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
FilePreviewFactory previewFactory;
|
private FilePreviewFactory previewFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
CacheService cacheService;
|
private CacheService cacheService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FileUtils fileUtils;
|
private FileUtils fileUtils;
|
||||||
|
|
||||||
private String fileDir = ConfigConstants.getFileDir();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param url
|
* @param url
|
||||||
* @param model
|
* @param model
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package cn.keking.filters;
|
package cn.keking.web.filter;
|
||||||
|
|
||||||
import cn.keking.config.ConfigConstants;
|
import cn.keking.config.ConfigConstants;
|
||||||
import cn.keking.config.ConfigRefreshComponent;
|
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -29,7 +28,7 @@ public class ChinesePathFilter implements Filter {
|
|||||||
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
||||||
localBaseUrl = pathBuilder.toString();
|
localBaseUrl = pathBuilder.toString();
|
||||||
String baseUrlTmp = ConfigConstants.getBaseUrl();
|
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("/")) {
|
if (!baseUrlTmp.endsWith("/")) {
|
||||||
baseUrlTmp = baseUrlTmp.concat("/");
|
baseUrlTmp = baseUrlTmp.concat("/");
|
||||||
}
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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
jodconverter-web/src/main/resources/web/notTrustHost.html
Normal file
41
jodconverter-web/src/main/resources/web/notTrustHost.html
Normal file
@@ -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>
|
||||||
|
有任何疑问,请加 <a href="https://jq.qq.com/?_wv=1027&k=5c0UAtu">官方QQ群:613025121</a> 咨询
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Reference in New Issue
Block a user