Compare commits

...

22 Commits

Author SHA1 Message Date
kl
2abedc34b4 fix(security): enforce whitelist with blacklist and harden wildcard rules 2026-03-03 14:35:56 +08:00
kl
a20606bf33 fix(security): set UTF-8 deny response and use Locale.ROOT 2026-03-03 14:18:41 +08:00
kl
5ba88d1243 test(security): verify CIDR matching for IPv4 upper boundary 2026-03-03 14:10:56 +08:00
kl
6bcefedd08 fix(security): handle ipv4 unsigned range and deny template fallback 2026-03-03 14:08:39 +08:00
kl
084bdc9012 fix(security): harden host matching against null and DNS rebinding 2026-03-03 13:51:30 +08:00
kl
1aa477bdf8 fix(security): support wildcard/cidr host pattern matching 2026-03-03 13:11:40 +08:00
陈精华
92ca92bee6 支持Java25环境 2025-12-03 18:46:23 +08:00
kailing
64c82a2406 !334 update docker/kkfileview-base/Dockerfile.
Merge pull request !334 from 云上小朱/N/A
2025-11-17 00:53:58 +00:00
云上小朱
e44ef813a1 update docker/kkfileview-base/Dockerfile.
在文件docker/kkfileview-base/Dockerfile中
我看到POM里写的Java21,但是Dockerfile写的JDK8. 是否应改为JDK21,我在本地测试,改为JDK21可正常打包代码并正常运行。

Signed-off-by: 云上小朱 <13077784+ysxz2025@user.noreply.gitee.com>
2025-11-14 01:04:31 +00:00
kl
9f3b45a4c7 安全:强制用户配置可访问域名的白名单或者黑名单,提高安全性 (#692)
* 安全:强制用户配置可访问域名的白名单或者黑名单,提高安全性

* 安全:强制用户配置可访问域名的白名单或者黑名单,提高安全性

* CI:修复 CI 问题

* CI:修复 CI 问题
2025-10-20 14:29:05 +08:00
kl
b1af0c7d72 优化:日志输出重构 (#689) 2025-10-13 11:14:54 +08:00
kl
421640221b Kl (#688)
* 升级: JDK1.8 升级到 JDK21 ,spring-boot 版本从 2.4.2 升级到 3.5.6

* 优化:启动日志新增 java version 输出信息
2025-10-11 20:14:39 +08:00
kl
f6c6e22b0d 升级: JDK1.8 升级到 JDK21 ,spring-boot 版本从 2.4.2 升级到 3.5.6 (#687) 2025-10-11 20:05:43 +08:00
kl
51653483b9 Kl json (#686)
* 新增:JSON 文件格式化预览功能

* 优化:优化 JSON 文件格式化预览效果
2025-10-11 17:54:17 +08:00
kl
a9787b0add 新增:JSON 文件格式化预览功能 (#685) 2025-10-11 11:52:49 +08:00
kl
6cdbf92fb0 优化:完善文件上传禁用功能的用户体验 (#684) 2025-10-11 10:41:34 +08:00
kl
fdb40680d3 安全:禁用文件上传接口 (#656)
- 从配置文件中移除file.upload.disable配置项
- 删除FileController中的文件上传相关代码
- 移除/fileUpload POST接口
- 删除文件上传校验逻辑
- 增强系统安全性,防止恶意文件上传

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-06-30 17:57:45 +08:00
陈精华
6746325bf2 update Github workflow 2025-04-14 16:10:29 +08:00
陈精华
05a8bff1e0 优化:调整单元测试 2025-03-31 15:56:50 +08:00
陈精华
874ff5b3f6 优化:解决部分场景下, 页面元素变化导致水印覆盖不全问题 2025-03-31 15:28:36 +08:00
陈精华
2230cfa52b update README.cn.md 2025-01-22 11:08:28 +08:00
陈精华
83c581364d update README.cn.md 2025-01-22 11:04:40 +08:00
61 changed files with 1205 additions and 138 deletions

View File

@@ -12,13 +12,41 @@ on:
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '8'
distribution: 'adopt'
cache: maven
java-version: '21'
distribution: 'temurin' # 使用 Eclipse Temurin (AdoptOpenJDK 的继任者)
cache: 'maven'
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: mvn -B package --file pom.xml
run: mvn -B package -Dmaven.test.skip=true --file pom.xml
- name: Upload Linux distribution package
if: success()
uses: actions/upload-artifact@v4
with:
name: kkfileview-linux
path: server/target/*.tar.gz
retention-days: 7
- name: Upload Windows distribution package
if: success()
uses: actions/upload-artifact@v4
with:
name: kkfileview-windows
path: server/target/*.zip
retention-days: 7

View File

@@ -53,80 +53,81 @@
#### 1. 文本预览
支持所有类型的文本文档预览, 由于文本文档类型过多,无法全部枚举,默认开启的类型如下 txt,html,htm,asp,jsp,xml,xbrl,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd
文本预览效果如下
![文本预览效果如下](https://kkview.cn/img/preview/preview-text.png)
![文本预览效果如下](./doc/img/preview/preview-text.png)
#### 2. 图片预览
支持jpg,jpeg,png,gif等图片预览(翻转,缩放,镜像),预览效果如下
![图片预览](https://kkview.cn/img/preview/preview-image.png)
![图片预览](./doc/img/preview/preview-image.png)
#### 3. word文档预览
支持doc,docx文档预览,word预览有两种模式:一种是每页word转为图片预览,另一种是整个word文档转成pdf,再预览pdf。两种模式的适用场景如下
* 图片预览:word文件大,前台加载整个pdf过慢
* pdf预览:内网访问,加载pdf快
图片预览模式预览效果如下
![word文档预览1](https://kkview.cn/img/preview/preview-doc-image.png)
![word文档预览1](./doc/img/preview/preview-doc-image.png)
pdf预览模式预览效果如下
![word文档预览2](https://kkview.cn/img/preview/preview-doc-pdf.png)
![word文档预览2](./doc/img/preview/preview-doc-pdf.png)
#### 4. ppt文档预览
支持ppt,pptx文档预览,和word文档一样,有两种预览模式
图片预览模式预览效果如下
![ppt文档预览1](https://kkview.cn/img/preview/preview-ppt-image.png)
![ppt文档预览1](./doc/img/preview/preview-ppt-image.png)
pdf预览模式预览效果如下
![ppt文档预览2](https://kkview.cn/img/preview/preview-ppt-pdf.png)
![ppt文档预览2](./doc/img/preview/preview-ppt-pdf.png)
#### 5. pdf文档预览
支持pdf文档预览,和word文档一样,有两种预览模式
图片预览模式预览效果如下
![pdf文档预览1](https://kkview.cn/img/preview/preview-pdf-image.png)
![pdf文档预览1](./doc/img/preview/preview-pdf-image.png)
pdf预览模式预览效果如下
![pdf文档预览2](https://kkview.cn/img/preview/preview-pdf-pdf.png)
![pdf文档预览2](./doc/img/preview/preview-pdf-pdf.png)
#### 6. excel文档预览
支持xls,xlsx文档预览,预览效果如下
![excel文档预览](https://kkview.cn/img/preview/preview-xls.png)
![excel文档预览](./doc/img/preview/preview-xls.png)
#### 7. 压缩文件预览
支持zip,rar,jar,tar,gzip等压缩包,预览效果如下
![压缩文件预览1](https://kkview.cn/img/preview/preview-zip.png)
![压缩文件预览1](./doc/img/preview/preview-zip.png)
可点击压缩包中的文件名,直接预览文件,预览效果如下
![压缩文件预览2](https://kkview.cn/img/preview/preview-zip-inner.png)
![压缩文件预览2](./doc/img/preview/preview-zip-inner.png)
#### 8. 多媒体文件预览
理论上支持所有的视频、音频文件,由于无法枚举所有文件格式,默认开启的类型如下
mp3,wav,mp4,flv
视频预览效果如下
![多媒体文件预览1](https://kkview.cn/img/preview/preview-video.png)
![多媒体文件预览1](./doc/img/preview/preview-video.png)
音频预览效果如下
![多媒体文件预览2](https://kkview.cn/img/preview/preview-audio.png)
![多媒体文件预览2](./doc/img/preview/preview-audio.png)
#### 9. CAD文档预览
支持CAD dwg文档预览,和word文档一样,有两种预览模式
图片预览模式预览效果如下
![cad文档预览1](https://kkview.cn/img/preview/preview-cad-image.png)
![cad文档预览1](./doc/img/preview/preview-cad-image.png)
pdf预览模式预览效果如下
![cad文档预览2](https://kkview.cn/img/preview/preview-cad-pdf.png)
考虑说明篇幅原因,就不贴其他格式文件的预览效果了,感兴趣的可以参考下面的实例搭建下
![cad文档预览2](./doc/img/preview/preview-cad-pdf.png)
#### 10. Excel文件纯前端渲染效果
![Excel文件纯前端渲染效果](https://kkview.cn/img/preview/preview-xlsx-web.png)
![Excel文件纯前端渲染效果](./doc/img/preview/preview-xlsx-web.png)
#### 11. 流程图bpmn文件预览效果
![流程图bpmn文件预览效果](https://kkview.cn/img/preview/preview-bpmn.png)
![流程图bpmn文件预览效果](./doc/img/preview/preview-bpmn.png)
#### 12. 3D模型文件预览效果:
![3D模型文件预览效果](https://kkview.cn/img/preview/preview-3ds.png)
![3D模型文件预览效果](./doc/img/preview/preview-3ds.png)
#### 13. dcm医疗数位影像文件预览效果:
![dcm医疗数位影像文件预览效果](https://kkview.cn/img/preview/preview-dcm.png)
![dcm医疗数位影像文件预览效果](./doc/img/preview/preview-dcm.png)
#### 14. drawio流程图预览效果:
![dcdrawio流程图预览效果](https://kkview.cn/img/preview/preview-drawio.png)
![drawio流程图预览效果](./doc/img/preview/preview-drawio.png)
考虑说明篇幅原因,就不贴其他格式文件的预览效果了,感兴趣的可以参考下面的实例搭建下
### 快速开始
> 项目使用技术
@@ -148,7 +149,56 @@ pdf预览模式预览效果如下
### 历史更新记录
#### > 2023年07月05日,v4.3 版本发布 :
#### > 2025年01月16日,v4.4.0 版本发布 :
### 新增功能
1. xlsx 新增支持打印功能
2. 配置文件新增启用 GZIP 压缩
3. CAD 格式新增支持转换成 SVG 和 TIF 格式,新增超时结束、线程管理
4. 新增删除文件使用验证码校验
5. 新增 xbrl 格式预览支持
6. PDF 预览新增控制签名、绘图、插图控制、搜索定位页码、定义显示内容等功能
7. 新增 CSV 格式前端解析支持
8. 新增 ARM64 下的 Docker 镜像支持
9. 新增 Office 预览支持转换超时属性设置功能
10. 新增预览文件 host 黑名单机制
### 优化
1. 优化 OFD 移动端预览 页面不自适应
2. 更新 xlsx 前端解析组件,加速解析速度
3. 升级 CAD 组件
4. office 功能调整,支持批注、转换页码限制、生成水印等功能
5. 升级 markdown 组件
6. 升级 dcm 解析组件
7. 升级 PDF.JS 解析组件
8. 更换视频播放插件为 ckplayer
9. tif 解析更加智能化,支持被修改的图片格式
10. 针对大小文本文件检测字符编码的正确率,处理并发隐患
11. 重构下载文件的代码,新增通用的文件服务器认证访问的设计
12. 更新 bootstrap 组件,并精简掉不需要的文件
13. 更新 epub 版本,优化 epub 显示效果
14. 解决定时清除缓存时,对于多媒体类型文件,只删除了磁盘缓存文件
15. 自动检测已安装 Office 组件,增加 LibreOffice 7.5 & 7.6 版本默认路径
16. 修改 drawio 默认为预览模式
17. 新增 PDF 线程管理、超时管理、内存缓存管理,更新 PDF 解析组件版本
18. 优化 Dockerfile,支持真正的跨平台构建镜像
### 修复
1. 修复 forceUpdatedCache 属性设置,但本地缓存文件不更新的问题
2. 修复 PDF 解密加密文件转换成功后后台报错的问题
3. 修复 BPMN 不支持跨域的问题
4. 修复压缩包二级反代特殊符号错误问题
5. 修复视频跨域配置导致视频无法预览的问题
6. 修复 TXT 文本类分页二次加载问题
7. 修复 Drawio 缺少 Base64 组件的问题
8. 修复 Markdown 被转义问题
9. 修复 EPUB 跨域报错问题
10. 修复 URL 特殊符号问题
11. 修复压缩包穿越漏洞
12. 修复压缩获取路径错误、图片合集路径错误、水印问题等 BUG
13. 修复前端解析 XLSX 包含 EMF 格式文件错误问题
#### > 2023年07月05日,v4.3.0 版本发布 :
#### 新增功能:
1. 新增dcm等医疗数位影像预

174
SECURITY_CONFIG.md Normal file
View File

@@ -0,0 +1,174 @@
# kkFileView 安全配置指南
## ⚠️ 重要安全更新
从 4.4.0 之后版本开始,kkFileView 增强了安全性,默认拒绝所有未配置的外部文件预览请求,以防止 SSRF(服务器端请求伪造)攻击。
## 🔒 安全配置说明
### 1. 信任主机白名单配置(推荐)
在 `application.properties` 中配置允许预览的域名:
```properties
# 方式1:通过配置文件
trust.host = kkview.cn,yourdomain.com,cdn.example.com
# 方式2:通过环境变量
KK_TRUST_HOST=kkview.cn,yourdomain.com,cdn.example.com
```
**示例场景**:
- 只允许预览来自 `oss.aliyuncs.com` 和 `cdn.example.com` 的文件
```properties
trust.host = oss.aliyuncs.com,cdn.example.com
```
### 2. 允许所有主机(不推荐,仅测试环境)
```properties
trust.host = *
```
⚠️ **警告**:此配置会允许访问任意外部地址,存在安全风险,仅应在测试环境使用!
### 3. 黑名单配置(高级)
禁止特定域名或内网地址:
```properties
# 禁止访问内网地址(强烈推荐)
not.trust.host = localhost,127.0.0.1,192.168.*,10.*,172.16.*,169.254.*
# 禁止特定恶意域名
not.trust.host = malicious-site.com,spam-domain.net
```
**优先级**:黑名单 > 白名单
### 4. Docker 环境配置
```bash
docker run -d \
-e KK_TRUST_HOST=yourdomain.com,cdn.example.com \
-e KK_NOT_TRUST_HOST=localhost,127.0.0.1 \
-p 8012:8012 \
keking/kkfileview:4.4.0
```
## 🛡️ 安全最佳实践
### ✅ 推荐配置
```properties
# 1. 明确配置信任主机白名单
trust.host = your-cdn.com,your-storage.com
# 2. 配置黑名单防止内网访问
not.trust.host = localhost,127.0.0.1,192.168.*,10.*,172.16.*
# 3. 禁用文件上传(生产环境)
file.upload.disable = true
# 4. 配置基础URL(使用反向代理时)
base.url = https://preview.yourdomain.com
```
### ❌ 不推荐配置
```properties
# 危险:允许所有主机访问
trust.host = *
# 危险:启用文件上传(生产环境)
file.upload.disable = false
```
## 🔍 配置验证
### 测试白名单是否生效
1. 配置白名单:
```properties
trust.host = kkview.cn
```
2. 尝试预览白名单内的文件:
```
http://localhost:8012/onlinePreview?url=https://kkview.cn/test.pdf
✅ 应该可以正常预览
```
3. 尝试预览白名单外的文件:
```
http://localhost:8012/onlinePreview?url=https://other-domain.com/test.pdf
❌ 应该被拒绝,显示"不信任的文件源"
```
### 测试黑名单是否生效
1. 配置黑名单:
```properties
not.trust.host = localhost,127.0.0.1
```
2. 尝试访问本地文件:
```
http://localhost:8012/getCorsFile?urlPath=http://127.0.0.1:8080/admin
❌ 应该被拒绝
```
## 📋 常见问题
### Q1: 升级后无法预览文件了?
**原因**:新版本默认拒绝未配置的主机。
**解决**:在配置文件中添加信任主机列表:
```properties
trust.host = your-file-server.com
```
### Q2: 如何临时恢复旧版本行为?
**不推荐**,但如果确实需要:
```properties
trust.host = *
```
### Q3: 配置了白名单但还是无法访问?
检查以下几点:
1. 域名是否完全匹配(区分大小写)
2. 是否配置了黑名单,黑名单优先级更高
3. 查看日志中的 WARNING 信息
4. 确认环境变量是否正确设置
### Q4: 如何允许子域名?
已支持通配符域名匹配,可使用 `*.example.com`:
```properties
trust.host = *.example.com
```
说明:
- `*.example.com` 会匹配 `cdn.example.com`、`api.internal.example.com`,但不匹配根域 `example.com`
- 对于 IP 风格通配(如 `192.168.*`、`10.*`),仅匹配字面量 IPv4 地址,不匹配域名
## 🚨 安全事件响应
如果发现可疑的预览请求:
1. 检查日志文件,搜索 "拒绝访问主机" 关键字
2. 确认 `trust.host` 配置是否合理
3. 检查是否有异常的网络请求
4. 如发现攻击行为,及时更新黑名单配置
## 📞 获取帮助
- GitHub Issues: https://github.com/kekingcn/kkFileView/issues
- Gitee Issues: https://gitee.com/kekingcn/file-online-preview/issues
---
**安全提示**:定期检查和更新信任主机列表,遵循最小权限原则。

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -5,7 +5,7 @@ RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.aliyun.com@g' /etc/apt/sources.li
sed -i 's@//ports.ubuntu.com@//mirrors.aliyun.com@g' /etc/apt/sources.list.d/ubuntu.sources &&\
apt-get update &&\
export DEBIAN_FRONTEND=noninteractive &&\
apt-get install -y --no-install-recommends openjdk-8-jre tzdata locales xfonts-utils fontconfig libreoffice-nogui &&\
apt-get install -y --no-install-recommends openjdk-21-jre tzdata locales xfonts-utils fontconfig libreoffice-nogui &&\
echo 'Asia/Shanghai' > /etc/timezone &&\
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8 &&\

View File

@@ -9,14 +9,14 @@
<version>4.4.0</version>
<properties>
<java.version>1.8</java.version>
<java.version>21</java.version>
<jodconverter.version>4.4.6</jodconverter.version>
<spring.boot.version>2.4.2</spring.boot.version>
<spring.boot.version>3.5.6</spring.boot.version>
<poi.version>5.2.2</poi.version>
<xdocreport.version>1.0.6</xdocreport.version>
<xstream.version>1.4.20</xstream.version>
<junrar.version>7.5.5</junrar.version>
<redisson.version>3.2.0</redisson.version>
<redisson.version>3.22.0</redisson.version>
<sevenzipjbinding.version>16.02-2.01</sevenzipjbinding.version>
<jchardet.version>1.0</jchardet.version>
<antlr.version>2.7.7</antlr.version>
@@ -43,6 +43,7 @@
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.release>${java.version}</maven.compiler.release>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@@ -44,21 +44,16 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- web end -->
<!-- poi start -->
@@ -100,9 +95,8 @@
</dependency>
<!-- poi start -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpcomponents.version}</version>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<!-- 对 rar5 的支持 和其他众多压缩支持 可参考 package net.sf.sevenzipjbinding.ArchiveFormat; -->
@@ -182,6 +176,12 @@
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
@@ -327,6 +327,14 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>

View File

@@ -22,6 +22,14 @@ spring.freemarker.expose-request-attributes = true
spring.freemarker.expose-session-attributes = true
spring.freemarker.request-context-attribute = request
spring.freemarker.suffix = .ftl
# Spring Boot Actuator 健康检查配置
# 开启健康检查端点
management.endpoints.web.exposure.include=health,info,metrics
# 显示详细的健康检查信息(生产环境建议设置为when-authorized)
management.endpoint.health.show-details=always
# 启用健康检查组件
management.health.defaults.enabled=true
# office设置
#openoffice或LibreOffice home路径
@@ -78,11 +86,25 @@ cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
#提供预览服务的地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置
#base.url = https://file.keking.cn
base.url = ${KK_BASE_URL:default}
#信任站点,多个用','隔开,设置了之后,会限制只能预览来自信任站点列表的文件,默认不限制
#trust.host = kkview.cn
# ========== 安全配置(重要)==========
# 信任站点白名单配置,多个用','隔开
# ⚠️ 安全提示:为防止SSRF攻击,强烈建议配置信任主机白名单
# ⚠️ 如果不配置,系统将默认拒绝所有外部文件预览请求
#
# 配置示例:
# trust.host = kkview.cn,yourdomain.com,cdn.example.com
#
# 如果需要允许所有域名(不推荐,仅用于测试环境),请设置为:
# trust.host = *
#
# 当前配置:
trust.host = ${KK_TRUST_HOST:default}
#不信任站点,多个用','隔开,设置了之后,会限制来自不信任站点列表的文件,默认不限制
#not.trust.host = kkview.cn
# 不信任站点黑名单配置,多个用','隔开
# 黑名单优先级高于白名单,设置后将禁止预览来自这些站点的文件
# 建议配置:禁止访问内网地址和本地地址
# not.trust.host = localhost,127.0.0.1,0.0.0.0,192.168.*,10.*,172.16.*
not.trust.host= ${KK_NOT_TRUST_HOST:default}
#文本类型,默认如下,可自定义添加
simText = ${KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}
@@ -159,10 +181,9 @@ watermark.height = ${WATERMARK_HEIGHT:80}
#水印倾斜度数,要求设置在大于等于0,小于90
watermark.angle = ${WATERMARK_ANGLE:10}
#首页功能设置
#是否禁用首页文件上传
file.upload.disable = ${KK_FILE_UPLOAD_DISABLE:false}
file.upload.disable = ${KK_FILE_UPLOAD_DISABLE:true}
# 备案信息,默认为空
beian = ${KK_BEIAN:default}
#禁止上传类型

View File

@@ -308,7 +308,8 @@ public class ConfigConstants {
if (DEFAULT_VALUE.equalsIgnoreCase(trustHost)) {
return new CopyOnWriteArraySet<>();
} else {
String[] trustHostArray = trustHost.toLowerCase().split(",");
// 去除空格并转小写
String[] trustHostArray = trustHost.toLowerCase().replaceAll("\\s+", "").split(",");
return new CopyOnWriteArraySet<>(Arrays.asList(trustHostArray));
}
}
@@ -426,7 +427,7 @@ public class ConfigConstants {
return fileUploadDisable;
}
@Value("${file.upload.disable:false}")
@Value("${file.upload.disable:true}")
public void setFileUploadDisable(Boolean fileUploadDisable) {
setFileUploadDisableValue(fileUploadDisable);
}

View File

@@ -5,7 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

View File

@@ -50,26 +50,21 @@ public class RedissonConfig {
.setConnectionMinimumIdleSize(connectionMinimumIdleSize)
.setConnectionPoolSize(connectionPoolSize)
.setDatabase(database)
.setDnsMonitoring(dnsMonitoring)
.setDnsMonitoringInterval(dnsMonitoringInterval)
.setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
.setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
.setSubscriptionsPerConnection(subscriptionsPerConnection)
.setClientName(clientName)
.setFailedAttempts(failedAttempts)
.setRetryAttempts(retryAttempts)
.setRetryInterval(retryInterval)
.setReconnectionTimeout(reconnectionTimeout)
.setTimeout(timeout)
.setConnectTimeout(connectTimeout)
.setIdleConnectionTimeout(idleConnectionTimeout)
.setPingTimeout(pingTimeout)
.setPassword(StringUtils.trimToNull(password));
Codec codec=(Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
config.setCodec(codec);
config.setThreads(thread);
config.setEventLoopGroup(new NioEventLoopGroup());
config.setUseLinuxNativeEpoll(false);
return config;
}

View File

@@ -22,6 +22,7 @@ public enum FileType {
MEDIACONVERT("mediaFilePreviewImpl"),
MARKDOWN("markdownFilePreviewImpl"),
XML("xmlFilePreviewImpl"),
JSON("jsonFilePreviewImpl"),
CAD("cadFilePreviewImpl"),
TIFF("tiffFilePreviewImpl"),
OFD("ofdFilePreviewImpl"),
@@ -44,12 +45,13 @@ public enum FileType {
private static final String[] DCM_TYPES = {"dcm"};
private static final String[] DRAWIO_TYPES = {"drawio"};
private static final String[] XML_TYPES = {"xml","xbrl"};
private static final String[] JSON_TYPES = {"json"};
private static final String[] TIFF_TYPES = {"tif", "tiff"};
private static final String[] OFD_TYPES = {"ofd"};
private static final String[] SVG_TYPES = {"svg"};
private static final String[] CAD_TYPES = {"dwg", "dxf", "dwf", "iges", "igs", "dwt", "dng", "ifc", "dwfx", "stl", "cf2", "plt"};
private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yaml", "yml", "json", "h", "cpp", "cs", "aspx", "jsp", "sql"};
private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yaml", "yml", "h", "cpp", "cs", "aspx", "jsp", "sql"};
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
public static final String[] MEDIA_CONVERT_TYPES = ConfigConstants.getConvertMedias();
private static final Map<String, FileType> FILE_TYPE_MAPPER = new HashMap<>();
@@ -109,6 +111,9 @@ public enum FileType {
for (String xml : XML_TYPES) {
FILE_TYPE_MAPPER.put(xml, FileType.XML);
}
for (String json : JSON_TYPES) {
FILE_TYPE_MAPPER.put(json, FileType.JSON);
}
FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN);
FILE_TYPE_MAPPER.put("pdf", FileType.PDF);
FILE_TYPE_MAPPER.put("bpmn", FileType.BPMN);

View File

@@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.ui.ExtendedModelMap;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/**
@@ -73,7 +73,7 @@ public class FileConvertQueueTask {
TimeUnit.SECONDS.sleep(10);
} catch (Exception ex) {
Thread.currentThread().interrupt();
ex.printStackTrace();
logger.error("Failed to sleep after exception", ex);
}
logger.info("处理预览转换任务异常,url:{}", url, e);
}

View File

@@ -31,7 +31,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLDecoder;
@@ -178,13 +178,13 @@ public class FileHandlerService implements InitializingBean {
sb.append("<script src=\"excel/excel.header.js\" type=\"text/javascript\"></script>");
sb.append("<link rel=\"stylesheet\" href=\"excel/excel.css\">");
} catch (IOException e) {
e.printStackTrace();
logger.error("Failed to read file: {}", outFilePath, e);
}
// 重新写入文件
try (FileOutputStream fos = new FileOutputStream(outFilePath); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
writer.write(sb.toString());
} catch (IOException e) {
e.printStackTrace();
logger.error("Failed to write file: {}", outFilePath, e);
}
}
@@ -477,14 +477,14 @@ public class FileHandlerService implements InitializingBean {
originFileName = URLDecoder.decode(originFileName, uriEncoding); //转义的文件名 解下出原始文件名
attribute.setSkipDownLoad(true);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
logger.error("Failed to decode file name: {}", originFileName, e);
}
}
if (UrlEncoderUtils.hasUrlEncoded(originFileName)) { //判断文件名是否转义
try {
originFileName = URLDecoder.decode(originFileName, uriEncoding); //转义的文件名 解下出原始文件名
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
logger.error("Failed to decode file name: {}", originFileName, e);
}
}else {
url = WebUtils.encodeUrlFileName(url); //对未转义的url进行转义

View File

@@ -26,6 +26,7 @@ public interface FilePreview {
String CODE_FILE_PREVIEW_PAGE = "code";
String EXEL_FILE_PREVIEW_PAGE = "html";
String XML_FILE_PREVIEW_PAGE = "xml";
String JSON_FILE_PREVIEW_PAGE = "json";
String MARKDOWN_FILE_PREVIEW_PAGE = "markdown";
String BPMN_FILE_PREVIEW_PAGE = "bpmn";
String DCM_FILE_PREVIEW_PAGE = "dcm";

View File

@@ -15,8 +15,8 @@ import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

View File

@@ -7,7 +7,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

View File

@@ -9,6 +9,8 @@ import cn.keking.utils.DownloadUtils;
import cn.keking.utils.KkFileUtils;
import cn.keking.utils.WebUtils;
import cn.keking.web.filter.BaseUrlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
@@ -22,6 +24,7 @@ import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
@Service
public class CadFilePreviewImpl implements FilePreview {
private static final Logger logger = LoggerFactory.getLogger(CadFilePreviewImpl.class);
private static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
@@ -55,7 +58,7 @@ public class CadFilePreviewImpl implements FilePreview {
try {
imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath, cadPreviewType, fileAttribute);
} catch (Exception e) {
e.printStackTrace();
logger.error("Failed to convert CAD file: {}", filePath, e);
}
if (imageUrls == null) {
return otherFilePreview.notSupportedFile(model, fileAttribute, "CAD转换异常,请联系管理员");

View File

@@ -0,0 +1,95 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FileHandlerService;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.KkFileUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.util.HtmlUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @author kl (http://kailing.pub)
* @since 2025/01/11
* JSON 文件预览处理实现
*/
@Service
public class JsonFilePreviewImpl implements FilePreview {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonFilePreviewImpl.class);
private final FileHandlerService fileHandlerService;
private final OtherFilePreviewImpl otherFilePreview;
public JsonFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
this.fileHandlerService = fileHandlerService;
this.otherFilePreview = otherFilePreview;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileName = fileAttribute.getName();
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
String filePath = fileAttribute.getOriginFilePath();
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) {
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
if (response.isFailure()) {
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
}
filePath = response.getContent();
if (ConfigConstants.isCacheEnabled()) {
fileHandlerService.addConvertedFile(fileName, filePath);
}
try {
String fileData = readJsonFile(filePath, fileName);
String escapedData = HtmlUtils.htmlEscape(fileData);
String base64Data = Base64.encodeBase64String(escapedData.getBytes(StandardCharsets.UTF_8));
model.addAttribute("textData", base64Data);
} catch (IOException e) {
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
}
return JSON_FILE_PREVIEW_PAGE;
}
String fileData = null;
try {
fileData = HtmlUtils.htmlEscape(readJsonFile(filePath, fileName));
} catch (IOException e) {
LOGGER.error("读取JSON文件失败: {}", filePath, e);
}
String base64Data = Base64.encodeBase64String(fileData.getBytes(StandardCharsets.UTF_8));
model.addAttribute("textData", base64Data);
return JSON_FILE_PREVIEW_PAGE;
}
/**
* 读取 JSON 文件,强制使用 UTF-8 编码
* JSON 标准规定必须使用 UTF-8 编码
*/
private String readJsonFile(String filePath, String fileName) throws IOException {
File file = new File(filePath);
if (KkFileUtils.isIllegalFileName(fileName)) {
return null;
}
if (!file.exists() || file.length() == 0) {
return "";
}
// JSON 标准规定使用 UTF-8 编码,不依赖自动检测
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
return new String(bytes, StandardCharsets.UTF_8);
}
}

View File

@@ -11,6 +11,8 @@ import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.ObjectUtils;
@@ -26,6 +28,7 @@ import java.io.File;
@Service
public class MediaFilePreviewImpl implements FilePreview {
private static final Logger logger = LoggerFactory.getLogger(MediaFilePreviewImpl.class);
private final FileHandlerService fileHandlerService;
private final OtherFilePreviewImpl otherFilePreview;
private static final String mp4 = "mp4";
@@ -66,7 +69,7 @@ public class MediaFilePreviewImpl implements FilePreview {
convertedUrl = outFilePath; //其他协议的 不需要转换方式的文件 直接输出
}
} catch (Exception e) {
e.printStackTrace();
logger.error("Failed to convert media file: {}", filePath, e);
}
if (convertedUrl == null) {
return otherFilePreview.notSupportedFile(model, fileAttribute, "视频转换异常,请联系管理员");
@@ -148,7 +151,7 @@ public class MediaFilePreviewImpl implements FilePreview {
recorder.record(captured_frame);
}
} catch (Exception e) {
e.printStackTrace();
logger.error("Failed to convert video file to mp4: {}", filePath, e);
return null;
} finally {
if (recorder != null) { //关闭

View File

@@ -9,11 +9,17 @@ import cn.keking.utils.DownloadUtils;
import cn.keking.utils.EncodingDetects;
import cn.keking.utils.KkFileUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.util.HtmlUtils;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
@@ -23,10 +29,12 @@ import java.nio.charset.StandardCharsets;
@Service
public class SimTextFilePreviewImpl implements FilePreview {
private static final Logger LOGGER = LoggerFactory.getLogger(SimTextFilePreviewImpl.class);
private final FileHandlerService fileHandlerService;
private final OtherFilePreviewImpl otherFilePreview;
public SimTextFilePreviewImpl(FileHandlerService fileHandlerService,OtherFilePreviewImpl otherFilePreview) {
public SimTextFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
this.fileHandlerService = fileHandlerService;
this.otherFilePreview = otherFilePreview;
}
@@ -47,7 +55,7 @@ public class SimTextFilePreviewImpl implements FilePreview {
}
try {
String fileData = HtmlUtils.htmlEscape(textData(filePath,fileName));
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes(StandardCharsets.UTF_8)));
} catch (IOException e) {
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
}
@@ -57,9 +65,9 @@ public class SimTextFilePreviewImpl implements FilePreview {
try {
fileData = HtmlUtils.htmlEscape(textData(filePath,fileName));
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("读取文本文件失败: {}", filePath, e);
}
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes(StandardCharsets.UTF_8)));
return TXT_FILE_PREVIEW_PAGE;
}

View File

@@ -6,9 +6,9 @@ import cn.keking.model.ReturnResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.mola.galimatias.GalimatiasParseException;
import org.apache.commons.io.FileUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;

View File

@@ -4,6 +4,8 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
@@ -18,6 +20,7 @@ import java.nio.file.Paths;
*/
public class OfficeUtils {
private static final Logger logger = LoggerFactory.getLogger(OfficeUtils.class);
private static final String POI_INVALID_PASSWORD_MSG = "password";
/**
@@ -49,7 +52,7 @@ public class OfficeUtils {
try {
propStream.close();//关闭文件输入流
} catch (IOException e) {
e.printStackTrace();
logger.error("Failed to close input stream for file: {}", path, e);
}
}
}
@@ -76,7 +79,7 @@ public class OfficeUtils {
try {
propStream.close();//关闭文件输入流
} catch (IOException e) {
e.printStackTrace();
logger.error("Failed to close input stream for file: {}", path, e);
}
}
}

View File

@@ -1,6 +1,9 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.service.ZtreeNodeVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
@@ -15,6 +18,7 @@ import java.util.regex.Pattern;
* create : 2023-04-08
**/
public class RarUtils {
private static final Logger logger = LoggerFactory.getLogger(RarUtils.class);
private static final String fileDir = ConfigConstants.getFileDir();
public static byte[] getUTF8BytesFromGBKString(String gbkStr) {
@@ -55,7 +59,7 @@ public class RarUtils {
str = new String(getUTF8BytesFromGBKString(str), StandardCharsets.UTF_8);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
logger.error("Failed to convert string encoding: {}", str, e);
}
}
return str;

View File

@@ -1,5 +1,8 @@
package cn.keking.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -31,6 +34,8 @@ import java.net.URL;
*/
public class SimpleEncodingDetects {
private static final Logger logger = LoggerFactory.getLogger(SimpleEncodingDetects.class);
/**
* 得到文件的编码
* @param content 文件内容
@@ -65,10 +70,10 @@ public class SimpleEncodingDetects {
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("File not found: {}", file, e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("Failed to read file: {}", file, e);
}
}

View File

@@ -1,16 +1,16 @@
package cn.keking.utils;
import io.mola.galimatias.GalimatiasParseException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -87,7 +87,7 @@ public class WebUtils {
try {
urlStr = URLEncoder.encode(urlStr, "UTF-8").replaceAll("\\+", "%20").replaceAll("%3A", ":").replaceAll("%2F", "/").replaceAll("%3F", "?").replaceAll("%26", "&").replaceAll("%3D", "=");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
LOGGER.error("Failed to encode URL: {}", urlStr, e);
}
}
return urlStr;
@@ -155,7 +155,7 @@ public class WebUtils {
URL urlObj = new URL(url);
url = urlObj.getPath().substring(1);
} catch (MalformedURLException e) {
e.printStackTrace();
LOGGER.error("Failed to parse file URL: {}", url, e);
}
}
// 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题
@@ -290,7 +290,7 @@ public class WebUtils {
* https://github.com/kekingcn/kkFileView/pull/340
*/
try {
return new String(Base64Utils.decodeFromString(source.replaceAll(" ", "+").replaceAll("\n", "")), charsets);
return new String(Base64.decodeBase64(source.replaceAll(" ", "+").replaceAll("\n", "")), charsets);
} catch (Exception e) {
if (e.getMessage().toLowerCase().contains(BASE64_MSG)) {
LOGGER.error("url解码异常,接入方法错误未使用BASE64");

View File

@@ -19,9 +19,9 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

View File

@@ -11,9 +11,9 @@ import cn.keking.utils.WebUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.opensagres.xdocreport.core.io.IOUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
@@ -28,8 +28,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

View File

@@ -4,8 +4,8 @@ import cn.keking.config.ConfigConstants;
import cn.keking.config.WatermarkConfigConstants;
import cn.keking.utils.KkFileUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
/**

View File

@@ -4,8 +4,8 @@ import cn.keking.config.ConfigConstants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
/**

Some files were not shown because too many files have changed in this diff Show More