mirror of
https://gitee.com/wangkang/udf.git
synced 2026-11-02 17:05:52 +00:00
增加访问文件的api , 调整xss的判断逻辑
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
+65
@@ -0,0 +1,65 @@
|
||||
package org.itkk.udf.api.general.web;
|
||||
|
||||
|
||||
import org.itkk.udf.api.common.CommonConstant;
|
||||
import org.itkk.udf.starter.core.exception.ParameterValidException;
|
||||
import org.itkk.udf.starter.file.db.DbFileConstant;
|
||||
import org.itkk.udf.starter.file.db.dto.DbFileInfoDto;
|
||||
import org.itkk.udf.starter.file.db.web.DbFileBase;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = CommonConstant.URL_ROOT_WEB_PUBLIC + "file/")
|
||||
public class FilePublicController extends DbFileBase {
|
||||
/**
|
||||
* 文件预览
|
||||
*
|
||||
* @param id id
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
@GetMapping("preview/{id}")
|
||||
public void preview(@PathVariable String id, @RequestParam(name = "width", required = false) Integer width, @RequestParam(name = "height", required = false) Integer height) throws IOException {
|
||||
//获得文件信息
|
||||
DbFileInfoDto dbFileInfoDto = dbFileService.get(id);
|
||||
//判空
|
||||
if (dbFileInfoDto == null) {
|
||||
throw new ParameterValidException("文件ID:" + id + "对应的文件不存在");
|
||||
}
|
||||
//判断是否公共文件
|
||||
if (DbFileConstant.PUBLIC_ROOT_PATH_CODE.equals(dbFileInfoDto.getRootPathCode())) {
|
||||
throw new ParameterValidException("文件ID:" + id + "不是公共文件");
|
||||
}
|
||||
//设置头信息
|
||||
this.setResponseHeader(id, true);
|
||||
//下载
|
||||
dbFileService.download(id, width, height, response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param id id
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
@GetMapping("download/{id}")
|
||||
public void download(@PathVariable String id) throws IOException {
|
||||
//获得文件信息
|
||||
DbFileInfoDto dbFileInfoDto = dbFileService.get(id);
|
||||
//判空
|
||||
if (dbFileInfoDto == null) {
|
||||
throw new ParameterValidException("文件ID:" + id + "对应的文件不存在");
|
||||
}
|
||||
//判断是否公共文件
|
||||
if (DbFileConstant.PUBLIC_ROOT_PATH_CODE.equals(dbFileInfoDto.getRootPathCode())) {
|
||||
throw new ParameterValidException("文件ID:" + id + "不是公共文件");
|
||||
}
|
||||
//设置头信息
|
||||
this.setResponseHeader(id, false);
|
||||
//下载
|
||||
dbFileService.download(id, null, null, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ logging.file.max-size=100MB
|
||||
logging.file.max-history=31
|
||||
# FILE DB
|
||||
org.itkk.udf.starter.db.file.properties.mapping.common=D:/app/file/common/
|
||||
org.itkk.udf.starter.db.file.properties.mapping.public=D:/app/file/public/
|
||||
org.itkk.udf.starter.db.file.properties.mapping.temp=D:/app/file/temp/
|
||||
org.itkk.udf.starter.db.file.properties.fileUploadSupportType=pdf,jpg,jpeg,png
|
||||
org.itkk.udf.starter.db.file.properties.previewSupportContentType=application/pdf,image/jpeg,image/png
|
||||
|
||||
@@ -11,6 +11,7 @@ logging.file.max-size=100MB
|
||||
logging.file.max-history=31
|
||||
# FILE DB
|
||||
org.itkk.udf.starter.db.file.properties.mapping.common=/usr/local/share/nginx/file/common/
|
||||
org.itkk.udf.starter.db.file.properties.mapping.public=/usr/local/share/nginx/file/public/
|
||||
org.itkk.udf.starter.db.file.properties.mapping.temp=/usr/local/share/nginx/file/temp/
|
||||
org.itkk.udf.starter.db.file.properties.fileUploadSupportType=pdf,jpg,jpeg,png
|
||||
org.itkk.udf.starter.db.file.properties.previewSupportContentType=application/pdf,image/jpeg,image/png
|
||||
|
||||
@@ -90,8 +90,12 @@ public class CoreUtil {
|
||||
* @return 包含中文标点 true , 不包含中文标点 false
|
||||
*/
|
||||
public static boolean isChinesePunctuation(String s) {
|
||||
final char[] skipArr = new char[]{'>', '<'};
|
||||
boolean rv = false;
|
||||
for (char c : s.toCharArray()) {
|
||||
if (ArrayUtils.contains(skipArr, c)) {
|
||||
continue;
|
||||
}
|
||||
if (isChinesePunctuation(c)) {
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
+5
-7
@@ -18,8 +18,6 @@ public class XssUtil {
|
||||
public static String xssEncode(String s) {
|
||||
if (s == null || s.isEmpty()) {
|
||||
return s;
|
||||
} else {
|
||||
s = stripXSSAndSql(s);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(s.length() + 16);
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
@@ -31,13 +29,13 @@ public class XssUtil {
|
||||
case '<':
|
||||
sb.append("<");// 转义小于号
|
||||
break;
|
||||
case '\'':
|
||||
/*case '\'':
|
||||
sb.append("'");// 转义单引号
|
||||
break;
|
||||
case '\"':
|
||||
sb.append(""");// 转义双引号
|
||||
break;
|
||||
/*case '&':
|
||||
case '&':
|
||||
sb.append("&");// 转义&
|
||||
break;
|
||||
case '#':
|
||||
@@ -48,7 +46,7 @@ public class XssUtil {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
return stripXSSAndSql(sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +62,7 @@ public class XssUtil {
|
||||
scriptPattern7 = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE),
|
||||
scriptPattern8 = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE),
|
||||
scriptPattern9 = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
scriptPattern10 = Pattern.compile("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|and|or|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|union|where|limit|group by|hex|set)\\b)", Pattern.CASE_INSENSITIVE),
|
||||
scriptPattern10 = Pattern.compile("(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(update|delete|select|insert|trancate|char|into|substr|ascii|declare|exec|count|master|drop|execute|union|where|limit|group by|hex)\\b)", Pattern.CASE_INSENSITIVE),
|
||||
scriptPattern11 = Pattern.compile("\\*\\/(\\s|.)*?\\/\\*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
|
||||
|
||||
private static String stripXSSAndSql(String value) {
|
||||
@@ -88,7 +86,7 @@ public class XssUtil {
|
||||
// Avoid onload= expressions
|
||||
value = scriptPattern9.matcher(value).replaceAll(REPLACE_STRING);
|
||||
// Avoid sql= expressions
|
||||
value = scriptPattern10.matcher(value).replaceAll(REPLACE_STRING);
|
||||
//value = scriptPattern10.matcher(value).replaceAll(REPLACE_STRING);
|
||||
// Avoid */xxx/*(...) expressions
|
||||
value = scriptPattern11.matcher(value).replaceAll(REPLACE_STRING);
|
||||
}
|
||||
|
||||
+7
@@ -7,10 +7,17 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*/
|
||||
@Slf4j
|
||||
public class DbFileConstant {
|
||||
|
||||
/**
|
||||
* 公共根路径代码
|
||||
*/
|
||||
public static final String PUBLIC_ROOT_PATH_CODE = "public";
|
||||
|
||||
/**
|
||||
* JPEG上下文类型
|
||||
*/
|
||||
public static final String CONTENT_TYPE_JPEG = "image/jpeg";
|
||||
|
||||
/**
|
||||
* PNG上下文类型
|
||||
*/
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package org.itkk.udf.starter.file.db.web;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.itkk.udf.starter.core.CoreConstant;
|
||||
import org.itkk.udf.starter.core.CoreProperties;
|
||||
import org.itkk.udf.starter.core.exception.ParameterValidException;
|
||||
import org.itkk.udf.starter.file.db.DbFileProperties;
|
||||
import org.itkk.udf.starter.file.db.dto.DbFileInfoDto;
|
||||
import org.itkk.udf.starter.file.db.service.DbFileService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public abstract class DbFileBase {
|
||||
|
||||
/**
|
||||
* dbFileService
|
||||
*/
|
||||
@Autowired
|
||||
protected DbFileService dbFileService;
|
||||
|
||||
/**
|
||||
* dbFileProperties
|
||||
*/
|
||||
@Autowired
|
||||
protected DbFileProperties dbFileProperties;
|
||||
|
||||
/**
|
||||
* coreProperties
|
||||
*/
|
||||
@Autowired
|
||||
protected CoreProperties coreProperties;
|
||||
|
||||
/**
|
||||
* response
|
||||
*/
|
||||
@Autowired
|
||||
protected HttpServletResponse response;
|
||||
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
@Autowired
|
||||
protected HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* 设置头信息
|
||||
*
|
||||
* @param id id
|
||||
* @param preview preview
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
protected void setResponseHeader(String id, Boolean preview) throws UnsupportedEncodingException {
|
||||
//获得文件信息
|
||||
DbFileInfoDto fileInfo = dbFileService.get(id);
|
||||
//判空
|
||||
if (fileInfo == null) {
|
||||
throw new ParameterValidException("文件" + id + "不存在");
|
||||
}
|
||||
//rootPath判空
|
||||
if (MapUtils.isEmpty(dbFileProperties.getMapping()) || !dbFileProperties.getMapping().containsKey(fileInfo.getRootPathCode())) {
|
||||
throw new ParameterValidException("文件路径映射" + fileInfo.getRootPathCode() + "不存在");
|
||||
}
|
||||
//清空response
|
||||
response.reset();
|
||||
//设置response
|
||||
response.setContentLengthLong(fileInfo.getFileSize());
|
||||
response.setCharacterEncoding(CoreConstant.CHARACTER_SET);
|
||||
response.setContentType(fileInfo.getContentType());
|
||||
response.setDateHeader("Expires", 0L);
|
||||
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
//response.addHeader("Cache-Control", "post-check=0, pre-check=0");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
//判断是否预览 (预览则要限定一下上下文类型){
|
||||
if (preview) {
|
||||
if (StringUtils.isNotBlank(dbFileProperties.getPreviewSupportContentType())) {
|
||||
if (!dbFileProperties.getPreviewSupportContentType().contains(fileInfo.getContentType())) {
|
||||
throw new ParameterValidException("不支持[" + fileInfo.getContentType() + "]此上下文类型的预览");
|
||||
}
|
||||
}
|
||||
}
|
||||
//判断是否预览 (预览则不用设置文件名)
|
||||
if (!preview) {
|
||||
//设置文件名
|
||||
String fileName = URLEncoder.encode(fileInfo.getFileName(), CoreConstant.CHARACTER_SET);
|
||||
if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
|
||||
} else {
|
||||
response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-90
@@ -1,57 +1,16 @@
|
||||
package org.itkk.udf.starter.file.db.web;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.itkk.udf.starter.core.CoreConstant;
|
||||
import org.itkk.udf.starter.core.CoreProperties;
|
||||
import org.itkk.udf.starter.core.RestResponse;
|
||||
import org.itkk.udf.starter.core.exception.ParameterValidException;
|
||||
import org.itkk.udf.starter.file.db.DbFileProperties;
|
||||
import org.itkk.udf.starter.file.db.dto.DbFileInfoDto;
|
||||
import org.itkk.udf.starter.file.db.service.DbFileService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class DbFileBaseController {
|
||||
|
||||
/**
|
||||
* dbFileService
|
||||
*/
|
||||
@Autowired
|
||||
private DbFileService dbFileService;
|
||||
|
||||
/**
|
||||
* dbFileProperties
|
||||
*/
|
||||
@Autowired
|
||||
private DbFileProperties dbFileProperties;
|
||||
|
||||
/**
|
||||
* coreProperties
|
||||
*/
|
||||
@Autowired
|
||||
private CoreProperties coreProperties;
|
||||
|
||||
/**
|
||||
* response
|
||||
*/
|
||||
@Autowired
|
||||
private HttpServletResponse response;
|
||||
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
public abstract class DbFileBaseController extends DbFileBase {
|
||||
|
||||
/**
|
||||
* 获得当前用户ID
|
||||
@@ -144,52 +103,4 @@ public abstract class DbFileBaseController {
|
||||
dbFileService.delete(id);
|
||||
return RestResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置头信息
|
||||
*
|
||||
* @param id id
|
||||
* @param preview preview
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private void setResponseHeader(String id, Boolean preview) throws UnsupportedEncodingException {
|
||||
//获得文件信息
|
||||
DbFileInfoDto fileInfo = dbFileService.get(id);
|
||||
//判空
|
||||
if (fileInfo == null) {
|
||||
throw new ParameterValidException("文件" + id + "不存在");
|
||||
}
|
||||
//rootPath判空
|
||||
if (MapUtils.isEmpty(dbFileProperties.getMapping()) || !dbFileProperties.getMapping().containsKey(fileInfo.getRootPathCode())) {
|
||||
throw new ParameterValidException("文件路径映射" + fileInfo.getRootPathCode() + "不存在");
|
||||
}
|
||||
//清空response
|
||||
response.reset();
|
||||
//设置response
|
||||
response.setContentLengthLong(fileInfo.getFileSize());
|
||||
response.setCharacterEncoding(CoreConstant.CHARACTER_SET);
|
||||
response.setContentType(fileInfo.getContentType());
|
||||
response.setDateHeader("Expires", 0L);
|
||||
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
//response.addHeader("Cache-Control", "post-check=0, pre-check=0");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
//判断是否预览 (预览则要限定一下上下文类型){
|
||||
if (preview) {
|
||||
if (StringUtils.isNotBlank(dbFileProperties.getPreviewSupportContentType())) {
|
||||
if (!dbFileProperties.getPreviewSupportContentType().contains(fileInfo.getContentType())) {
|
||||
throw new ParameterValidException("不支持[" + fileInfo.getContentType() + "]此上下文类型的预览");
|
||||
}
|
||||
}
|
||||
}
|
||||
//判断是否预览 (预览则不用设置文件名)
|
||||
if (!preview) {
|
||||
//设置文件名
|
||||
String fileName = URLEncoder.encode(fileInfo.getFileName(), CoreConstant.CHARACTER_SET);
|
||||
if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
|
||||
} else {
|
||||
response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
package org.itkk.udf.starter.file.db.web;
|
||||
|
||||
import org.itkk.udf.starter.core.exception.SystemRuntimeException;
|
||||
import org.itkk.udf.starter.file.db.dto.WopiFileInfo;
|
||||
import org.itkk.udf.starter.file.db.service.DbFileService;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public abstract class WopiBaseContrller {
|
||||
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* response
|
||||
*/
|
||||
@Autowired
|
||||
private HttpServletResponse response;
|
||||
|
||||
/**
|
||||
* dbFileService
|
||||
*/
|
||||
@Autowired
|
||||
private DbFileService dbFileService;
|
||||
|
||||
/**
|
||||
* 获取文件流
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
@GetMapping("files/{name}/contents")
|
||||
public void getFile(@PathVariable String name) {
|
||||
final String utf8 = "UTF-8";
|
||||
final String iso88591 = "ISO-8859-1";
|
||||
InputStream fis = null;
|
||||
OutputStream toClient = null;
|
||||
try {
|
||||
// 获得文件
|
||||
File file = dbFileService.getFile(name);
|
||||
// 取得文件名
|
||||
String filename = file.getName();
|
||||
// 以流的形式下载文件
|
||||
fis = new BufferedInputStream(new FileInputStream(file));
|
||||
byte[] buffer = new byte[fis.available()];
|
||||
fis.read(buffer);
|
||||
// 清空response
|
||||
response.reset();
|
||||
// 设置response的Header
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes(utf8), iso88591));
|
||||
response.addHeader("Content-Length", "" + file.length());
|
||||
toClient = new BufferedOutputStream(response.getOutputStream());
|
||||
response.setContentType("application/octet-stream");
|
||||
toClient.write(buffer);
|
||||
toClient.flush();
|
||||
} catch (Exception e) {
|
||||
throw new SystemRuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
if (toClient != null) {
|
||||
toClient.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SystemRuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param name name
|
||||
* @return WopiFileInfo
|
||||
*/
|
||||
@RequestMapping("files/{name}")
|
||||
public WopiFileInfo getFileInfo(@PathVariable String name) {
|
||||
//定义返回值
|
||||
WopiFileInfo info = null;
|
||||
//获得文件
|
||||
File file = dbFileService.getFile(name);
|
||||
//判空
|
||||
if (file.exists()) {
|
||||
//实例化
|
||||
info = new WopiFileInfo();
|
||||
//填充文件信息
|
||||
info.setBaseFileName(file.getName());
|
||||
info.setSize(file.length());
|
||||
info.setOwnerId("admin");
|
||||
info.setVersion(file.lastModified());
|
||||
info.setSha256(getHash256(file));
|
||||
info.setAllowExternalMarketplace(false);
|
||||
info.setUserCanWrite(false);
|
||||
info.setSupportsUpdate(false);
|
||||
info.setSupportsLocks(false);
|
||||
info.setDisablePrint(true);
|
||||
info.setDisableTranslation(true);
|
||||
info.setUserCanNotWriteRelative(true);
|
||||
}
|
||||
//返回
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的SHA-256值
|
||||
*
|
||||
* @param file file
|
||||
* @return String
|
||||
*/
|
||||
private String getHash256(File file) {
|
||||
String value = "";
|
||||
// 获取hash值
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int numRead;
|
||||
InputStream fis = new FileInputStream(file);
|
||||
//如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256
|
||||
MessageDigest complete = MessageDigest.getInstance("SHA-256");
|
||||
do {
|
||||
//从文件读到buffer
|
||||
numRead = fis.read(buffer);
|
||||
if (numRead > 0) {
|
||||
//用读到的字节进行MD5的计算,第二个参数是偏移量
|
||||
complete.update(buffer, 0, numRead);
|
||||
}
|
||||
} while (numRead != -1);
|
||||
|
||||
fis.close();
|
||||
value = new String(Base64.encodeBase64(complete.digest()));
|
||||
} catch (Exception e) {
|
||||
throw new SystemRuntimeException(e);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user