From c72c3d671bc7e9f56d03c34e46b50b4307e4a31e Mon Sep 17 00:00:00 2001 From: pioneer Date: Tue, 6 Dec 2022 16:07:13 +0800 Subject: [PATCH] open --- README.md | 6 + plugin.xml | 25 ++ .../java/com/hzdatalink/gsdes/Constants.java | 9 + .../gsdes/EncodeExportExtensionProvider.java | 39 +++ .../com/hzdatalink/gsdes/FileOperation.java | 226 ++++++++++++++++++ .../gsdes/GetFileCLIInfoResult.java | 71 ++++++ .../hzdatalink/gsdes/GetFileInfoResult.java | 53 ++++ .../gsdes/IsFileEncryptedResult.java | 29 +++ .../java/com/hzdatalink/gsdes/Result.java | 23 ++ .../BodyReaderHttpServletRequestWrapper.java | 63 +++++ .../gsdes/export/EncryptExporter.java | 85 +++++++ .../gsdes/export/EncryptOutputStream.java | 104 ++++++++ .../hzdatalink/gsdes/filter/DecodeFilter.java | 115 +++++++++ .../hzdatalink/gsdes/filter/GlobalFilter.java | 94 ++++++++ .../com/hzdatalink/gsdes/util/FileUtil.java | 36 +++ 15 files changed, 978 insertions(+) create mode 100644 README.md create mode 100644 plugin.xml create mode 100644 src/main/java/com/hzdatalink/gsdes/Constants.java create mode 100644 src/main/java/com/hzdatalink/gsdes/EncodeExportExtensionProvider.java create mode 100644 src/main/java/com/hzdatalink/gsdes/FileOperation.java create mode 100644 src/main/java/com/hzdatalink/gsdes/GetFileCLIInfoResult.java create mode 100644 src/main/java/com/hzdatalink/gsdes/GetFileInfoResult.java create mode 100644 src/main/java/com/hzdatalink/gsdes/IsFileEncryptedResult.java create mode 100644 src/main/java/com/hzdatalink/gsdes/Result.java create mode 100644 src/main/java/com/hzdatalink/gsdes/bean/BodyReaderHttpServletRequestWrapper.java create mode 100644 src/main/java/com/hzdatalink/gsdes/export/EncryptExporter.java create mode 100644 src/main/java/com/hzdatalink/gsdes/export/EncryptOutputStream.java create mode 100644 src/main/java/com/hzdatalink/gsdes/filter/DecodeFilter.java create mode 100644 src/main/java/com/hzdatalink/gsdes/filter/GlobalFilter.java create mode 100644 src/main/java/com/hzdatalink/gsdes/util/FileUtil.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..f883824 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# open-JSD-10257 + +JSD-10257 excel加密文件导入自动解密导出\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..e32a601 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,25 @@ + + com.fr.plugin.xx.ygkj.encode + com.hzdatalink.gsdes + + yes + 1.4 + 10.0 + 2018-07-31 + fr.open + + + [2022-06-20]【1.1】增加导入解密。
+ [2022-06-21]【1.2】增加填报导入支持。
+ [2022-06-21]【1.3】保留解密文件。
+ [2022-07-29]【1.4】兼容标记导入。
+ ]]>
+ + + + + + + +
\ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/Constants.java b/src/main/java/com/hzdatalink/gsdes/Constants.java new file mode 100644 index 0000000..a827c26 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/Constants.java @@ -0,0 +1,9 @@ +package com.hzdatalink.gsdes; + +/** + * @author xx + * @date 2020/11/20 + */ +public class Constants { + public static final String PLUGIN_ID = "com.fr.plugin.xx.ygkj.encode"; +} diff --git a/src/main/java/com/hzdatalink/gsdes/EncodeExportExtensionProvider.java b/src/main/java/com/hzdatalink/gsdes/EncodeExportExtensionProvider.java new file mode 100644 index 0000000..0498102 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/EncodeExportExtensionProvider.java @@ -0,0 +1,39 @@ +package com.hzdatalink.gsdes; + +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.Original; +import com.fr.io.collection.ExportCollection; +import com.fr.io.exporter.AppExporter; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.record.analyzer.EnableMetrics; +import com.fr.stable.fun.Authorize; +import com.fr.web.core.ReportSessionIDInfor; +import com.fr.web.core.reserve.DefaultExportExtension; +import com.hzdatalink.gsdes.export.EncryptExporter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @Author xx + * @Date 2021/11/23 + * @Description + **/ +@FunctionRecorder +@Authorize(callSignKey = Constants.PLUGIN_ID) +@EnableMetrics +public class EncodeExportExtensionProvider extends DefaultExportExtension { + + @Override + @Focus(id = Constants.PLUGIN_ID, text = "xx加密", source = Original.PLUGIN) + public ExportCollection createCollection(HttpServletRequest req, HttpServletResponse res, + ReportSessionIDInfor info, String format, String filename, boolean isEmbed) throws Exception { + ExportCollection collection = super.createCollection(req, res, info, format, filename, isEmbed); + AppExporter exporter = collection.getExporter(); + if (PluginContexts.currentContext().isAvailable()) { + collection.setExporter(new EncryptExporter(exporter)); + } + return collection; + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/FileOperation.java b/src/main/java/com/hzdatalink/gsdes/FileOperation.java new file mode 100644 index 0000000..76a5c30 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/FileOperation.java @@ -0,0 +1,226 @@ +// GS-EDS加解密接口包,注意:不可修改包名! +package com.hzdatalink.gsdes; + +import com.fr.log.FineLoggerFactory; + +public class FileOperation { + // DEMO命令行程序入口 + public static void main(String[] args) { + if (args.length == 0) { + System.out.println("请在命令行传入测试目标文件路径."); + return; + } + + // 测试文件 + String fileName = args[0]; + System.out.println(String.format("开始测试文件加解密: %s.", fileName)); + + testFileEncDec(fileName); + testFileInfo(fileName); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + + // 文件加密 + public static Result encodeFile(String srcFileName, // 源文件名 + String dstFileName // 目标文件名 + ) { + return jniEncodeFile(srcFileName, dstFileName); + } + + // 文件解密 + public static Result decodeFile(String srcFileName, // 源文件名 + String dstFileName // 目标文件名 + ) { + return jniDecodeFile(srcFileName, dstFileName); + } + + // 判断文件是否加密函数声明 + public static IsFileEncryptedResult isFileEncrypted(String fileName // 文件名 + ) { + return jniIsFileEncrypted(fileName); + } + + // 获取文件信息函数声明 + public static GetFileInfoResult getFileInfo(String fileName // 文件名 + ) { + return jniGetFileInfo(fileName); + } + + // 获取标密文件信息 + public static GetFileCLIInfoResult getFileCLIInfo(String fileName // 文件名 + ) { + return jniGetFileCLIInfo(fileName); + } + + // 设置加密文件信息 + public static Result setFileInfo(String fileName, // 文件名 + int userOID, // 文件所属用户OID + int orgOID, // 文件所属组织ID + int clID, // 文件密级 + int fileId // 文件ID + ) { + return jniSetFileInfo(fileName, userOID, orgOID, clID, fileId); + } + + // 设置标密文件信息 + public static Result setFileCLIInfo(String fileName, // 文件名 + int userOID, // 文件所属用户OID + int orgOID, // 文件所属组织ID + int clID, // 文件密级 + int fileId, // 文件ID + int sp, // 文件保密期限 + int cliTime, // 文件标密时间 + String fileUUID // 文件UUID + ) { + return jniSetFileCLIInfo(fileName, userOID, orgOID, clID, fileId, sp, cliTime, fileUUID); + } + + //////////////////////////////////////////////////////////////////// + // 加载libGsDes.so + static { + String os = System.getProperty("os.name"); + //Windows操作系统 + if (os != null && os.toLowerCase().startsWith("windows")) { + FineLoggerFactory.getLogger().info("current system is win"); + System.loadLibrary("gsedsapi"); + } else if (os != null && os.toLowerCase().startsWith("linux")) { + FineLoggerFactory.getLogger().info("current system is linux"); + System.loadLibrary("GsDes"); + } else { //其它操作系统 + FineLoggerFactory.getLogger().info("not support system"); + } + } + + // 文件加密函数声明 + public static native Result jniEncodeFile(String srcFileName, // 源文件名 + String dstFileName // 目标文件名 + ); + + // 文件解密函数声明 + public static native Result jniDecodeFile(String srcFileName, // 源文件名 + String dstFileName // 目标文件名 + ); + + // 判断文件是否加密函数声明 + public static native IsFileEncryptedResult jniIsFileEncrypted(String fileName // 文件名 + ); + + // 获取文件信息函数声明 + public static native GetFileInfoResult jniGetFileInfo(String fileName // 文件名 + ); + + // 获取标密文件信息 + public static native GetFileCLIInfoResult jniGetFileCLIInfo(String fileName // 文件名 + ); + + // 设置加密文件信息 + public static native Result jniSetFileInfo(String fileName, // 文件名 + int userOID, // 文件所属用户OID + int orgOID, // 文件所属组织ID + int clID, // 文件密级 + int fileId // 文件ID + ); + + // 设置标密文件信息 + public static native Result jniSetFileCLIInfo(String fileName, // 文件名 + int userOID, // 文件所属用户OID + int orgOID, // 文件所属组织ID + int clID, // 文件密级 + int fileId, // 文件ID + int sp, // 文件保密期限 + int cliTime, // 文件标密时间 + String fileUUID // 文件UUID + ); + + private static void testFileEncDec(String fileName) { + Result result; + + // 解密文件 + result = decodeFile(fileName, fileName); + if (result.getSucceeded()) { + System.out.println("解密文件成功."); + } else { + System.out.println(String.format("解密文件失败, %s", result.getMessage())); + } + + // 加密文件 + result = encodeFile(fileName, fileName); + if (result.getSucceeded()) { + System.out.println("加密文件成功."); + } else { + System.out.println(String.format("加密文件失败, %s", result.getMessage())); + return; + } + + // 校验文件是否加密 + IsFileEncryptedResult isEnc = isFileEncrypted(fileName); + if (isEnc.getSucceeded()) { + System.out.println(String.format("检查文件是否加密成功, 文件%s.", (isEnc.getEncrypted() ? "已加密" : "未加密"))); + } else { + System.out.println(String.format("检查文件是否加密失败, %s", isEnc.getMessage())); + return; + } + + // 解密文件 + result = decodeFile(fileName, fileName); + if (result.getSucceeded()) { + System.out.println("解密文件成功."); + } else { + System.out.println(String.format("解密文件失败, %s", result.getMessage())); + } + } + + private static void testFileInfo(String fileName) { + // 加密文件 + Result result = encodeFile(fileName, fileName); + if (result.getSucceeded()) { + System.out.println("加密文件成功."); + } else { + System.out.println(String.format("加密文件失败, %s", result.getMessage())); + return; + } + + // 设置文件信息 + result = setFileInfo(fileName, 1026, 6, 5, 0); + if (result.getSucceeded()) { + System.out.println("设置文件信息成功."); + } else { + System.out.println(String.format("设置文件信息失败, %s", result.getMessage())); + } + + // 获取文件信息 + GetFileInfoResult fileInfo = getFileInfo(fileName); + if (fileInfo.getSucceeded()) { + System.out.println(String.format("获取文件信息成功, 文件%s, User:%d, Org:%d, cl:%d, fileid:%d.", + (fileInfo.getEncrypted() ? "已加密" : "未加密"), fileInfo.getUserOID(), fileInfo.getOrgOID(), + fileInfo.getCLID(), fileInfo.getFileID())); + } else { + System.out.println(String.format("获取文件信息失败, %s", fileInfo.getMessage())); + } + + // 获取标密文件信息 + GetFileCLIInfoResult fileCliInfo = getFileCLIInfo(fileName); + if (fileCliInfo.getSucceeded()) { + System.out.println(String.format( + "获取标密文件信息成功, 文件%s, User:%d, Org:%d, cl:%d, sp:%d, cliTime:%d, fileUuid:%s.", + (fileCliInfo.getEncrypted() ? "已加密" : "未加密"), fileCliInfo.getUserOID(), fileCliInfo.getOrgOID(), + fileCliInfo.getCLID(), fileCliInfo.getSP(), fileCliInfo.getCLITime(), fileCliInfo.getFileUUID())); + } else { + System.out.println(String.format("获取标密文件信息失败, %s", fileCliInfo.getMessage())); + } + + // 设置标密文件信息 + result = setFileCLIInfo(fileName, // 文件名 + fileCliInfo.getUserOID(), fileCliInfo.getOrgOID(), fileCliInfo.getCLID(), fileCliInfo.getFileId(), + fileCliInfo.getSP(), fileCliInfo.getCLITime(), fileCliInfo.getFileUUID()); + if (result.getSucceeded()) { + System.out.println("设置文件信息成功."); + } else { + System.out.println(String.format("设置文件信息失败, %s", result.getMessage())); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/GetFileCLIInfoResult.java b/src/main/java/com/hzdatalink/gsdes/GetFileCLIInfoResult.java new file mode 100644 index 0000000..6ad76d7 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/GetFileCLIInfoResult.java @@ -0,0 +1,71 @@ +// GS-EDS加解密接口包,注意:不可修改包名! +package com.hzdatalink.gsdes; + +// GetFileCLIInfo 函数返回结果 +public class GetFileCLIInfoResult { + + private String message; // 是否成功 + private boolean succeeded; // 失败信息 + private boolean encrypted; // 文件是否加密 + private int userOID; // 文件所属用户OID + private int orgOID; // 文件所属组织ID + private int clID; // 文件密级 + private short sp; // 文件保密期限 + private int cliTime; // 文件标密时间 + private String fileUUID; // 文件UUID + private int fileID; // 文件ID + + public GetFileCLIInfoResult() { + this.succeeded = false; + } + + // 是否成功 + public boolean getSucceeded() { + return succeeded; + } + + // 失败信息 + public String getMessage() { + return message; + } + + // 文件是否加密 + public boolean getEncrypted() { + return encrypted; + } + + // 文件所属用户OID + public int getUserOID() { + return userOID; + } + + // 文件所属组织ID + public int getOrgOID() { + return orgOID; + } + + // 文件密级 + public int getCLID() { + return clID; + } + + // 文件ID + public int getFileId() { + return fileID; + } + + // 文件保密期限 + public short getSP() { + return sp; + } + + // 文件标密时间 + public int getCLITime() { + return cliTime; + } + + // 文件UUID + public String getFileUUID() { + return fileUUID; + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/GetFileInfoResult.java b/src/main/java/com/hzdatalink/gsdes/GetFileInfoResult.java new file mode 100644 index 0000000..6c6fdf5 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/GetFileInfoResult.java @@ -0,0 +1,53 @@ +// GS-EDS加解密接口包,注意:不可修改包名! +package com.hzdatalink.gsdes; + +// GetFileInfo 函数返回结果 +public class GetFileInfoResult { + + private String message; // 是否成功 + private boolean succeeded; // 失败信息 + private boolean encrypted; // 文件是否加密 + private int userOID; // 文件所属用户OID + private int orgOID; // 文件所属组织ID + private int clID; // 文件密级 + private int fileID; // 文件ID + + public GetFileInfoResult() { + this.succeeded = false; + } + + // 是否成功 + public boolean getSucceeded() { + return succeeded; + } + + // 失败信息 + public String getMessage() { + return message; + } + + // 文件是否加密 + public boolean getEncrypted() { + return encrypted; + } + + // 文件所属用户OID + public int getUserOID() { + return userOID; + } + + // 文件所属组织ID + public int getOrgOID() { + return orgOID; + } + + // 文件密级 + public int getCLID() { + return clID; + } + + // 文件ID + public int getFileID() { + return fileID; + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/IsFileEncryptedResult.java b/src/main/java/com/hzdatalink/gsdes/IsFileEncryptedResult.java new file mode 100644 index 0000000..e97e552 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/IsFileEncryptedResult.java @@ -0,0 +1,29 @@ +// GS-EDS加解密接口包,注意:不可修改包名! +package com.hzdatalink.gsdes; + +// IsFileEncrypted 返回结果 +public class IsFileEncryptedResult { + + private String message; // 是否成功 + private boolean succeeded; // 失败信息 + private boolean encrypted; // 是否加密 + + public IsFileEncryptedResult() { + this.succeeded = false; + } + + // 是否成功 + public boolean getSucceeded() { + return succeeded; + } + + // 失败信息 + public String getMessage() { + return message; + } + + // 是否加密 + public boolean getEncrypted() { + return encrypted; + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/Result.java b/src/main/java/com/hzdatalink/gsdes/Result.java new file mode 100644 index 0000000..149a9cf --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/Result.java @@ -0,0 +1,23 @@ +// GS-EDS加解密接口包,注意:不可修改包名! +package com.hzdatalink.gsdes; + +// 通用返回结果 +public class Result { + + private String message; // 是否成功 + private boolean succeeded; // 失败信息 + + public Result() { + this.succeeded = false; + } + + // 是否成功 + public boolean getSucceeded() { + return succeeded; + } + + // 失败信息 + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/bean/BodyReaderHttpServletRequestWrapper.java b/src/main/java/com/hzdatalink/gsdes/bean/BodyReaderHttpServletRequestWrapper.java new file mode 100644 index 0000000..9860df8 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/bean/BodyReaderHttpServletRequestWrapper.java @@ -0,0 +1,63 @@ +package com.hzdatalink.gsdes.bean; + +import com.fr.third.jodd.io.StreamUtil; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * @author xx + * @date 2020/11/20 + */ +public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { + private BufferedReader br; + private byte[] body; + public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { + super(request); + //this.br = request.getReader(); + body = StreamUtil.readBytes(request.getInputStream()); + } + + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + + @Override + public int read() throws IOException { + return bais.read(); + } + }; + } + + public void setBody(byte[] body) { + this.body = body; + } +} diff --git a/src/main/java/com/hzdatalink/gsdes/export/EncryptExporter.java b/src/main/java/com/hzdatalink/gsdes/export/EncryptExporter.java new file mode 100644 index 0000000..2cfa2bf --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/export/EncryptExporter.java @@ -0,0 +1,85 @@ +package com.hzdatalink.gsdes.export; + +import com.fr.general.CommonIOUtils; +import com.fr.io.exporter.AppExporter; +import com.fr.log.FineLoggerFactory; +import com.fr.main.workbook.ResultWorkBook; +import com.fr.page.PageSetCreator; +import com.fr.page.PageSetProvider; +import com.fr.web.core.ReportRepositoryDeal; +import com.hzdatalink.gsdes.FileOperation; +import com.hzdatalink.gsdes.util.FileUtil; + +import java.io.*; + +/** + * @Author xx + * @Date 2021/11/23 + * @Description + **/ +public class EncryptExporter implements AppExporter { + + private AppExporter original; + + public EncryptExporter(AppExporter original) { + this.original = original; + } + + + @Override + public void export(OutputStream out, ResultWorkBook book) throws Exception { + ByteArrayOutputStream encryptOutputStream = new ByteArrayOutputStream(); + original.export(encryptOutputStream, book); + this.encrypt(encryptOutputStream.toByteArray(),out); + } + + @Override + public void export(OutputStream out, PageSetProvider pageSet) throws Exception { + ByteArrayOutputStream encryptOutputStream = new ByteArrayOutputStream(); + original.export(encryptOutputStream, pageSet); + this.encrypt(encryptOutputStream.toByteArray(),out); + } + + @Override + public void export(OutputStream out, ResultWorkBook book, PageSetCreator creator, ReportRepositoryDeal repo, int[] sheets) throws Exception { + ByteArrayOutputStream encryptOutputStream = new ByteArrayOutputStream(); + original.export(encryptOutputStream, book, creator, repo, sheets); + this.encrypt(encryptOutputStream.toByteArray(),out); + } + + @Override + public void export(OutputStream out, ResultWorkBook book, PageSetProvider pageSet, ReportRepositoryDeal repo, int[] sheets) throws Exception { + ByteArrayOutputStream encryptOutputStream = new ByteArrayOutputStream(); + original.export(encryptOutputStream, book, pageSet, repo, sheets); + this.encrypt(encryptOutputStream.toByteArray(),out); + } + + @Override + public void setVersion(Object o) { + original.setVersion(o); + } + + private void encrypt(byte[] bytes,OutputStream outputStream) throws IOException { + FileOutputStream fileOutputStream = null; + try { + File tempFile = FileUtil.createTempFile(); + File encodeFile = FileUtil.createTempFile(); + fileOutputStream = new FileOutputStream(tempFile); + fileOutputStream.write(bytes); + fileOutputStream.flush(); + FileOperation.encodeFile(tempFile.getAbsolutePath(), encodeFile.getAbsolutePath()); + byte[] encodeByte = CommonIOUtils.inputStream2Bytes(new FileInputStream(encodeFile)); + tempFile.deleteOnExit(); + encodeFile.deleteOnExit(); + outputStream.write(encodeByte); + outputStream.flush(); + outputStream.close(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + if (fileOutputStream != null) { + fileOutputStream.close(); + } + } + } +} diff --git a/src/main/java/com/hzdatalink/gsdes/export/EncryptOutputStream.java b/src/main/java/com/hzdatalink/gsdes/export/EncryptOutputStream.java new file mode 100644 index 0000000..0bc2836 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/export/EncryptOutputStream.java @@ -0,0 +1,104 @@ +package com.hzdatalink.gsdes.export; + +import com.fr.general.CommonIOUtils; +import com.fr.log.FineLoggerFactory; +import com.hzdatalink.gsdes.FileOperation; +import com.hzdatalink.gsdes.util.FileUtil; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import java.io.*; + +/** + * @Author xx + * @Date 2021/11/23 + * @Description + **/ +public class EncryptOutputStream extends ServletOutputStream { + + private OutputStream original = null; + private boolean closed = false; + private ByteArrayOutputStream crypt = new ByteArrayOutputStream(); + + public EncryptOutputStream(OutputStream original) { + this.original = original; + } + + /** + * 实际加密的代码就在这里实现了 + * + * @param bytes + * @return + */ + private byte[] encrypt(byte[] bytes) throws IOException { + FileOutputStream fileOutputStream = null; + try { + File tempFile = FileUtil.createTempFile(); + File encodeFile = FileUtil.createTempFile(); + fileOutputStream = new FileOutputStream(tempFile); + fileOutputStream.write(bytes); + fileOutputStream.flush(); + FileOperation.encodeFile(tempFile.getAbsolutePath(), encodeFile.getAbsolutePath()); + byte[] encodeByte = CommonIOUtils.inputStream2Bytes(new FileInputStream(encodeFile)); + tempFile.deleteOnExit(); + encodeFile.deleteOnExit(); + return encodeByte; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + if (fileOutputStream != null) { + fileOutputStream.close(); + } + } + return bytes; + } + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Cannot write to a closed output stream"); + } + crypt.write(b); + } + + @Override + public void close() throws IOException { + if (!closed) { + byte[] bytes = crypt.toByteArray(); + bytes = encrypt(bytes); + original.write(bytes); + original.flush(); + original.close(); + closed = true; + } + } + + @Override + public void flush() throws IOException { + crypt.flush(); + } + + @Override + public void write(byte[] data) throws IOException { + write(data, 0, data.length); + } + + @Override + public void write(byte[] data, int off, int len) throws IOException { + if (closed) { + throw new IOException("Cannot write to a closed output stream"); + } + crypt.write(data, off, len); + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener listener) { + + } + +} \ No newline at end of file diff --git a/src/main/java/com/hzdatalink/gsdes/filter/DecodeFilter.java b/src/main/java/com/hzdatalink/gsdes/filter/DecodeFilter.java new file mode 100644 index 0000000..0bf4ec9 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/filter/DecodeFilter.java @@ -0,0 +1,115 @@ +package com.hzdatalink.gsdes.filter; + +import com.fr.base.ServerConfig; +import com.fr.base.core.IgnoreBytesInputStream; +import com.fr.base.core.ParseResult; +import com.fr.base.core.PostParseUtils; +import com.fr.general.CommonIOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.third.org.apache.commons.io.IOUtils; +import com.fr.web.utils.WebUtils; +import com.hzdatalink.gsdes.FileOperation; +import com.hzdatalink.gsdes.IsFileEncryptedResult; +import com.hzdatalink.gsdes.bean.BodyReaderHttpServletRequestWrapper; +import com.hzdatalink.gsdes.util.FileUtil; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; + +/** + * @author xx + * @date 2020/11/20 + */ +public class DecodeFilter { + private static final byte[] NEW_LINE_BYTES = new byte[]{13, 10}; + private static final byte[] BOUNDARY_END = new byte[]{45, 45}; + + private static final String TMP_PATH = System.getProperty("java.io.tmpdir"); + + public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { + try { + FineLoggerFactory.getLogger().info("decode request uri: {}", req.getRequestURI()); + BodyReaderHttpServletRequestWrapper wrapper = new BodyReaderHttpServletRequestWrapper(req); + InputStream inputStream = wrapper.getInputStream(); + ParseResult parseResult = PostParseUtils.parse(inputStream, req.getCharacterEncoding()); + InputStream fileDecorator = new IgnoreBytesInputStream(inputStream, this.concat(this.concat(NEW_LINE_BYTES, parseResult.getBoundary().getBytes()), BOUNDARY_END)); + String filename = WebUtils.getHTTPRequestParameter(req, "filename"); + File file = saveTmp(fileDecorator, filename); + FineLoggerFactory.getLogger().info("record file to {}", file.getPath()); + byte[] bytes = null; + IsFileEncryptedResult encode = FileOperation.isFileEncrypted(file.getAbsolutePath()); + FineLoggerFactory.getLogger().info("isFileEncrypted res is {}", encode.getSucceeded()); + if (encode != null && encode.getEncrypted()) { + FineLoggerFactory.getLogger().info("current file is encode file"); + File decodeFile = FileUtil.createTempFile(); + FineLoggerFactory.getLogger().info("decode file path is {}",decodeFile.getAbsolutePath()); + FileOperation.decodeFile(file.getAbsolutePath(), decodeFile.getAbsolutePath()); + bytes = CommonIOUtils.inputStream2Bytes(new FileInputStream(decodeFile)); + decodeFile.deleteOnExit(); + } + if (bytes == null) { + FineLoggerFactory.getLogger().info("current file is not decode"); + } else { + FineLoggerFactory.getLogger().info("decode file byte size is {}", bytes.length); + byte[] body = null; + String character = req.getCharacterEncoding(); + if (StringUtils.isNotEmpty(character)) { + body = handleBody(bytes, parseResult, req.getCharacterEncoding()); + } else { + body = handleBody(bytes, parseResult, ServerConfig.getInstance().getServerCharset()); + } + wrapper.setBody(body); + } + file.delete(); + FineLoggerFactory.getLogger().info("delete temp file"); + filterChain.doFilter(wrapper, res); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + private File saveTmp(InputStream input, String filename) throws IOException { + File file = FileUtil.createTempFile(); + try { + FileOutputStream outputStream = new FileOutputStream(file.getPath()); + IOUtils.copyLarge(input, outputStream); + FineLoggerFactory.getLogger().info("save tmp file path is {}", file.getPath()); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return file; + } + + + private byte[] concat(byte[] a, byte[] b) { + byte[] c = new byte[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } + + private byte[] handleBody(byte[] body, ParseResult parseResult, String charsetName) throws UnsupportedEncodingException { + byte[] newBody; + byte[] start; + byte[] end; + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(parseResult.getBoundary()).append("\r\n") + .append("Content-Disposition:").append(parseResult.getDispline()) + .append("; name=\"").append(parseResult.getFieldName()) + .append("\"; filename=\"").append(parseResult.getFileName()).append("\"\r\n") + .append("Content-Type: ").append(parseResult.getMime()).append("/").append(parseResult.getSubMime()).append("\r\n").append("\r\n"); + start = stringBuilder.toString().getBytes(charsetName); + StringBuilder stringBuilder1 = new StringBuilder(); + stringBuilder1.append("\r\n").append(parseResult.getBoundary()).append("--\r\n"); + end = stringBuilder1.toString().getBytes(charsetName); +// newBody = this.concat(this.concat(("------WebKitFormBoundary6c2DUJvlVKG0I1po\r\n" + +// "Content-Disposition: form-data; name=\"FileData\"; filename=\"1.xlsx\"\r\n" + +// "Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n" + +// "\r\n").getBytes(charsetName), body), ("\r\n------WebKitFormBoundary6c2DUJvlVKG0I1po--\r\n").getBytes(charsetName)); + newBody = this.concat(this.concat(start, body), end); + return newBody; + } +} diff --git a/src/main/java/com/hzdatalink/gsdes/filter/GlobalFilter.java b/src/main/java/com/hzdatalink/gsdes/filter/GlobalFilter.java new file mode 100644 index 0000000..0ed5537 --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/filter/GlobalFilter.java @@ -0,0 +1,94 @@ +package com.hzdatalink.gsdes.filter; + +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContexts; +import com.fr.stable.StringUtils; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author xx + * @date 2020/11/20 + */ +public class GlobalFilter extends AbstractGlobalRequestFilterProvider { + @Override + public String filterName() { + return "gsdes"; + } + + @Override + public String[] urlPatterns() { + if (PluginContexts.currentContext().isAvailable()) { + return new String[]{ + "/*" + }; + } else { + return new String[]{"/neverbeused"}; + } + } + + @Override + public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { + if (isDecode(req)) { + new DecodeFilter().doFilter(req, res, filterChain); + return; + } + + try { + filterChain.doFilter(req, res); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } catch (ServletException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + private boolean isDecode(HttpServletRequest req) { + if (req.getRequestURI().endsWith("attach/upload")) { + return true; + } + if (req.getRequestURI().endsWith("/dataset/upload")) { + return true; + } + String op = WebUtils.getHTTPRequestParameter(req, "op"); + String cmd = WebUtils.getHTTPRequestParameter(req, "cmd"); + if (StringUtils.equals("fr_attach", op) && StringUtils.equals("ah_upload", cmd)) { + return true; + } + if (StringUtils.equals("fr_write", op) && StringUtils.equals("imp_w_excel_data", cmd)) { + return true; + } + if (StringUtils.equals("fr_mark_excel", op) && StringUtils.equals("cache_excel", cmd)) { + return true; + } + return false; + } + + private boolean isEncode(HttpServletRequest req) { + if (req.getRequestURI().endsWith("/report/data/export")) { + return true; + } + if (req.getRequestURI().endsWith("/report/data/global/export/pdf")) { + return true; + } + if (req.getRequestURI().endsWith("/report/data/global/export/excel")) { + return true; + } + String op = WebUtils.getHTTPRequestParameter(req, "op"); + String cmd = WebUtils.getHTTPRequestParameter(req, "cmd"); + if (StringUtils.equals("fr_attach", op) && StringUtils.equals("ah_download", cmd)) { + return true; + } + if (StringUtils.equals("customcommit", op) && StringUtils.equals("downloadfile", cmd)) { + return true; + } + return false; + } + +} diff --git a/src/main/java/com/hzdatalink/gsdes/util/FileUtil.java b/src/main/java/com/hzdatalink/gsdes/util/FileUtil.java new file mode 100644 index 0000000..d4a8fdc --- /dev/null +++ b/src/main/java/com/hzdatalink/gsdes/util/FileUtil.java @@ -0,0 +1,36 @@ +package com.hzdatalink.gsdes.util; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +/** + * @author xx + * @date 2020/11/20 + */ +public class FileUtil { + + /** + * 创建临时文件 + * + * @return java.io.File + **/ + public static File createTempFile() throws IOException { + return File.createTempFile("tmp" + UUID.randomUUID().toString(), null);//创建一个临时文件 + } + + /** + * 删除文件 + * + * @param file + * @return boolean + * @author Zhanying + **/ + public static boolean deleteFile(File file) { + boolean flag = file.exists() && file.isFile() && file.delete(); + // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除 + return flag; + } + + +}