diff --git a/server/src/main/config/application.properties b/server/src/main/config/application.properties index fd79f6d5..e964c10c 100644 --- a/server/src/main/config/application.properties +++ b/server/src/main/config/application.properties @@ -22,9 +22,15 @@ office.plugin.server.ports = 2001,2002 ## office 转换服务 task 超时时间,默认五分钟 office.plugin.task.timeout = 5m -#文件资源路径(默认为打包根路径下的file目录下) +#预览生成资源路径(默认为打包根路径下的file目录下) #file.dir = D:\\kkFileview\\ file.dir = ${KK_FILE_DIR:default} + +#允许预览的本地文件夹 默认不允许任何本地文件被预览 +#file.dir = D:\\kkFileview\\ +local.preview.dir = ${KK_LOCAL_PREVIEW_DIR:default} + + #openoffice home路径 #office.home = C:\\Program Files (x86)\\OpenOffice 4 office.home = ${KK_OFFICE_HOME:default} @@ -66,7 +72,7 @@ office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image} office.preview.switch.disabled = ${KK_OFFICE_PREVIEW_SWITCH_DISABLED:false} #是否禁止下载转换生成的pdf文件 -pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:true} +pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:false} #是否禁用首页文件上传 file.upload.disable = ${KK_FILE_UPLOAD_ENABLED:false} diff --git a/server/src/main/java/cn/keking/config/ConfigConstants.java b/server/src/main/java/cn/keking/config/ConfigConstants.java index 3ebd818a..cdef9a28 100644 --- a/server/src/main/java/cn/keking/config/ConfigConstants.java +++ b/server/src/main/java/cn/keking/config/ConfigConstants.java @@ -33,6 +33,7 @@ public class ConfigConstants { private static String ftpControlEncoding; private static String baseUrl; private static String fileDir = ConfigUtils.getHomePath() + File.separator + "file" + File.separator; + private static String localPreviewDir; private static CopyOnWriteArraySet trustHostSet; private static String pdfDownloadDisable; private static Boolean fileUploadDisable; @@ -47,6 +48,7 @@ public class ConfigConstants { public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8"; public static final String DEFAULT_BASE_URL = "default"; public static final String DEFAULT_FILE_DIR_VALUE = "default"; + public static final String DEFAULT_LOCAL_PREVIEW_DIR_VALUE = "default"; public static final String DEFAULT_TRUST_HOST = "default"; public static final String DEFAULT_PDF_DOWNLOAD_DISABLE = "true"; public static final String DEFAULT_FILE_UPLOAD_DISABLE = "false"; @@ -203,6 +205,24 @@ public class ConfigConstants { } } + public static String getLocalPreviewDir() { + return localPreviewDir; + } + + @Value("${local.preview.dir:default}") + public void setLocalPreviewDir(String localPreviewDir) { + setLocalPreviewDirValue(localPreviewDir); + } + + public static void setLocalPreviewDirValue(String localPreviewDir) { + if (!DEFAULT_LOCAL_PREVIEW_DIR_VALUE.equals(localPreviewDir)) { + if (!localPreviewDir.endsWith(File.separator)) { + localPreviewDir = localPreviewDir + File.separator; + } + } + ConfigConstants.localPreviewDir = localPreviewDir; + } + @Value("${trust.host:default}") public void setTrustHost(String trustHost) { setTrustHostValue(trustHost); diff --git a/server/src/main/java/cn/keking/utils/WebUtils.java b/server/src/main/java/cn/keking/utils/WebUtils.java index c978e59c..58ed678c 100644 --- a/server/src/main/java/cn/keking/utils/WebUtils.java +++ b/server/src/main/java/cn/keking/utils/WebUtils.java @@ -81,6 +81,14 @@ public class WebUtils { * @return 文件名 */ public static String getFileNameFromURL(String url) { + if (url.toLowerCase().startsWith("file:")) { + try { + URL urlObj = new URL(url); + url = urlObj.getPath().substring(1); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } // 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题 // 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名 String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length()); diff --git a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java index 7309db76..42804746 100644 --- a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java +++ b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java @@ -1,5 +1,6 @@ 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; @@ -12,6 +13,7 @@ import fr.opensagres.xdocreport.core.io.IOUtils; import io.mola.galimatias.GalimatiasParseException; import jodd.io.NetUtil; import org.apache.commons.codec.binary.Base64; +import org.artofsolving.jodconverter.util.PlatformUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; @@ -25,9 +27,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URL; +import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.Locale; import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE; @@ -61,6 +65,9 @@ public class OnlinePreviewController { String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url"); return otherFilePreview.notSupportedFile(model, errorMsg); } + if (!allowPreview(fileUrl)) { + return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + fileUrl); + } FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req); model.addAttribute("file", fileAttribute); FilePreview filePreview = previewFactory.get(fileAttribute); @@ -86,8 +93,14 @@ public class OnlinePreviewController { String currentUrl = req.getParameter("currentUrl"); if (StringUtils.hasText(currentUrl)) { String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl)); + if (!allowPreview(decodedCurrentUrl)) { + return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + decodedCurrentUrl); + } model.addAttribute("currentUrl", decodedCurrentUrl); } else { + if (!allowPreview(imgUrls.get(0))) { + return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + imgUrls.get(0)); + } model.addAttribute("currentUrl", imgUrls.get(0)); } return PICTURE_FILE_PREVIEW_PAGE; @@ -105,6 +118,12 @@ public class OnlinePreviewController { logger.info("下载跨域pdf文件url:{}", urlPath); try { URL url = WebUtils.normalizedURL(urlPath); + if (!allowPreview(urlPath)) { + response.setHeader("content-type", "text/html;charset=utf-8"); + response.getOutputStream().println("forbidden"); + response.setStatus(401); + return; + } byte[] bytes = NetUtil.downloadBytes(url.toString()); IOUtils.write(bytes, response.getOutputStream()); } catch (IOException | GalimatiasParseException e) { @@ -125,4 +144,24 @@ public class OnlinePreviewController { return "success"; } + private boolean allowPreview(String urlPath) { + try { + URL url = WebUtils.normalizedURL(urlPath); + if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) { + String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name()); + if (PlatformUtils.isWindows()) { + filePath = filePath.replaceAll("/", "\\\\"); + } + filePath = filePath.substring(1); + if (!filePath.startsWith(ConfigConstants.getFileDir()) && !filePath.startsWith(ConfigConstants.getLocalPreviewDir())) { + return false; + } + } + return true; + } catch (IOException | GalimatiasParseException e) { + logger.error("解析URL异常,url:{}", urlPath, e); + return false; + } + } + } diff --git a/server/src/main/resources/web/fileNotSupported.ftl b/server/src/main/resources/web/fileNotSupported.ftl index 5f755d6f..69699143 100644 --- a/server/src/main/resources/web/fileNotSupported.ftl +++ b/server/src/main/resources/web/fileNotSupported.ftl @@ -32,8 +32,7 @@
- 该文件类型(${file.suffix?html})系统暂时不支持在线预览,说明: - + 该文件类型(${fileType})系统暂时不支持在线预览,说明

${msg}

有任何疑问,请加 官方QQ群:613025121 咨询