From bcc4315ea9d0cd0386f360340ce3a31207ea65f1 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:08:50 +0800 Subject: [PATCH 01/93] =?UTF-8?q?fix(parser):=20JsScriptLoader=20JarFile?= =?UTF-8?q?=20=E6=94=B9=E7=94=A8=20try-with-resources=20=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8F=A5=E6=9F=84=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JarFile 在手动 close() 时若中间抛异常会导致文件句柄未关闭, 改为 try-with-resources 确保无论正常或异常都能释放资源。 --- .../qaiu/parser/customjs/JsScriptLoader.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsScriptLoader.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsScriptLoader.java index d66b106..a3d665f 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsScriptLoader.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsScriptLoader.java @@ -139,21 +139,20 @@ public class JsScriptLoader { try { String jarPath = jarUrl.getPath().substring(5, jarUrl.getPath().indexOf("!")); - JarFile jarFile = new JarFile(jarPath); - - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - String entryName = entry.getName(); - - if (entryName.startsWith(RESOURCE_PATH + "/") && - entryName.endsWith(".js") && - !isExcludedFile(entryName.substring(entryName.lastIndexOf('/') + 1))) { - resourceFiles.add(entryName); + + try (JarFile jarFile = new JarFile(jarPath)) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + + if (entryName.startsWith(RESOURCE_PATH + "/") && + entryName.endsWith(".js") && + !isExcludedFile(entryName.substring(entryName.lastIndexOf('/') + 1))) { + resourceFiles.add(entryName); + } } } - - jarFile.close(); } catch (Exception e) { log.debug("解析JAR包资源文件失败", e); } From ae3ff9ecbb5ca47a5a3964d5bf53b2a23a4dfbbf Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:09:59 +0800 Subject: [PATCH 02/93] =?UTF-8?q?fix(parser):=20JsPlaygroundLogger=20?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=88=97=E8=A1=A8=E9=99=90=E5=88=B6=E6=9C=80?= =?UTF-8?q?=E5=A4=A7=201000=20=E6=9D=A1=E9=98=B2=E6=AD=A2=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 日志列表 Collections.synchronizedList 无容量限制,长时间运行会无界增长。 新增 addLog() 方法,在添加前检查容量,超过 1000 条时移除最早的条目。 --- .../parser/customjs/JsPlaygroundLogger.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java index a6b2acd..8319d96 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java @@ -14,6 +14,7 @@ import java.util.List; public class JsPlaygroundLogger { // 使用线程安全的列表 + private static final int MAX_LOG_SIZE = 1000; private final List logs = Collections.synchronizedList(new ArrayList<>()); /** @@ -59,6 +60,18 @@ public class JsPlaygroundLogger { return obj.toString(); } + /** + * 添加日志条目,超过最大容量时移除最早的条目 + */ + private void addLog(LogEntry entry) { + synchronized (logs) { + if (logs.size() >= MAX_LOG_SIZE) { + logs.remove(0); + } + logs.add(entry); + } + } + /** * 记录日志(内部方法) * @param level 日志级别 @@ -67,7 +80,7 @@ public class JsPlaygroundLogger { */ private void log(String level, Object message, String source) { String msg = toString(message); - logs.add(new LogEntry(level, msg, source)); + addLog(new LogEntry(level, msg, source)); System.out.println("[" + source + "PlaygroundLogger] " + level + ": " + msg); } @@ -111,7 +124,7 @@ public class JsPlaygroundLogger { if (throwable != null) { msg = msg + ": " + throwable.getMessage(); } - logs.add(new LogEntry("ERROR", msg, "JS")); + addLog(new LogEntry("ERROR", msg, "JS")); System.out.println("[JSPlaygroundLogger] ERROR: " + msg); } @@ -153,7 +166,7 @@ public class JsPlaygroundLogger { if (throwable != null) { msg = msg + ": " + throwable.getMessage(); } - logs.add(new LogEntry("ERROR", msg, "JAVA")); + addLog(new LogEntry("ERROR", msg, "JAVA")); System.out.println("[JAVAPlaygroundLogger] ERROR: " + msg); } From 942de9c430502ff987d42eecff2e9a3c729c7f6b Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:11:35 +0800 Subject: [PATCH 03/93] =?UTF-8?q?fix(core):=20ConfigRetriever=20=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E8=B7=AF=E5=BE=84=E4=B9=9F=E8=B0=83=E7=94=A8=20close(?= =?UTF-8?q?)=20=E9=98=B2=E6=AD=A2=E8=B5=84=E6=BA=90=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit readConfig() 中 onSuccess 回调未关闭 ConfigRetriever, 文件监听器和底层资源无法释放,现在成功和失败路径均调用 close()。 --- core/src/main/java/cn/qaiu/vx/core/util/ConfigUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/util/ConfigUtil.java b/core/src/main/java/cn/qaiu/vx/core/util/ConfigUtil.java index 1d5cb50..fbcc5b3 100644 --- a/core/src/main/java/cn/qaiu/vx/core/util/ConfigUtil.java +++ b/core/src/main/java/cn/qaiu/vx/core/util/ConfigUtil.java @@ -62,7 +62,10 @@ public class ConfigUtil { // 异步获取配置 // 成功直接完成 promise retriever.getConfig() - .onSuccess(promise::complete) + .onSuccess(config -> { + promise.complete(config); + retriever.close(); + }) .onFailure(err -> { // 配置读取失败,直接返回失败 Future promise.fail(new RuntimeException( From d99885d39646ebe7ff7485bc7b170701da15fbd4 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:12:37 +0800 Subject: [PATCH 04/93] =?UTF-8?q?fix(core):=20RouterVerticle=20Router=20?= =?UTF-8?q?=E4=BB=8E=20static=20final=20=E6=94=B9=E4=B8=BA=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Router 声明为 static final 会在类加载时提前创建, 与 Vert.x 实例生命周期不匹配,改为在 start() 中初始化为实例字段。 --- .../main/java/cn/qaiu/vx/core/verticle/RouterVerticle.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/verticle/RouterVerticle.java b/core/src/main/java/cn/qaiu/vx/core/verticle/RouterVerticle.java index acc0c7e..b85a484 100644 --- a/core/src/main/java/cn/qaiu/vx/core/verticle/RouterVerticle.java +++ b/core/src/main/java/cn/qaiu/vx/core/verticle/RouterVerticle.java @@ -23,12 +23,11 @@ public class RouterVerticle extends AbstractVerticle { private static final Logger LOGGER = LoggerFactory.getLogger(RouterVerticle.class); private static final int port = SharedDataUtil.getValueForServerConfig("port"); - private static final Router router = new RouterHandlerFactory( - SharedDataUtil.getJsonStringForServerConfig("contextPath")).createRouter(); private static final JsonObject globalConfig = SharedDataUtil.getJsonConfig("globalConfig"); private HttpServer server; + private Router router; static { LOGGER.info(JacksonConfig.class.getSimpleName() + " >> "); @@ -61,6 +60,8 @@ public class RouterVerticle extends AbstractVerticle { .setReuseAddress(true) // 允许地址重用 .setReusePort(true); // 允许端口重用 + router = new RouterHandlerFactory( + SharedDataUtil.getJsonStringForServerConfig("contextPath")).createRouter(); server = vertx.createHttpServer(options); server.requestHandler(router).webSocketHandler(s->{}).listen() From 886dcd039f78f746819bea60d7ba3128dd6304ac Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:13:42 +0800 Subject: [PATCH 05/93] =?UTF-8?q?fix(web-service):=20DbServiceImpl=20Threa?= =?UTF-8?q?d.sleep=20=E6=94=B9=E4=B8=BA=20vertx.setTimer=20=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E9=98=BB=E5=A1=9E=20event=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sayOk() 中使用 Thread.sleep(4000) 会阻塞 Vert.x event loop 线程, 改为 vertx.setTimer 异步延迟完成 promise。 --- .../cn/qaiu/lz/web/service/impl/DbServiceImpl.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java index 0d1ee25..4d8584a 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java @@ -42,12 +42,11 @@ public class DbServiceImpl implements DbService { @Override public Future sayOk(String data) { log.info("say ok1 -> wait..."); - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return Future.succeededFuture(JsonObject.mapFrom(JsonResult.data("Hi: " + data))); + Promise promise = Promise.promise(); + cn.qaiu.vx.core.util.VertxHolder.getVertxInstance().setTimer(4000, id -> { + promise.complete(JsonObject.mapFrom(JsonResult.data("Hi: " + data))); + }); + return promise.future(); } @Override From b77c8a80e9010be12b1142aeffc8476868fee804 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:14:32 +0800 Subject: [PATCH 06/93] =?UTF-8?q?fix(web-service):=20ParserApi=20=E4=B8=AD?= =?UTF-8?q?=20CacheManager/ServerApi=20=E6=94=B9=E4=B8=BA=20static=20?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E6=AF=8F=E6=AC=A1=E8=AF=B7=E6=B1=82=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CacheManager 和 ServerApi 无请求级状态,每次 new 会造成不必要的对象分配, 改为 static final 字段复用;同时修复 viewURL 中内联 new ServerApi()。 --- .../src/main/java/cn/qaiu/lz/web/controller/ParserApi.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java index 8d99c08..cb0b73b 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java @@ -49,8 +49,8 @@ public class ParserApi { return dbService.getStatisticsInfo(); } - private final CacheManager cacheManager = new CacheManager(); - private final ServerApi serverApi = new ServerApi(); + private static final CacheManager cacheManager = new CacheManager(); + private static final ServerApi serverApi = new ServerApi(); @RouteMapping(value = "/linkInfo", method = RouteMethod.GET) public Future parse(HttpServerRequest request, String pwd, String auth) { @@ -220,7 +220,7 @@ public class ParserApi { } String previewURL = SharedDataUtil.getJsonStringForServerConfig("previewURL"); - new ServerApi().parseJson(request, pwd, null).onSuccess(res -> { + serverApi.parseJson(request, pwd, null).onSuccess(res -> { redirect(response, previewURL, res); }).onFailure(e -> { ResponseUtil.fireJsonResultResponse(response, JsonResult.error(e.toString())); From 36b38421e51c345ea24b0f8406eb8dc58272fe62 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:18:43 +0800 Subject: [PATCH 07/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DJWT=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=97=B6=E5=BA=8F=E6=94=BB=E5=87=BB=EF=BC=9A?= =?UTF-8?q?=E4=BD=BF=E7=94=A8MessageDigest.isEqual()=E6=9B=BF=E4=BB=A3Stri?= =?UTF-8?q?ng.equals()=E8=BF=9B=E8=A1=8C=E7=AD=BE=E5=90=8D=E6=AF=94?= =?UTF-8?q?=E8=BE=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/lz/common/util/JwtUtil.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java b/web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java index f1ef675..0da695f 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java @@ -7,6 +7,7 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Instant; import java.time.LocalDateTime; @@ -93,9 +94,10 @@ public class JwtUtil { String encodedPayload = parts[1]; String signature = parts[2]; - // 验证签名 + // 验证签名(使用常量时间比较防止时序攻击) String expectedSignature = hmacSha256(encodedHeader + "." + encodedPayload, SECRET_KEY); - if (!expectedSignature.equals(signature)) { + if (!MessageDigest.isEqual(expectedSignature.getBytes(StandardCharsets.UTF_8), + signature.getBytes(StandardCharsets.UTF_8))) { return false; } From 4159b884de9a067ac18f7bd3e06b69073673bb66 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:19:22 +0800 Subject: [PATCH 08/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=9E=9A=E4=B8=BE=E5=92=8C=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=B3=84=E9=9C=B2=EF=BC=9A=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=A4=B1=E8=B4=A5=E6=8F=90=E7=A4=BA=E4=B8=BA?= =?UTF-8?q?'=E7=94=A8=E6=88=B7=E5=90=8D=E6=88=96=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E9=94=99=E8=AF=AF'=EF=BC=8C=E9=9A=90=E8=97=8F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=BC=82=E5=B8=B8=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/qaiu/lz/web/service/impl/UserServiceImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java index dbb53f3..ac567ef 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java @@ -125,18 +125,18 @@ public class UserServiceImpl implements UserService { if (rows.size() == 0) { promise.complete(new JsonObject() .put("success", false) - .put("message", "用户不存在")); + .put("message", "用户名或密码错误")); return; } - + Row row = rows.iterator().next(); SysUser existUser = rowToUser(row); - + // 验证密码 if (!PasswordUtil.checkPassword(user.getPassword(), existUser.getPassword())) { promise.complete(new JsonObject() .put("success", false) - .put("message", "密码错误")); + .put("message", "用户名或密码错误")); return; } @@ -169,7 +169,7 @@ public class UserServiceImpl implements UserService { log.error("登录查询失败", err); promise.complete(new JsonObject() .put("success", false) - .put("message", "登录失败: " + err.getMessage())); + .put("message", "登录失败,请稍后重试")); }); return promise.future(); From ba981d281f7a3e30b4a996e04efc07e64d483ca9 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:21:12 +0800 Subject: [PATCH 09/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DToken=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=B3=84=E9=9C=B2=EF=BC=9A=E6=97=A5=E5=BF=97=E4=B8=ADtoken?= =?UTF-8?q?=E4=BB=85=E6=89=93=E5=8D=B0=E5=89=8D8=E4=B8=AA=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=EF=BC=8C=E5=85=B6=E4=BD=99=E7=94=A8...=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 2 +- parser/src/main/java/cn/qaiu/parser/impl/IzTool.java | 8 ++++---- .../src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index 74e6546..bcfe83d 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -290,7 +290,7 @@ public class FjTool extends PanBase { if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); header0.set("appToken", token); - log.info("登录成功 token: {}", token); + log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); client.postAbs(UriTemplate.of(TOKEN_VERIFY_URL)) .setTemplateParam("uuid", uuid) .setTemplateParam("ts", tsEncode2) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index d8c9ac8..f3ad28e 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -101,8 +101,8 @@ public class IzTool extends PanBase { // 检查并输出认证状态 if (shareLinkInfo.getOtherParam().containsKey("auths")) { boolean isTempAuth = shareLinkInfo.getOtherParam().containsKey("__TEMP_AUTH_ADDED"); - log.info("文件解析检测到认证信息: isTempAuth={}, authFlag={}, token={}", - isTempAuth, authFlag, token != null ? "已登录(" + token.substring(0, Math.min(10, token.length())) + "...)" : "未登录"); + log.info("文件解析检测到认证信息: isTempAuth={}, authFlag={}, token={}", + isTempAuth, authFlag, token != null ? "已登录(" + token.substring(0, Math.min(8, token.length())) + "...)" : "未登录"); // 如果需要认证但还没有token,先执行登录 if ((isTempAuth || authFlag) && token == null) { @@ -118,7 +118,7 @@ public class IzTool extends PanBase { // 登录失败,继续使用免登录模式 }); } else if (token != null) { - log.info("文件解析使用已有token: {}...", token.substring(0, Math.min(10, token.length()))); + log.info("文件解析使用已有token: {}...", token.substring(0, Math.min(8, token.length()))); } } else { log.debug("文件解析无认证信息,使用免登录模式"); @@ -312,7 +312,7 @@ public class IzTool extends PanBase { if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); header.set("appToken", token); - log.info("登录成功 token: {}", token); + log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); promise1.complete(); } else { // 检查是否为临时认证 diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java index 459e8d7..0166672 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java @@ -281,7 +281,7 @@ public class IzToolWithAuth extends PanBase { if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); header.set("appToken", token); - log.info("登录成功 token: {}", token); + log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); promise1.complete(); } else { // 检查是否为临时认证 @@ -480,7 +480,7 @@ public class IzToolWithAuth extends PanBase { requestDirList(id, shareId, tsEncode, promise); }) .onSuccess(r -> { - log.info("目录解析登录成功,token={}, 使用 VIP 模式", token != null ? token.substring(0, 10) + "..." : "null"); + log.info("目录解析登录成功,token={}, 使用 VIP 模式", token != null ? token.substring(0, Math.min(8, token.length())) + "..." : "null"); requestDirList(id, shareId, tsEncode, promise); }); return; @@ -627,7 +627,7 @@ public class IzToolWithAuth extends PanBase { // 如果有 token,使用 VIP 接口 if (StringUtils.isNotBlank(appToken)) { - log.debug("parseById 使用 VIP 接口, appToken={}", appToken.substring(0, Math.min(10, appToken.length())) + "..."); + log.debug("parseById 使用 VIP 接口, appToken={}", appToken.substring(0, Math.min(8, appToken.length())) + "..."); webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL_VIP)) .putHeaders(header) .setTemplateParam("fidEncode", paramJson.getString("fidEncode")) From 42925c857c82427b5e44dfb7b586f18e61f7196e Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:22:52 +0800 Subject: [PATCH 10/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DPlayground=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E6=97=B6=E5=BA=8F=E6=94=BB=E5=87=BB=E5=92=8C=E5=A0=86?= =?UTF-8?q?=E6=A0=88=E6=B3=84=E9=9C=B2=EF=BC=9A=E4=BD=BF=E7=94=A8MessageDi?= =?UTF-8?q?gest.isEqual()=E6=AF=94=E8=BE=83=E5=AF=86=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E8=BF=94=E5=9B=9E=E7=BB=99=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E5=AE=8C=E6=95=B4=E5=A0=86=E6=A0=88=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/qaiu/lz/web/controller/PlaygroundApi.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java index 4972d86..dc96e1b 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java @@ -28,6 +28,8 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -129,8 +131,11 @@ public class PlaygroundApi { return promise.future(); } - // 验证密码 - if (config.getPassword().equals(password)) { + // 验证密码(使用常量时间比较防止时序攻击) + String storedPassword = config.getPassword(); + if (storedPassword != null && MessageDigest.isEqual( + storedPassword.getBytes(StandardCharsets.UTF_8), + password.getBytes(StandardCharsets.UTF_8))) { String token = config.generateToken(); JsonObject tokenData = new JsonObject().put("token", token); promise.complete(JsonResult.data(tokenData).toJsonObject()); @@ -299,7 +304,6 @@ public class PlaygroundApi { }).onFailure(e -> { long executionTime = System.currentTimeMillis() - startTime; String errorMessage = e.getMessage(); - String stackTrace = getStackTrace(e); log.error("演练场执行失败", e); @@ -317,7 +321,6 @@ public class PlaygroundApi { PlaygroundTestResp response = PlaygroundTestResp.builder() .success(false) .error(errorMessage) - .stackTrace(stackTrace) .executionTime(executionTime) .logs(respLogs) .build(); @@ -328,14 +331,12 @@ public class PlaygroundApi { } catch (Exception e) { long executionTime = System.currentTimeMillis() - startTime; String errorMessage = e.getMessage(); - String stackTrace = getStackTrace(e); log.error("演练场初始化失败", e); PlaygroundTestResp response = PlaygroundTestResp.builder() .success(false) .error(errorMessage) - .stackTrace(stackTrace) .executionTime(executionTime) .logs(new ArrayList<>()) .build(); @@ -346,8 +347,7 @@ public class PlaygroundApi { log.error("解析请求参数失败", e); promise.complete(JsonObject.mapFrom(PlaygroundTestResp.builder() .success(false) - .error("解析请求参数失败: " + e.getMessage()) - .stackTrace(getStackTrace(e)) + .error("解析请求参数失败") .build())); } From 838c86ae155a63a3c8beaf1f6e20540f76432ab1 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:23:17 +0800 Subject: [PATCH 11/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DJsParserExecutor=20DCL?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=BC=BA=E5=B0=91volatile=EF=BC=9AEXECUTOR?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=B7=BB=E5=8A=A0volatile=E4=BF=9D=E8=AF=81?= =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=8F=AF=E8=A7=81=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java index 69310b4..7226e0b 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java @@ -33,7 +33,7 @@ public class JsParserExecutor implements IPanTool, AutoCloseable { private static final Logger log = LoggerFactory.getLogger(JsParserExecutor.class); - private static WorkerExecutor EXECUTOR; + private static volatile WorkerExecutor EXECUTOR; private static final Object EXECUTOR_LOCK = new Object(); private static String FETCH_RUNTIME_JS = null; From d323376bedc12d889d02aee64f732ed04181342e Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:25:07 +0800 Subject: [PATCH 12/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DRateLimiter=20count++?= =?UTF-8?q?=E9=9D=9E=E5=8E=9F=E5=AD=90=E6=93=8D=E4=BD=9C=EF=BC=9A=E5=B0=86?= =?UTF-8?q?volatile=20int=E6=94=B9=E4=B8=BAAtomicInteger=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8incrementAndGet()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/qaiu/lz/common/interceptorImpl/RateLimiter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/RateLimiter.java b/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/RateLimiter.java index 0330d6f..fa3937e 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/RateLimiter.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/RateLimiter.java @@ -10,6 +10,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; @Slf4j public class RateLimiter { @@ -51,12 +52,12 @@ public class RateLimiter { return new RequestInfo(1, currentTime); } else { // 增加计数器 - requestInfo.count++; + requestInfo.count.incrementAndGet(); return requestInfo; } }); - if (info.count > MAX_REQUESTS) { + if (info.count.get() > MAX_REQUESTS) { // 超过限制 // 计算剩余时间 long remainingTime = TIME_WINDOW - (System.currentTimeMillis() - info.timestamp); @@ -71,11 +72,11 @@ public class RateLimiter { } private static class RequestInfo { - volatile int count; + final AtomicInteger count; volatile long timestamp; RequestInfo(int count, long time) { - this.count = count; + this.count = new AtomicInteger(count); this.timestamp = time; } } From 46b2eb1ccd273e31e297301f041bed21366598ba Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:26:12 +0800 Subject: [PATCH 13/93] =?UTF-8?q?=E4=BF=AE=E5=A4=8DRouterHandlerFactory?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E4=BF=A1=E6=81=AF=E6=B3=84=E9=9C=B2=EF=BC=9A?= =?UTF-8?q?Future=E5=A4=B1=E8=B4=A5=E5=92=8C=E5=BC=82=E5=B8=B8=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=E6=97=B6=E8=BF=94=E5=9B=9E=E9=80=9A=E7=94=A8=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=B6=88=E6=81=AF=EF=BC=8C=E8=AF=A6=E7=BB=86=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BB=85=E8=AE=B0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handlerfactory/RouterHandlerFactory.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java index aca7f7b..703fcc4 100644 --- a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java +++ b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java @@ -127,8 +127,9 @@ public class RouterHandlerFactory implements BaseHttpApi { // 错误请求处理 mainRouter.errorHandler(405, ctx -> doFireJsonResultResponse(ctx, JsonResult .error("Method Not Allowed", 405))); - mainRouter.errorHandler(404, ctx -> ctx.response().setStatusCode(404).setChunked(true) - .end("Internal server error: 404 not found")); + mainRouter.errorHandler(404, ctx -> { + ctx.response().setStatusCode(404).end("404 not found"); + }); return mainRouter; } @@ -408,22 +409,18 @@ public class RouterHandlerFactory implements BaseHttpApi { doFireJsonResultResponse(ctx, JsonResult.data(null)); } - }).onFailure(e -> doFireJsonResultResponse(ctx, JsonResult.error(e.getMessage()), 500)); + }).onFailure(e -> { + LOGGER.error("请求处理失败", e); + doFireJsonResultResponse(ctx, JsonResult.error("服务器内部错误"), 500); + }); } else { doFireJsonResultResponse(ctx, JsonResult.data(data)); } } } catch (Throwable e) { e.printStackTrace(); - String err = e.getMessage(); - if (e.getCause() != null) { - if (e.getCause() instanceof InvocationTargetException) { - err = ((InvocationTargetException) e.getCause()).getTargetException().getMessage(); - } else { - err = e.getCause().getMessage(); - } - } - doFireJsonResultResponse(ctx, JsonResult.error(err), 500); + LOGGER.error("请求处理异常", e); + doFireJsonResultResponse(ctx, JsonResult.error("服务器内部错误"), 500); } } From c0b18be5ab1cdb41321630bc575303d28cc0e238 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:36:20 +0800 Subject: [PATCH 14/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20ShareLinkInfo?= =?UTF-8?q?.getCacheKey()=20=E4=B8=AD=20otherParam.get("UA")=20=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=AF=BC=E8=87=B4=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/entity/ShareLinkInfo.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/entity/ShareLinkInfo.java b/parser/src/main/java/cn/qaiu/entity/ShareLinkInfo.java index 138c05a..abdac86 100644 --- a/parser/src/main/java/cn/qaiu/entity/ShareLinkInfo.java +++ b/parser/src/main/java/cn/qaiu/entity/ShareLinkInfo.java @@ -86,7 +86,10 @@ public class ShareLinkInfo { // 将type和shareKey组合成一个字符串作为缓存key String key = type + ":" + shareKey; if (type.equals("p115")) { - key += ("_" + otherParam.get("UA").toString().hashCode()); + Object ua = otherParam != null ? otherParam.get("UA") : null; + if (ua != null) { + key += ("_" + ua.toString().hashCode()); + } } return key; } From 0b8592559aacdc5a179a14b5493695be2d0ee773 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:36:47 +0800 Subject: [PATCH 15/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20CommonUtils.g?= =?UTF-8?q?etURLParams()=20=E4=B8=AD=20fullUrl.getQuery()=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20null=20=E6=97=B6=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/util/CommonUtils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/parser/src/main/java/cn/qaiu/util/CommonUtils.java b/parser/src/main/java/cn/qaiu/util/CommonUtils.java index 1c4cd58..d5391dd 100644 --- a/parser/src/main/java/cn/qaiu/util/CommonUtils.java +++ b/parser/src/main/java/cn/qaiu/util/CommonUtils.java @@ -33,6 +33,9 @@ public class CommonUtils { public static Map getURLParams(String url) throws MalformedURLException { URL fullUrl = new URL(url); String query = fullUrl.getQuery(); + if (query == null || query.isEmpty()) { + return new HashMap<>(); + } String[] params = query.split("&"); Map map = new HashMap<>(); for (String param : params) { From 9bcdcb2cb7206324189f07703805f0ea58d2034e Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:37:22 +0800 Subject: [PATCH 16/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20MkwTool=20?= =?UTF-8?q?=E4=B8=AD=20set-cookie=20=E4=B8=BA=20null=20=E6=97=B6=E7=9A=84?= =?UTF-8?q?=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java index df856dd..1d59e2c 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java @@ -29,7 +29,7 @@ public class MkwTool extends PanBase { clientSession.getAbs(shareUrl).send().onSuccess(result -> { String cookie = result.headers().get("set-cookie"); - if (!cookie.isEmpty()) { + if (cookie != null && !cookie.isEmpty()) { String regex = "([A-Za-z0-9_]+)=([A-Za-z0-9]+)"; Pattern pattern = Pattern.compile(regex); From a664ae3a565a270ce83eaddb4d6added6ef23819 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:38:27 +0800 Subject: [PATCH 17/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20ParserApi=20?= =?UTF-8?q?=E4=B8=AD=20redirectUrl()=20=E5=92=8C=20viewUrl()=20=E7=9A=84?= =?UTF-8?q?=20Promise=20=E6=9C=AA=20complete=20=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/lz/web/controller/ParserApi.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java index cb0b73b..ba7a56a 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java @@ -157,7 +157,10 @@ public class ParserApi { Promise promise = Promise.promise(); getFileDownUrl(type, param) - .onSuccess(res -> ResponseUtil.redirect(response, res)) + .onSuccess(res -> { + ResponseUtil.redirect(response, res); + promise.complete(); + }) .onFailure(t -> promise.fail(t.fillInStackTrace())); return promise.future(); } @@ -237,6 +240,7 @@ public class ParserApi { .onSuccess(res -> { String url = viewPrefix + URLEncoder.encode(res, StandardCharsets.UTF_8); ResponseUtil.redirect(response, url); + promise.complete(); }) .onFailure(t -> promise.fail(t.fillInStackTrace())); return promise.future(); From 46e9999e4c70e51d590b6fedc889692904d6e77d Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:39:05 +0800 Subject: [PATCH 18/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20CacheManager.?= =?UTF-8?q?updateTotalByField=20=E4=B8=AD=20getShareKeyTotal=20=E7=BC=BA?= =?UTF-8?q?=E5=B0=91=20onFailure=20=E5=AF=BC=E8=87=B4=20Promise=20?= =?UTF-8?q?=E6=B0=B8=E4=B8=8D=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/lz/common/cache/CacheManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java index 77f86f1..83c871d 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java @@ -165,6 +165,9 @@ public class CacheManager { promise.fail(e); LOGGER.error("updateTotalByField: ", e); }); + }).onFailure(e -> { + promise.fail(e); + LOGGER.error("getShareKeyTotal in updateTotalByField: ", e); }); return promise.future(); } From 1dddec110ed24fde860cf62a69043659670e422f Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:39:31 +0800 Subject: [PATCH 19/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20PasswordUtil.?= =?UTF-8?q?checkPassword=20=E4=B8=AD=E7=9A=84=E6=97=B6=E5=BA=8F=E6=94=BB?= =?UTF-8?q?=E5=87=BB=E6=BC=8F=E6=B4=9E=EF=BC=8C=E4=BD=BF=E7=94=A8=20Messag?= =?UTF-8?q?eDigest.isEqual()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/lz/common/util/PasswordUtil.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/util/PasswordUtil.java b/web-service/src/main/java/cn/qaiu/lz/common/util/PasswordUtil.java index 6d2ae24..62c466f 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/util/PasswordUtil.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/util/PasswordUtil.java @@ -80,8 +80,10 @@ public class PasswordUtil { byte[] calculatedHash = md.digest(plainPassword.getBytes(StandardCharsets.UTF_8)); String calculatedHashBase64 = Base64.getEncoder().encodeToString(calculatedHash); - // 比较计算出的哈希值和存储的哈希值 - return hashBase64.equals(calculatedHashBase64); + // 比较计算出的哈希值和存储的哈希值(使用常量时间比较防止时序攻击) + return MessageDigest.isEqual( + hashBase64.getBytes(StandardCharsets.UTF_8), + calculatedHashBase64.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { // 如果发生异常(例如格式不正确),返回false return false; From 4586138bf1f3f49ea7170b5fc84ac5b300eba7f8 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:40:32 +0800 Subject: [PATCH 20/93] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20AESUtils.getR?= =?UTF-8?q?andomString=20=E4=BD=BF=E7=94=A8=E4=B8=8D=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E7=9A=84=20Random=EF=BC=8C=E6=94=B9=E4=B8=BA=20SecureRandom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/util/AESUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/util/AESUtils.java b/parser/src/main/java/cn/qaiu/util/AESUtils.java index 2fc41c7..a3a42b0 100644 --- a/parser/src/main/java/cn/qaiu/util/AESUtils.java +++ b/parser/src/main/java/cn/qaiu/util/AESUtils.java @@ -14,7 +14,6 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Date; import java.util.HexFormat; -import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -299,7 +298,7 @@ public class AESUtils { //length用户要求产生字符串的长度 public static String getRandomString(int length){ String str="abcdefghijklmnopqrstuvwxyz0123456789"; - Random random=new Random(); + SecureRandom random=new SecureRandom(); StringBuilder sb=new StringBuilder(); for(int i=0;i Date: Fri, 29 May 2026 02:41:00 +0800 Subject: [PATCH 21/93] =?UTF-8?q?fix:=20=E5=B0=86=20secret.yml=20=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=20.gitignore=20=E9=98=B2=E6=AD=A2=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=B3=84=E9=9C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 32c8707..6cfc6c6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ target/ sdkTest.log app.yml app-local.yml +secret.yml #some local files From 5a08ed68c260e7f5ee78aee6f8942c580f430097 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:47:27 +0800 Subject: [PATCH 22/93] =?UTF-8?q?fix:=20IzTool=20=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=AE=89=E5=85=A8=20-=20token/authFlag=20=E6=94=B9=E4=B8=BA=20?= =?UTF-8?q?volatile=EF=BC=8Cheader=20=E5=89=AF=E6=9C=AC=E6=9B=BF=E4=BB=A3?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/qaiu/parser/impl/IzTool.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index f3ad28e..044b7e8 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -89,8 +89,8 @@ public class IzTool extends PanBase { String uuid = UUID.randomUUID().toString().toLowerCase(); // 也可以使用 UUID.randomUUID().toString() - public static String token = null; - public static boolean authFlag = true; + public static volatile String token = null; + public static volatile boolean authFlag = true; public Future parse() { @@ -247,7 +247,7 @@ public class IzTool extends PanBase { log.warn("登录失败: {}", failRes.getMessage()); fail(failRes.getMessage()); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); @@ -263,12 +263,12 @@ public class IzTool extends PanBase { log.warn("重新登录失败: {}", failRes.getMessage()); fail(failRes.getMessage()); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); } else { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); } @@ -311,7 +311,9 @@ public class IzTool extends PanBase { JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); - header.set("appToken", token); + MultiMap h = MultiMap.caseInsensitiveMultiMap(); + h.addAll(header); + h.set("appToken", token); log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); promise1.complete(); } else { From 79c9eb3dda280174f0fdc8473ff7a7d0851dde16 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:48:13 +0800 Subject: [PATCH 23/93] =?UTF-8?q?fix:=20FjTool=20=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=AE=89=E5=85=A8=20-=20token/userId/authFlag=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20volatile=EF=BC=8Cheader0=20=E5=89=AF=E6=9C=AC?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=E5=85=B1=E4=BA=AB=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index bcfe83d..1a75e4d 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -109,9 +109,9 @@ public class FjTool extends PanBase { // String uuid = UUID.randomUUID().toString().toLowerCase(); // 也可以使用 UUID.randomUUID().toString() - static String token = null; - static String userId = null; - public static boolean authFlag = true; + static volatile String token = null; + static volatile String userId = null; + public static volatile boolean authFlag = true; public FjTool(ShareLinkInfo shareLinkInfo) { super(shareLinkInfo); @@ -289,12 +289,14 @@ public class FjTool extends PanBase { JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); - header0.set("appToken", token); + MultiMap h0 = MultiMap.caseInsensitiveMultiMap(); + h0.addAll(header0); + h0.set("appToken", token); log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); client.postAbs(UriTemplate.of(TOKEN_VERIFY_URL)) .setTemplateParam("uuid", uuid) .setTemplateParam("ts", tsEncode2) - .putHeaders(header0).send().onSuccess(res -> { + .putHeaders(h0).send().onSuccess(res -> { if (asJson(res).getInteger("code") == 200) { if (FjTool.userId == null) { FjTool.userId = asJson(res).getJsonObject("map").getString("userId"); From aef1b9ab11cd97e6c6b3ce7f3d34cca4de361273 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:49:01 +0800 Subject: [PATCH 24/93] =?UTF-8?q?fix:=20IzToolWithAuth=20=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E5=AE=89=E5=85=A8=20-=20token/authFlag=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20volatile=EF=BC=8Cheader=20=E5=89=AF=E6=9C=AC?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=E5=85=B1=E4=BA=AB=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/qaiu/parser/impl/IzToolWithAuth.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java index 0166672..ee1a095 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java @@ -88,8 +88,8 @@ public class IzToolWithAuth extends PanBase { String uuid = UUID.randomUUID().toString().toLowerCase(); // 也可以使用 UUID.randomUUID().toString() - public static String token = null; - public static boolean authFlag = true; + public static volatile String token = null; + public static volatile boolean authFlag = true; public Future parse() { @@ -216,7 +216,7 @@ public class IzToolWithAuth extends PanBase { log.warn("登录失败: {}", failRes.getMessage()); fail(failRes.getMessage()); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); @@ -232,12 +232,12 @@ public class IzToolWithAuth extends PanBase { log.warn("重新登录失败: {}", failRes.getMessage()); fail(failRes.getMessage()); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); } else { - httpRequest.setTemplateParam("appToken", header.get("appToken")) + httpRequest.setTemplateParam("appToken", token) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); } @@ -280,7 +280,9 @@ public class IzToolWithAuth extends PanBase { JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); - header.set("appToken", token); + MultiMap h = MultiMap.caseInsensitiveMultiMap(); + h.addAll(header); + h.set("appToken", token); log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); promise1.complete(); } else { From 746c7ad5b3754b1d196ca3a43e0e72218416453c Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:50:06 +0800 Subject: [PATCH 25/93] =?UTF-8?q?fix:=20=E6=9B=BF=E6=8D=A2=20e.printStackT?= =?UTF-8?q?race()=20=E5=92=8C=20System.out.println=20=E4=B8=BA=20logger=20?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HttpProxyVerticle: err.printStackTrace() / e.printStackTrace() -> LOGGER.error() - RouterHandlerFactory: 5处 printStackTrace() -> LOGGER.error() - CommonUtil: e.printStackTrace() -> LOGGER.error() - ReflectionUtil: 新增 LOGGER,3处 printStackTrace() -> LOGGER.error() - CreateDatabase: e.printStackTrace() -> LOGGER.error() - URLUtil: 新增 LOGGER,e.printStackTrace() -> LOGGER.error() - LzTool: e.printStackTrace() -> log.error() - MkwTool: 3处 System.out.println + 1处 printStackTrace -> log.debug()/log.error() - PdbTool: e.printStackTrace() -> log.error() - ParserApi: t.printStackTrace() -> log.error() - CacheManager: 2处 Throwable::printStackTrace -> LOGGER.error() - QQTool: 3处 System.out.println -> log.debug() - FjTool: System.out.println -> log.debug() --- .../src/main/java/cn/qaiu/db/ddl/CreateDatabase.java | 2 +- .../vx/core/handlerfactory/RouterHandlerFactory.java | 9 ++++----- .../main/java/cn/qaiu/vx/core/util/CommonUtil.java | 2 +- .../java/cn/qaiu/vx/core/util/ReflectionUtil.java | 11 ++++++++--- .../cn/qaiu/vx/core/verticle/HttpProxyVerticle.java | 4 ++-- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 2 +- parser/src/main/java/cn/qaiu/parser/impl/LzTool.java | 2 +- parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java | 8 ++++---- parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java | 2 +- parser/src/main/java/cn/qaiu/parser/impl/QQTool.java | 6 +++--- parser/src/main/java/cn/qaiu/util/URLUtil.java | 7 ++++++- .../java/cn/qaiu/lz/common/cache/CacheManager.java | 4 ++-- .../java/cn/qaiu/lz/web/controller/ParserApi.java | 2 +- 13 files changed, 35 insertions(+), 26 deletions(-) diff --git a/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java b/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java index 6749c15..f740c0f 100644 --- a/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java +++ b/core-database/src/main/java/cn/qaiu/db/ddl/CreateDatabase.java @@ -53,7 +53,7 @@ public class CreateDatabase { stmt.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); LOGGER.info(">>>>>>>>>>> 数据库'{}'创建成功 <<<<<<<<<<<<", dbName); } catch (SQLException e) { - e.printStackTrace(); + LOGGER.error("创建数据库失败", e); } } diff --git a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java index 703fcc4..f573f6a 100644 --- a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java +++ b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java @@ -180,7 +180,7 @@ public class RouterHandlerFactory implements BaseHttpApi { if (ctx.statusCode() == 503 || ctx.failure() == null) { doFireJsonResultResponse(ctx, JsonResult.error("未知异常, 请联系管理员"), 503); } else { - ctx.failure().printStackTrace(); + LOGGER.error("路由处理失败", ctx.failure()); doFireJsonResultResponse(ctx, JsonResult.error(ctx.failure().getMessage()), 500); } }); @@ -199,7 +199,7 @@ public class RouterHandlerFactory implements BaseHttpApi { try { ReflectionUtil.invokeWithArguments(method, instance, sock); } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("WebSocket处理异常", e); } }); if (url.endsWith("*")) { @@ -323,7 +323,7 @@ public class RouterHandlerFactory implements BaseHttpApi { parameterValueList.put(k, entity); } } catch (ClassNotFoundException e) { - e.printStackTrace(); + LOGGER.error("实体类绑定异常: {}", typeName, e); } } }); @@ -366,7 +366,7 @@ public class RouterHandlerFactory implements BaseHttpApi { Object entity = ParamUtil.multiMapToEntity(queryParams, aClass); parameterValueList.put(k, entity); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error("参数绑定异常: {}", v.getRight().getName(), e); } } else if (parameterValueList.get(k) == null && JsonObject.class.getName().equals(v.getRight().getName())) { @@ -418,7 +418,6 @@ public class RouterHandlerFactory implements BaseHttpApi { } } } catch (Throwable e) { - e.printStackTrace(); LOGGER.error("请求处理异常", e); doFireJsonResultResponse(ctx, JsonResult.error("服务器内部错误"), 500); } diff --git a/core/src/main/java/cn/qaiu/vx/core/util/CommonUtil.java b/core/src/main/java/cn/qaiu/vx/core/util/CommonUtil.java index d9da4ff..3f77baa 100644 --- a/core/src/main/java/cn/qaiu/vx/core/util/CommonUtil.java +++ b/core/src/main/java/cn/qaiu/vx/core/util/CommonUtil.java @@ -153,7 +153,7 @@ public class CommonUtil { appVersion = properties.getProperty("app.version") + "build" + properties.getProperty("build"); } } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("读取app.properties失败", e); } } return appVersion; diff --git a/core/src/main/java/cn/qaiu/vx/core/util/ReflectionUtil.java b/core/src/main/java/cn/qaiu/vx/core/util/ReflectionUtil.java index 3d30eee..8cb1b50 100644 --- a/core/src/main/java/cn/qaiu/vx/core/util/ReflectionUtil.java +++ b/core/src/main/java/cn/qaiu/vx/core/util/ReflectionUtil.java @@ -25,6 +25,9 @@ import java.net.URL; import java.text.ParseException; import java.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static cn.qaiu.vx.core.util.ConfigConstant.BASE_LOCATIONS; /** @@ -36,6 +39,8 @@ import static cn.qaiu.vx.core.util.ConfigConstant.BASE_LOCATIONS; */ public final class ReflectionUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtil.class); + // 缓存Reflections实例,避免重复扫描(每次扫描约35K+值,耗时1-3秒,占用大量内存) private static final Map REFLECTIONS_CACHE = new java.util.concurrent.ConcurrentHashMap<>(); @@ -128,7 +133,7 @@ public final class ReflectionUtil { parameterTypes[j - k])); } } catch (NotFoundException e) { - e.printStackTrace(); + LOGGER.error("获取方法参数失败", e); } return paramMap; } @@ -183,7 +188,7 @@ public final class ReflectionUtil { try { return DateUtils.parseDate(value, fmt); } catch (ParseException e) { - e.printStackTrace(); + LOGGER.error("日期解析失败: {}", value, e); throw new RuntimeException("无法将格式化日期"); } default: @@ -215,7 +220,7 @@ public final class ReflectionUtil { } return arr; } catch (Exception e) { - e.printStackTrace(); + LOGGER.error("数组类型转换失败: {}", value, e); } return null; } diff --git a/core/src/main/java/cn/qaiu/vx/core/verticle/HttpProxyVerticle.java b/core/src/main/java/cn/qaiu/vx/core/verticle/HttpProxyVerticle.java index aa713ea..c6fdfc3 100644 --- a/core/src/main/java/cn/qaiu/vx/core/verticle/HttpProxyVerticle.java +++ b/core/src/main/java/cn/qaiu/vx/core/verticle/HttpProxyVerticle.java @@ -196,7 +196,7 @@ public class HttpProxyVerticle extends AbstractVerticle { ); }) .onFailure(err -> { - err.printStackTrace(); + LOGGER.error("HTTP请求失败", err); clientRequest.response().setStatusCode(502).end("Bad Gateway: Request failed"); }); } @@ -222,7 +222,7 @@ public class HttpProxyVerticle extends AbstractVerticle { } return port; } catch (Exception e) { - e.printStackTrace(); + LOGGER.error("提取端口失败: {}", urlString, e); // 出现异常时返回 -1,表示提取失败 return -1; } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index 1a75e4d..b9a3031 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -497,7 +497,7 @@ public class FjTool extends PanBase { JsonArray list; try { JsonObject jsonObject = asJson(res); - System.out.println(jsonObject.encodePrettily()); + log.debug("目录列表: {}", jsonObject.encodePrettily()); list = jsonObject.getJsonArray("list"); } catch (Exception e) { log.error("解析目录失败: {}", res.bodyAsString()); diff --git a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java index c87bb96..5f41a2b 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java @@ -107,7 +107,7 @@ public class LzTool extends PanBase { try { setFileInfo(html, shareLinkInfo); } catch (Exception e) { - e.printStackTrace(); + log.error("文件信息解析异常", e); } // 匹配iframe Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\""); diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java index 1d59e2c..5686703 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/MkwTool.java @@ -35,13 +35,13 @@ public class MkwTool extends PanBase { Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(cookie); if (matcher.find()) { - System.out.println(matcher.group(1)); - System.out.println(matcher.group(2)); + log.debug("cookie key: {}", matcher.group(1)); + log.debug("cookie value: {}", matcher.group(2)); var key = matcher.group(1); var token = matcher.group(2); String sign = JsExecUtils.getKwSign(token, key); - System.out.println(sign); + log.debug("sign: {}", sign); clientSession.getAbs(UriTemplate.of(API_URL)).setTemplateParam("mid", shareLinkInfo.getShareKey()) .putHeader("Secret", sign).send().onSuccess(res -> { JsonObject json = asJson(res); @@ -54,7 +54,7 @@ public class MkwTool extends PanBase { } } catch (Exception e) { - e.printStackTrace(); + log.error("解析失败", e); fail("解析失败"); } }); diff --git a/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java b/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java index 9edac9d..1561b1c 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java @@ -85,7 +85,7 @@ public class PdbTool extends PanBase implements IPanTool { }) .onFailure(handleFail()); } catch (Exception e) { - e.printStackTrace(); + log.error("URL编码异常", e); } }) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/QQTool.java b/parser/src/main/java/cn/qaiu/parser/impl/QQTool.java index f5e8cd7..fe6022d 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/QQTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/QQTool.java @@ -74,9 +74,9 @@ public class QQTool extends PanBase { }); // 调试匹配的情况 - System.out.println("文件名称: " + filename); - System.out.println("文件大小: " + filesize); - System.out.println("文件直链: " + fileurl); + log.debug("文件名称: {}", filename); + log.debug("文件大小: {}", filesize); + log.debug("文件直链: {}", fileurl); // 提交 promise.complete(fileurl.replace("\\x26", "&")); diff --git a/parser/src/main/java/cn/qaiu/util/URLUtil.java b/parser/src/main/java/cn/qaiu/util/URLUtil.java index 916a27f..a8b7bb1 100644 --- a/parser/src/main/java/cn/qaiu/util/URLUtil.java +++ b/parser/src/main/java/cn/qaiu/util/URLUtil.java @@ -2,6 +2,9 @@ package cn.qaiu.util; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.net.URL; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -10,6 +13,8 @@ import java.util.Map; public class URLUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(URLUtil.class); + private final Map queryParams = new HashMap<>(); // 构造函数,传入URL并解析参数 @@ -31,7 +36,7 @@ public class URLUtil { } } } catch (Exception e) { - e.printStackTrace(); + LOGGER.error("URL解析失败: {}", url, e); } } diff --git a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java index 83c871d..cd385c0 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java @@ -89,7 +89,7 @@ public class CacheManager { } else { LOGGER.warn("No rows affected when updating cache link info for shareKey: {}", cacheLinkInfo.getShareKey()); } - }).onFailure(Throwable::printStackTrace); + }).onFailure(e -> LOGGER.error("缓存链接更新失败", e)); if (cacheLinkInfo.getFileInfo() != null) { String sql2 = """ @@ -123,7 +123,7 @@ public class CacheManager { } else { LOGGER.warn("No rows affected when inserting pan file info for shareKey: {}", cacheLinkInfo.getShareKey()); } - }).onFailure(Throwable::printStackTrace); + }).onFailure(e -> LOGGER.error("文件信息插入失败", e)); } }); } diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java index ba7a56a..e413333 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java @@ -76,7 +76,7 @@ public class ParserApi { } promise.complete(build); }).onFailure(t->{ - t.printStackTrace(); + log.error("获取统计信息失败", t); promise.complete(build); }); return promise.future(); From dc629a31264324e2b41f4dbfb3d28007c4a4fd53 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:53:32 +0800 Subject: [PATCH 26/93] =?UTF-8?q?fix:=20P115Tool=20=E4=B8=AD=20UA=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=B8=BA=20null=20=E6=97=B6=E7=9A=84=20NPE?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E9=BB=98=E8=AE=A4=20User-Agent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/parser/impl/P115Tool.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/P115Tool.java b/parser/src/main/java/cn/qaiu/parser/impl/P115Tool.java index a02c586..0e3a23f 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/P115Tool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/P115Tool.java @@ -21,6 +21,8 @@ public class P115Tool extends PanBase { private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "share/skip_login_downurl"; + private static final String DEFAULT_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"; + private static final MultiMap header; static { @@ -49,9 +51,11 @@ public class P115Tool extends PanBase { public Future parse() { // 第一次请求 获取文件信息 + Object uaObj = shareLinkInfo.getOtherParam().get("UA"); + String ua = uaObj != null ? uaObj.toString() : DEFAULT_UA; client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)) .putHeaders(header) - .putHeader("User-Agent", shareLinkInfo.getOtherParam().get("UA").toString()) + .putHeader("User-Agent", ua) .setTemplateParam("dataKey", shareLinkInfo.getShareKey()) .setTemplateParam("dataPwd", shareLinkInfo.getSharePassword()) .send().onSuccess(res -> { @@ -68,7 +72,7 @@ public class P115Tool extends PanBase { // share_code={dataKey}&receive_code={dataPwd}&file_id={file_id} client.postAbs(SECOND_REQUEST_URL) .putHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") - .putHeader("User-Agent", shareLinkInfo.getOtherParam().get("UA").toString()) + .putHeader("User-Agent", ua) .sendForm(MultiMap.caseInsensitiveMultiMap() .set("share_code", shareLinkInfo.getShareKey()) .set("receive_code", shareLinkInfo.getSharePassword()) From fa4028296fcfbbe2e442e35b9f2dd32d37cdb496 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:54:00 +0800 Subject: [PATCH 27/93] =?UTF-8?q?fix:=20FjTool=20parseFileList=20=E4=B8=AD?= =?UTF-8?q?=20uuid=20=E5=8F=82=E6=95=B0=E4=B8=BA=20null=20=E6=97=B6?= =?UTF-8?q?=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index b9a3031..b46137f 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -456,7 +456,10 @@ public class FjTool extends PanBase { // 如果参数里的目录ID不为空,则直接解析目录 String dirId = (String) shareLinkInfo.getOtherParam().get("dirId"); if (dirId != null && !dirId.isEmpty()) { - uuid = shareLinkInfo.getOtherParam().get("uuid").toString(); + Object uuidObj = shareLinkInfo.getOtherParam().get("uuid"); + if (uuidObj != null) { + uuid = uuidObj.toString(); + } parserDir(dirId, shareId, promise0); return promise0.future(); } From da715c8a8f5e6d88b62eb4c8a98089cba0719954 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:55:32 +0800 Subject: [PATCH 28/93] =?UTF-8?q?fix:=20CacheManager=20=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E5=8F=8C=E6=8B=AC=E5=8F=B7=E5=88=9D=E5=A7=8B=E5=8C=96=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E6=A0=87=E5=87=86=20HashMap=20=E5=86=99?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/qaiu/lz/common/cache/CacheManager.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java index cd385c0..3980721 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java @@ -153,13 +153,13 @@ public class CacheManager { getShareKeyTotal(shareKey, fieldLower).onSuccess(total -> { Integer newTotal = (total == null ? 0 : total) + 1; + Map updateParams = new HashMap<>(); + updateParams.put("panType", getShareType(shareKey)); + updateParams.put("shareKey", shareKey); + updateParams.put("total", newTotal); + updateParams.put("ts", System.currentTimeMillis()); SqlTemplate.forUpdate(jdbcPool, sql) - .execute(new HashMap<>() {{ - put("panType", getShareType(shareKey)); - put("shareKey", shareKey); - put("total", newTotal); - put("ts", System.currentTimeMillis()); - }}) + .execute(updateParams) .onSuccess(res -> promise.complete(res.rowCount())) .onFailure(e->{ promise.fail(e); @@ -265,10 +265,9 @@ public class CacheManager { .onSuccess(res -> { if(res.iterator().hasNext()) { JsonObject next = res.iterator().next(); - Map resp = new HashMap<>(){{ - put("hit_total" ,next.getInteger("hit_total")); - put("parser_total" ,next.getInteger("parser_total")); - }}; + Map resp = new HashMap<>(); + resp.put("hit_total", next.getInteger("hit_total")); + resp.put("parser_total", next.getInteger("parser_total")); promise.complete(resp); } else { promise.complete(); From 377bc12cf961d11918d0e921ea0b3cd172395f48 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 02:55:57 +0800 Subject: [PATCH 29/93] =?UTF-8?q?fix:=20Dockerfile=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=9D=9E=20root=20=E7=94=A8=E6=88=B7=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E5=BA=94=E7=94=A8=EF=BC=8C=E6=8F=90=E5=8D=87=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 8d50655..853eb64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,4 +14,8 @@ RUN unzip netdisk-fast-download-bin.zip && \ EXPOSE 6400 6401 +RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser && \ + chown -R appuser:appgroup /app +USER appuser + ENTRYPOINT ["sh", "run.sh"] From 54d2a8189c65e62503ec282725b6510b1d65a5e8 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:07:22 +0800 Subject: [PATCH 30/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20log?= =?UTF-8?q?back=20=E7=89=88=E6=9C=AC=201.5.18=20->=201.5.32=20(=E6=A0=B9?= =?UTF-8?q?=20pom.xml)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 CVE-2024-12798 等 3 个安全漏洞 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 221b307..113bf41 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 2.0.0 2.18.6 - 1.5.18 + 1.5.32 4.13.2 From 080206925f8636963e145b65c595db65c8321f26 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:07:39 +0800 Subject: [PATCH 31/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20log?= =?UTF-8?q?back=20=E7=89=88=E6=9C=AC=201.5.19=20->=201.5.32=20(parser=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 CVE-2024-12798 等 3 个安全漏洞 --- parser/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/pom.xml b/parser/pom.xml index b5791d1..a276ed3 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -65,7 +65,7 @@ 2.0.16 3.18.0 2.18.6 - 1.5.19 + 1.5.32 4.13.2 From 9cb32b3e8f49fbd3a8dc3d2758aa10eb503d34a5 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:08:00 +0800 Subject: [PATCH 32/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20pos?= =?UTF-8?q?tgresql=20=E9=A9=B1=E5=8A=A8=E7=89=88=E6=9C=AC=2042.7.3=20->=20?= =?UTF-8?q?42.7.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 SCRAM 认证 DoS 漏洞 --- core-database/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-database/pom.xml b/core-database/pom.xml index 398fd2d..0ae8493 100644 --- a/core-database/pom.xml +++ b/core-database/pom.xml @@ -65,7 +65,7 @@ org.postgresql postgresql - 42.7.3 + 42.7.11 From 8f77d9fe98e577dd5e506c57b182e4fa13ea2b25 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:08:27 +0800 Subject: [PATCH 33/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20Ver?= =?UTF-8?q?t.x=20=E7=89=88=E6=9C=AC=204.5.24=20->=204.5.27=20(=E6=A0=B9=20?= =?UTF-8?q?pom.xml)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 SslContext 缓存 DoS 漏洞 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 113bf41..2774c9b 100644 --- a/pom.xml +++ b/pom.xml @@ -25,8 +25,8 @@ ${project.basedir}/web-service/target/package - - 4.5.24 + + 4.5.27 0.10.2 1.18.38 2.0.16 From 2bb9912cf5296474a35a9c81d021f253df01e1c7 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:08:43 +0800 Subject: [PATCH 34/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20Ver?= =?UTF-8?q?t.x=20=E7=89=88=E6=9C=AC=204.5.24=20->=204.5.27=20(parser=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 SslContext 缓存 DoS 漏洞 --- parser/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/pom.xml b/parser/pom.xml index a276ed3..4d991c4 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -59,7 +59,7 @@ UTF-8 - 4.5.24 + 4.5.27 0.10.2 1.18.38 2.0.16 From aa3057170949c371682a51f42ec4d3b474f5ef82 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:08:59 +0800 Subject: [PATCH 35/93] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20axi?= =?UTF-8?q?os=20=E7=89=88=E6=9C=AC=201.13.5=20->=201.16.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 14 个安全漏洞 --- web-front/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-front/package.json b/web-front/package.json index b73baba..814d708 100644 --- a/web-front/package.json +++ b/web-front/package.json @@ -13,7 +13,7 @@ "@element-plus/icons-vue": "^2.3.1", "@monaco-editor/loader": "^1.4.0", "@vueuse/core": "^11.2.0", - "axios": "1.13.5", + "axios": "1.16.1", "clipboard": "^2.0.11", "core-js": "^3.8.3", "crypto-js": "^4.2.0", From 07a330cfd4a062fd2024bd8538f493eb952b1670 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:14:10 +0800 Subject: [PATCH 36/93] =?UTF-8?q?fix:=20LocalConstant=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=20ConcurrentHashMap=20=E4=BF=9D=E8=AF=81=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E5=AE=89=E5=85=A8=EF=BC=8CLzTool=20=E6=96=B9=E6=B3=95=E5=90=8D?= =?UTF-8?q?=E6=8B=BC=E5=86=99=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LocalConstant: HashMap → ConcurrentHashMap,put() 改用 putIfAbsent 消除 check-then-act 竞态 - LzTool: 私有方法 setDateAndComplate → setDateAndComplete(拼写修正,仅内部调用) --- core/src/main/java/cn/qaiu/vx/core/util/LocalConstant.java | 7 +++---- parser/src/main/java/cn/qaiu/parser/impl/LzTool.java | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/util/LocalConstant.java b/core/src/main/java/cn/qaiu/vx/core/util/LocalConstant.java index 0a7fa8c..6111e9b 100644 --- a/core/src/main/java/cn/qaiu/vx/core/util/LocalConstant.java +++ b/core/src/main/java/cn/qaiu/vx/core/util/LocalConstant.java @@ -1,7 +1,7 @@ package cn.qaiu.vx.core.util; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * vertx 上下文外的本地容器 为不在vertx线程的方法传递数据 @@ -10,11 +10,10 @@ import java.util.Map; * @author QAIU */ public class LocalConstant { - private static final Map LOCAL_CONST = new HashMap<>(); + private static final Map LOCAL_CONST = new ConcurrentHashMap<>(); public static Map put(String k, Object v) { - if (LOCAL_CONST.containsKey(k)) return LOCAL_CONST; - LOCAL_CONST.put(k, v); + LOCAL_CONST.putIfAbsent(k, v); return LOCAL_CONST; } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java index 5f41a2b..63900e3 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java @@ -290,12 +290,12 @@ public class LzTool extends PanBase { if (location0 == null) { fail(downUrl + " -> 直链获取失败2, 可能分享已失效"); } else { - setDateAndComplate(location0); + setDateAndComplete(location0); } }).onFailure(handleFail(downUrl)); return; } - setDateAndComplate(location); + setDateAndComplete(location); }) .onFailure(handleFail(downUrl)); } catch (Exception e) { @@ -304,7 +304,7 @@ public class LzTool extends PanBase { }).onFailure(handleFail(url)); } - private void setDateAndComplate(String location0) { + private void setDateAndComplete(String location0) { // 分享时间 提取url中的时间戳格式:lanzoui.com/abc/abc/yyyy/mm/dd/ String regex = "(\\d{4}/\\d{1,2}/\\d{1,2})"; Matcher matcher = Pattern.compile(regex).matcher(location0); From 29d8bf3ea4f9acd403eeee2044be94b6618e512c Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:24:53 +0800 Subject: [PATCH 37/93] fix(security): add noopener,noreferrer to all window.open calls Prevent reverse tabnapping by adding security attributes to all window.open calls that open links in new tabs. --- web-front/src/views/ClientLinks.vue | 4 ++-- web-front/src/views/Home.vue | 4 ++-- web-front/src/views/Playground.vue | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web-front/src/views/ClientLinks.vue b/web-front/src/views/ClientLinks.vue index 0080a6b..00626d2 100644 --- a/web-front/src/views/ClientLinks.vue +++ b/web-front/src/views/ClientLinks.vue @@ -369,7 +369,7 @@ export default { copyToClipboard(link) return } - window.open(link, '_blank') + window.open(link, '_blank', 'noopener,noreferrer') ElMessage.success('正在唤起迅雷下载') break @@ -386,7 +386,7 @@ export default { // 下载客户端 const downloadClient = (type) => { const url = getClientDownloadUrl(type) - window.open(url, '_blank') + window.open(url, '_blank', 'noopener,noreferrer') ElMessage.success(`正在跳转到 ${getClientDisplayName(type)} 下载页面`) } diff --git a/web-front/src/views/Home.vue b/web-front/src/views/Home.vue index 6e9f719..ca29b65 100644 --- a/web-front/src/views/Home.vue +++ b/web-front/src/views/Home.vue @@ -1309,7 +1309,7 @@ export default { // 文件点击处理 handleFileClick(file) { if (file.parserUrl) { - window.open(file.parserUrl, '_blank') + window.open(file.parserUrl, '_blank', 'noopener,noreferrer') } else { this.$message.warning('该文件暂无下载链接') } @@ -1439,7 +1439,7 @@ export default { 错误信息:${JSON.stringify(this.errorDetail, null, 2)}`; navigator.clipboard.writeText(text).then(() => { this.$message.success('已复制分享信息和错误详情'); - window.open('https://github.com/qaiu/netdisk-fast-download/issues/new', '_blank'); + window.open('https://github.com/qaiu/netdisk-fast-download/issues/new', '_blank', 'noopener,noreferrer'); }).catch(() => { this.$message.error('复制失败'); }); diff --git a/web-front/src/views/Playground.vue b/web-front/src/views/Playground.vue index 42b79f2..7385466 100644 --- a/web-front/src/views/Playground.vue +++ b/web-front/src/views/Playground.vue @@ -1178,7 +1178,7 @@ function parseById(shareLinkInfo, http, logger) { // 新窗口打开首页 const goHomeInNewWindow = () => { - window.open('/', '_blank'); + window.open('/', '_blank', 'noopener,noreferrer'); }; // 检查是否有未保存的文件 From 5a0dc69186bcde0bca118e57f94d69f5f43b8b76 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:28:22 +0800 Subject: [PATCH 38/93] chore: remove debug console.log statements Remove debug logging from production code while preserving console.error and console.warn for actual error/warning cases. --- web-front/src/components/DarkMode.vue | 1 - web-front/src/components/DirectoryTree.vue | 1 - web-front/src/utils/downloaderService.js | 1 - web-front/src/utils/monacoTypes.js | 3 --- web-front/src/views/Home.vue | 5 +---- web-front/src/views/Playground.vue | 4 ---- 6 files changed, 1 insertion(+), 14 deletions(-) diff --git a/web-front/src/components/DarkMode.vue b/web-front/src/components/DarkMode.vue index b41e4ea..5a3870f 100644 --- a/web-front/src/components/DarkMode.vue +++ b/web-front/src/components/DarkMode.vue @@ -36,7 +36,6 @@ if (item) { const darkMode = ref(item) watch(darkMode, (newValue) => { - console.log(`darkMode: ${newValue}`) window.localStorage.setItem("darkMode", newValue); // 发射主题变化事件 diff --git a/web-front/src/components/DirectoryTree.vue b/web-front/src/components/DirectoryTree.vue index f91f46a..805d54b 100644 --- a/web-front/src/components/DirectoryTree.vue +++ b/web-front/src/components/DirectoryTree.vue @@ -491,7 +491,6 @@ export default { }, // 处理文件点击 handleFileClick(file) { - console.log('点击文件', file, this.viewMode) if (file.fileType === 'folder') { this.enterFolder(file) } else if (this.viewMode === 'pane') { diff --git a/web-front/src/utils/downloaderService.js b/web-front/src/utils/downloaderService.js index 9576544..911f2a3 100644 --- a/web-front/src/utils/downloaderService.js +++ b/web-front/src/utils/downloaderService.js @@ -410,7 +410,6 @@ function addThunderDownload(tasks, config) { if (userAgent) taskParam.userAgent = userAgent taskParam.threadCount = '1' - console.log('[Thunder SDK] newTask params:', JSON.stringify(taskParam)) window.thunderLink.newTask(taskParam) return Promise.resolve('thunder-ok') } diff --git a/web-front/src/utils/monacoTypes.js b/web-front/src/utils/monacoTypes.js index 5c863f2..833d043 100644 --- a/web-front/src/utils/monacoTypes.js +++ b/web-front/src/utils/monacoTypes.js @@ -313,7 +313,6 @@ export async function loadTypesFromApi(monaco) { cachedContent, 'file:///types.js' ); - console.log('从缓存加载types.js成功'); // 异步更新缓存 updateTypesJsCache(); return; @@ -334,7 +333,6 @@ export async function loadTypesFromApi(monaco) { typesJsContent, 'file:///types.js' ); - console.log('加载types.js成功并已缓存'); } } catch (error) { console.warn('加载types.js失败,使用内置类型定义:', error); @@ -350,7 +348,6 @@ async function updateTypesJsCache() { if (response.ok) { const typesJsContent = await response.text(); localStorage.setItem('playground_types_js', typesJsContent); - console.log('types.js缓存已更新'); } } catch (error) { console.warn('更新types.js缓存失败:', error); diff --git a/web-front/src/views/Home.vue b/web-front/src/views/Home.vue index ca29b65..e6999ec 100644 --- a/web-front/src/views/Home.vue +++ b/web-front/src/views/Home.vue @@ -959,18 +959,16 @@ export default { // 优先使用个人配置 if (this.allAuthConfigs[panType]) { config = this.allAuthConfigs[panType] - console.log(`[认证] 使用个人配置: ${this.getPanDisplayName(panType)}`) } else { // 从后端随机获取捐赠账号(后端已加密,直接使用 encryptedAuth) try { const response = await axios.get(`${this.baseAPI}/v2/randomAuth`, { params: { panType } }) const encryptedAuth = response.data?.data?.encryptedAuth if (encryptedAuth) { - console.log(`[认证] 使用捐赠账号: ${this.getPanDisplayName(panType)}`) return encryptedAuth } } catch (e) { - console.log(`[认证] 无可用捐赠账号: ${this.getPanDisplayName(panType)}`) + // no available donated account } return '' } @@ -1319,7 +1317,6 @@ export default { async getPaste(isManual = false) { try { const text = await navigator.clipboard.readText() - console.log('获取到的文本内容是:', text) const shortInfo = this.expandShortFormat(text) if (shortInfo) { diff --git a/web-front/src/views/Playground.vue b/web-front/src/views/Playground.vue index 7385466..b47fb0c 100644 --- a/web-front/src/views/Playground.vue +++ b/web-front/src/views/Playground.vue @@ -1758,7 +1758,6 @@ function parseFileList(shareLinkInfo, http, logger) { testParams.value.method ); - console.log('测试结果:', result); testResult.value = result; // 将日志添加到控制台 @@ -1820,10 +1819,8 @@ function parseFileList(shareLinkInfo, http, logger) { loadingList.value = true; try { const result = await playgroundApi.getParserList(); - console.log('获取解析器列表响应:', result); // 检查响应格式 if (result.code === 200 || result.success) { - console.log('列表数据:', result.data); parserList.value = result.data || []; } else if (result.data && Array.isArray(result.data)) { // 如果data直接是数组 @@ -1857,7 +1854,6 @@ function parseFileList(shareLinkInfo, http, logger) { try { const codeToPublish = currentCode.value; const result = await playgroundApi.saveParser(codeToPublish); - console.log('保存解析器响应:', result); // 检查响应格式 if (result.code === 200 || result.success) { // 从响应或代码中提取type信息 From e261ebe698d7c0394646514328dbedf1945050f0 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:37:32 +0800 Subject: [PATCH 39/93] fix: replace System.out.println with log.debug in WsTool --- .../src/main/java/cn/qaiu/parser/impl/WsTool.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/WsTool.java b/parser/src/main/java/cn/qaiu/parser/impl/WsTool.java index e10c9dd..d7b0f51 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/WsTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/WsTool.java @@ -67,11 +67,7 @@ public class WsTool extends PanBase { String filepid = asJson(res2).getJsonObject("data").getString("ufileid"); // 文件夹pid String filebid = asJson(res2).getJsonObject("data").getString("boxid"); // 文件夹bid - // 调试输出文件夹信息 - System.out.println("文件夹期限: " + filetime); - System.out.println("文件夹大小: " + filesize); - System.out.println("文件夹pid: " + filepid); - System.out.println("文件夹bid: " + filebid); + log.debug("文件夹期限: {}, 大小: {}, pid: {}, bid: {}", filetime, filesize, filepid, filebid); // 获取文件信息 httpClient.postAbs(SHARE_URL_API + "ufile/list").putHeaders(headers) @@ -97,9 +93,7 @@ public class WsTool extends PanBase { String filefid = asJson(res3).getJsonObject("data") .getJsonArray("fileList").getJsonObject(0).getString("fid"); // 文件fid - // 调试输出文件信息 - System.out.println("文件名称: " + filename); - System.out.println("文件fid: " + filefid); + log.debug("文件名称: {}, fid: {}", filename, filefid); // 检查文件是否失效 httpClient.postAbs(SHARE_URL_API + "dl/sign").putHeaders(headers) @@ -114,8 +108,7 @@ public class WsTool extends PanBase { // 获取直链 String fileurl = asJson(res4).getJsonObject("data").getString("url"); - // 调试输出文件直链 - System.out.println("文件直链: " + fileurl); + log.debug("文件直链: {}", fileurl); if (!fileurl.equals("")) { promise.complete(URLDecoder.decode(fileurl, StandardCharsets.UTF_8)); From 082cc4c7436c3651fd29d075ef99a480e6e9935b Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:38:07 +0800 Subject: [PATCH 40/93] fix: replace System.out.println with log in PodTool; mask token in log output --- parser/src/main/java/cn/qaiu/parser/impl/PodTool.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java b/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java index 042e1ec..c8d8c0f 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java @@ -129,7 +129,7 @@ public class PodTool extends PanBase { if (urlMatcher.find()) { String url = urlMatcher.group("url"); - System.out.println("URL: " + url); + log.debug("URL: {}", url); return url; } throw new RuntimeException("URL匹配失败"); @@ -172,7 +172,7 @@ public class PodTool extends PanBase { if (tokenMatcher.find()) { String token = tokenMatcher.group(1); - System.out.println("Token: " + token); + log.debug("Token: {}***", token.length() > 4 ? token.substring(0, 4) : "***"); return token; } throw new RuntimeException("token匹配失败"); @@ -198,8 +198,8 @@ public class PodTool extends PanBase { // 发送请求并处理响应 client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> { - System.out.println("Response Status Code: " + response.statusCode()); - System.out.println("Response Body: " + response.body()); + log.debug("Response Status Code: {}", response.statusCode()); + log.debug("Response Body: {}", response.body()); promise.complete(response.body()); return null; }); From 6557b493830091fff2b7d2c85edc9ab468afa235 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:38:36 +0800 Subject: [PATCH 41/93] fix: replace System.out.println with log.debug in MkgsTool --- parser/src/main/java/cn/qaiu/parser/impl/MkgsTool.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MkgsTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MkgsTool.java index 1182c9f..cb01165 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/MkgsTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/MkgsTool.java @@ -86,10 +86,10 @@ public class MkgsTool extends PanBase { // 查找并输出 hash 字段的值 if (matcher.find()) { String hashValue = matcher.group(1); // 获取第一个捕获组 - System.out.println(hashValue); + log.debug("hash: {}", hashValue); client.getAbs(UriTemplate.of(API_URL)).setTemplateParam("hash", hashValue).send().onSuccess(res3 -> { JsonObject jsonObject = asJson(res3); - System.out.println(jsonObject.encodePrettily()); + log.debug("API response: {}", jsonObject.encodePrettily()); if (jsonObject.containsKey("url")) { promise.complete(jsonObject.getString("url")); } else { From aed9e9f10d0192ec1b0ab54ee3c843e31e807789 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:39:11 +0800 Subject: [PATCH 42/93] fix: replace System.out.println/printStackTrace with logger in ReqIpUtil; add final to static fields --- .../src/main/java/cn/qaiu/util/ReqIpUtil.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/util/ReqIpUtil.java b/parser/src/main/java/cn/qaiu/util/ReqIpUtil.java index 84384ce..bfaab33 100644 --- a/parser/src/main/java/cn/qaiu/util/ReqIpUtil.java +++ b/parser/src/main/java/cn/qaiu/util/ReqIpUtil.java @@ -8,15 +8,19 @@ import io.vertx.core.http.impl.headers.HeadersMultiMap; import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClientSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ReqIpUtil { - public static String BASE_URL = "https://ip.ihuan.me"; - public static String BASE_URL_TEMPLATE = BASE_URL + "/{path}"; + private static final Logger log = LoggerFactory.getLogger(ReqIpUtil.class); + + public static final String BASE_URL = "https://ip.ihuan.me"; + public static final String BASE_URL_TEMPLATE = BASE_URL + "/{path}"; // GET https://ip.ihuan.me/mouse.do -> $("input[name='key']").val("30b4975b5547fed806bd2b9caa18485a"); - public static String PATH1 = "mouse.do"; + public static final String PATH1 = "mouse.do"; - public static String PATH2 = "tqdl.html"; + public static final String PATH2 = "tqdl.html"; // 创建请求头Map static MultiMap headers = new HeadersMultiMap(); @@ -58,15 +62,15 @@ public class ReqIpUtil { void next(AsyncResult> response) { if (response.failed()) { - response.cause().printStackTrace(); + log.error("请求失败", response.cause()); } else { HttpResponse res = response.result(); - System.out.println("Received response with status code " + res.statusCode()); - System.out.println("Body: " + res.body()); + log.debug("Received response with status code {}", res.statusCode()); + log.debug("Body: {}", res.body()); webClientSession.getAbs(BASE_URL_TEMPLATE).setTemplateParam("path", PATH1) .putHeaders(headers) // 将请求头Map添加到请求中 .send(response2 -> { - System.out.println(response2.result().bodyAsString()); + log.debug("response2: {}", response2.result().bodyAsString()); }); } From caddff567f6c8aac0134e6ab5885b2198396c724 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:39:36 +0800 Subject: [PATCH 43/93] fix: replace System.out.println with logger in IpExtractor --- parser/src/main/java/cn/qaiu/util/IpExtractor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/util/IpExtractor.java b/parser/src/main/java/cn/qaiu/util/IpExtractor.java index f8bc7ea..186a8cd 100644 --- a/parser/src/main/java/cn/qaiu/util/IpExtractor.java +++ b/parser/src/main/java/cn/qaiu/util/IpExtractor.java @@ -5,6 +5,8 @@ import io.vertx.core.Vertx; import io.vertx.core.http.impl.headers.HeadersMultiMap; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClientSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; @@ -15,6 +17,8 @@ import java.util.ArrayList; import java.util.List; public class IpExtractor { + private static final Logger log = LoggerFactory.getLogger(IpExtractor.class); + public static void main(String[] args) throws InterruptedException { @@ -42,9 +46,9 @@ public class IpExtractor { WebClient client = WebClient.create(Vertx.vertx()); WebClientSession webClientSession = WebClientSession.create(client); webClientSession.getAbs("https://ip.ihuan.me").putHeaders(headers).send().onSuccess(res->{ - System.out.println(res.toString()); + log.debug("response: {}", res.toString()); webClientSession.getAbs("https://ip.ihuan.me").putHeaders(headers).send().onSuccess(res2->{ - System.out.println(res2.toString()); + log.debug("response2: {}", res2.toString()); }); }); From 49a391824467d5e78f667c553b50df7a098edd84 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:40:06 +0800 Subject: [PATCH 44/93] fix: replace double-brace init with static block + Collections.unmodifiableMap; add final to UNIQUE_PREFIX --- .../main/java/cn/qaiu/db/ddl/CreateTable.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/core-database/src/main/java/cn/qaiu/db/ddl/CreateTable.java b/core-database/src/main/java/cn/qaiu/db/ddl/CreateTable.java index 2228980..a547e32 100644 --- a/core-database/src/main/java/cn/qaiu/db/ddl/CreateTable.java +++ b/core-database/src/main/java/cn/qaiu/db/ddl/CreateTable.java @@ -24,35 +24,39 @@ import java.util.*; * @author QAIU */ public class CreateTable { - public static Map, String> javaProperty2SqlColumnMap = new HashMap<>() {{ + public static final Map, String> javaProperty2SqlColumnMap; + static { + Map, String> map = new HashMap<>(); // Java类型到SQL类型的映射 - put(Integer.class, "INT"); - put(Short.class, "SMALLINT"); - put(Byte.class, "TINYINT"); - put(Long.class, "BIGINT"); - put(java.math.BigDecimal.class, "DECIMAL"); - put(Double.class, "DOUBLE"); - put(Float.class, "REAL"); - put(Boolean.class, "BOOLEAN"); - put(String.class, "VARCHAR"); - put(Date.class, "TIMESTAMP"); - put(java.time.LocalDateTime.class, "TIMESTAMP"); - put(java.sql.Timestamp.class, "TIMESTAMP"); - put(java.sql.Date.class, "DATE"); - put(java.sql.Time.class, "TIME"); + map.put(Integer.class, "INT"); + map.put(Short.class, "SMALLINT"); + map.put(Byte.class, "TINYINT"); + map.put(Long.class, "BIGINT"); + map.put(java.math.BigDecimal.class, "DECIMAL"); + map.put(Double.class, "DOUBLE"); + map.put(Float.class, "REAL"); + map.put(Boolean.class, "BOOLEAN"); + map.put(String.class, "VARCHAR"); + map.put(Date.class, "TIMESTAMP"); + map.put(java.time.LocalDateTime.class, "TIMESTAMP"); + map.put(java.sql.Timestamp.class, "TIMESTAMP"); + map.put(java.sql.Date.class, "DATE"); + map.put(java.sql.Time.class, "TIME"); // 基本数据类型 - put(int.class, "INT"); - put(short.class, "SMALLINT"); - put(byte.class, "TINYINT"); - put(long.class, "BIGINT"); - put(double.class, "DOUBLE"); - put(float.class, "REAL"); - put(boolean.class, "BOOLEAN"); - }}; + map.put(int.class, "INT"); + map.put(short.class, "SMALLINT"); + map.put(byte.class, "TINYINT"); + map.put(long.class, "BIGINT"); + map.put(double.class, "DOUBLE"); + map.put(float.class, "REAL"); + map.put(boolean.class, "BOOLEAN"); + + javaProperty2SqlColumnMap = Collections.unmodifiableMap(map); + } private static final Logger LOGGER = LoggerFactory.getLogger(CreateTable.class); - public static String UNIQUE_PREFIX = "idx_"; + public static final String UNIQUE_PREFIX = "idx_"; private static Case getCase(Class clz) { return switch (clz.getName()) { From c4f94a2bc766552c972e21118ac4b17c50f185e1 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 03:48:11 +0800 Subject: [PATCH 45/93] fix: replace printStackTrace/System.out.println with logger in JsHttpClient, PlaygroundApi, LogStatistics, CacheServiceImpl, JsPlaygroundExecutor, JsPlaygroundLogger --- .../java/cn/qaiu/parser/customjs/JsHttpClient.java | 4 ++-- .../qaiu/parser/customjs/JsPlaygroundExecutor.java | 2 +- .../cn/qaiu/parser/customjs/JsPlaygroundLogger.java | 13 +++++++++---- .../lz/common/interceptorImpl/LogStatistics.java | 2 +- .../cn/qaiu/lz/web/controller/PlaygroundApi.java | 1 + .../qaiu/lz/web/service/impl/CacheServiceImpl.java | 4 ++-- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsHttpClient.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsHttpClient.java index 0442903..2ada6b0 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsHttpClient.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsHttpClient.java @@ -534,8 +534,8 @@ public class JsHttpClient { } else { promise.fail(result.cause()); } - }).onFailure(Throwable::printStackTrace); - + }).onFailure(e -> log.error("HTTP请求失败", e)); + // 等待响应完成(使用配置的超时时间) HttpResponse response = promise.future().toCompletionStage() .toCompletableFuture() diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java index e1a31cc..19ae052 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java @@ -355,7 +355,7 @@ public class JsPlaygroundExecutor { */ public List getLogs() { List logs = playgroundLogger.getLogs(); - System.out.println("[JsPlaygroundExecutor] 获取日志,数量: " + logs.size()); + log.debug("获取日志,数量: {}", logs.size()); return logs; } diff --git a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java index 8319d96..f442e64 100644 --- a/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java +++ b/parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundLogger.java @@ -4,6 +4,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * 演练场日志收集器 * 收集JavaScript执行过程中的日志信息 @@ -12,7 +15,9 @@ import java.util.List; * @author QAIU */ public class JsPlaygroundLogger { - + + private static final Logger log = LoggerFactory.getLogger(JsPlaygroundLogger.class); + // 使用线程安全的列表 private static final int MAX_LOG_SIZE = 1000; private final List logs = Collections.synchronizedList(new ArrayList<>()); @@ -81,7 +86,7 @@ public class JsPlaygroundLogger { private void log(String level, Object message, String source) { String msg = toString(message); addLog(new LogEntry(level, msg, source)); - System.out.println("[" + source + "PlaygroundLogger] " + level + ": " + msg); + log.debug("[{}PlaygroundLogger] {}: {}", source, level, msg); } /** @@ -125,7 +130,7 @@ public class JsPlaygroundLogger { msg = msg + ": " + throwable.getMessage(); } addLog(new LogEntry("ERROR", msg, "JS")); - System.out.println("[JSPlaygroundLogger] ERROR: " + msg); + log.debug("[JSPlaygroundLogger] ERROR: {}", msg); } // ===== 以下是供Java层调用的内部方法 ===== @@ -167,7 +172,7 @@ public class JsPlaygroundLogger { msg = msg + ": " + throwable.getMessage(); } addLog(new LogEntry("ERROR", msg, "JAVA")); - System.out.println("[JAVAPlaygroundLogger] ERROR: " + msg); + log.debug("[JAVAPlaygroundLogger] ERROR: {}", msg); } /** diff --git a/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/LogStatistics.java b/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/LogStatistics.java index 18dc3be..628bc5e 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/LogStatistics.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/interceptorImpl/LogStatistics.java @@ -48,6 +48,6 @@ public class LogStatistics implements AfterInterceptor { .execute(info) .onSuccess(res -> { log.info("inserted log: id={}, path={}, code={}", info.getId(), info.getPath(), info.getCode()); - }).onFailure(Throwable::printStackTrace); + }).onFailure(e -> log.error("插入解析日志失败: id={}", info.getId(), e)); } } diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java index dc96e1b..fb54307 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java @@ -704,6 +704,7 @@ public class PlaygroundApi { if (throwable == null) { return ""; } + log.error("获取异常堆栈信息", throwable); java.io.StringWriter sw = new java.io.StringWriter(); java.io.PrintWriter pw = new java.io.PrintWriter(sw); throwable.printStackTrace(pw); diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/CacheServiceImpl.java b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/CacheServiceImpl.java index 977432c..8dbd0c1 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/CacheServiceImpl.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/CacheServiceImpl.java @@ -104,7 +104,7 @@ public class CacheServiceImpl implements CacheService { promise.complete(result); // 更新缓存 cacheManager.cacheShareLink(cacheLinkInfo); - cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(Throwable::printStackTrace); + cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(e -> log.error("更新API解析计数失败: cacheKey={}", cacheKey, e)); }).onFailure(promise::fail); } else { // 缓存命中,生成过期时间并生成下载命令 @@ -120,7 +120,7 @@ public class CacheServiceImpl implements CacheService { promise.complete(result); cacheManager.updateTotalByField(cacheKey, CacheTotalField.CACHE_HIT_TOTAL) - .onFailure(Throwable::printStackTrace); + .onFailure(e -> log.error("更新缓存命中计数失败: cacheKey={}", cacheKey, e)); } }).onFailure(t -> promise.fail(t.fillInStackTrace())); From ffaba4f496b787a74a492490c3608916286cef65 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 04:03:37 +0800 Subject: [PATCH 46/93] =?UTF-8?q?fix(test):=20BaiduPhotoParserTest=20Vertx?= =?UTF-8?q?=20=E8=B5=84=E6=BA=90=E6=B3=84=E6=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将各 @Test 方法中局部创建的 Vertx.vertx() 统一为成员变量, 通过 @Before 创建并初始化,@After 关闭,避免资源泄漏。 --- .../cn/qaiu/parser/BaiduPhotoParserTest.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/parser/src/test/java/cn/qaiu/parser/BaiduPhotoParserTest.java b/parser/src/test/java/cn/qaiu/parser/BaiduPhotoParserTest.java index ee6bde0..1618f77 100644 --- a/parser/src/test/java/cn/qaiu/parser/BaiduPhotoParserTest.java +++ b/parser/src/test/java/cn/qaiu/parser/BaiduPhotoParserTest.java @@ -8,6 +8,8 @@ import cn.qaiu.parser.customjs.JsParserExecutor; import cn.qaiu.WebClientVertxInit; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import java.util.HashMap; @@ -22,15 +24,26 @@ import java.util.Map; */ public class BaiduPhotoParserTest { + private Vertx vertx; + + @Before + public void setUp() { + vertx = Vertx.vertx(); + WebClientVertxInit.init(vertx); + } + + @After + public void tearDown() { + if (vertx != null) { + vertx.close(); + } + } + @Test public void testBaiduPhotoParserRegistration() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + // 检查是否加载了百度相册解析器 CustomParserConfig config = CustomParserRegistry.get("baidu_photo"); assert config != null : "百度相册解析器未加载"; @@ -44,11 +57,7 @@ public class BaiduPhotoParserTest { public void testBaiduPhotoFileShareExecution() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建解析器 - 测试文件分享链接 IPanTool tool = ParserCreate.fromType("baidu_photo") @@ -76,11 +85,7 @@ public class BaiduPhotoParserTest { public void testBaiduPhotoFolderShareExecution() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建解析器 - 测试文件夹分享链接 IPanTool tool = ParserCreate.fromType("baidu_photo") @@ -108,11 +113,7 @@ public class BaiduPhotoParserTest { public void testBaiduPhotoParserFileList() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { IPanTool tool = ParserCreate.fromType("baidu_photo") // 分享key PPgOEodBVE @@ -166,11 +167,7 @@ public class BaiduPhotoParserTest { public void testBaiduPhotoParserById() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建ShareLinkInfo Map otherParam = new HashMap<>(); From 88739e8d1add30d1646cfbe49bf688045a1d8b3c Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 04:04:52 +0800 Subject: [PATCH 47/93] =?UTF-8?q?fix(test):=20JsParserTest=20Vertx=20?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=B3=84=E6=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将各 @Test 方法中局部创建的 Vertx.vertx() 统一为成员变量, 通过 @Before 创建并初始化,@After 关闭,避免资源泄漏。 --- .../java/cn/qaiu/parser/JsParserTest.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/parser/src/test/java/cn/qaiu/parser/JsParserTest.java b/parser/src/test/java/cn/qaiu/parser/JsParserTest.java index 88f2a43..c738f90 100644 --- a/parser/src/test/java/cn/qaiu/parser/JsParserTest.java +++ b/parser/src/test/java/cn/qaiu/parser/JsParserTest.java @@ -7,6 +7,8 @@ import cn.qaiu.parser.custom.CustomParserRegistry; import cn.qaiu.parser.customjs.JsParserExecutor; import cn.qaiu.WebClientVertxInit; import io.vertx.core.Vertx; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import java.util.HashMap; @@ -21,15 +23,26 @@ import java.util.Map; */ public class JsParserTest { + private Vertx vertx; + + @Before + public void setUp() { + vertx = Vertx.vertx(); + WebClientVertxInit.init(vertx); + } + + @After + public void tearDown() { + if (vertx != null) { + vertx.close(); + } + } + @Test public void testJsParserRegistration() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + // 检查是否加载了JavaScript解析器 CustomParserConfig config = CustomParserRegistry.get("demo_js"); assert config != null : "JavaScript解析器未加载"; @@ -43,11 +56,7 @@ public class JsParserTest { public void testJsParserExecution() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建解析器 IPanTool tool = ParserCreate.fromType("demo_js") @@ -74,11 +83,7 @@ public class JsParserTest { public void testJsParserFileList() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建解析器 IPanTool tool = ParserCreate.fromType("demo_js") @@ -114,11 +119,7 @@ public class JsParserTest { public void testJsParserById() { // 清理注册表 CustomParserRegistry.clear(); - - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - + try { // 创建ShareLinkInfo Map otherParam = new HashMap<>(); From 06416a4e5f6a2280116d2e1bd30d757702f31743 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 04:06:13 +0800 Subject: [PATCH 48/93] =?UTF-8?q?fix(test):=20JsFetchBridgeTest=20Vertx=20?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=B3=84=E6=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将各 @Test 方法中局部创建的 Vertx.vertx() 统一为成员变量, 通过 @Before 创建并初始化,@After 关闭,避免资源泄漏。 --- .../parser/customjs/JsFetchBridgeTest.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/parser/src/test/java/cn/qaiu/parser/customjs/JsFetchBridgeTest.java b/parser/src/test/java/cn/qaiu/parser/customjs/JsFetchBridgeTest.java index 527a954..47392ff 100644 --- a/parser/src/test/java/cn/qaiu/parser/customjs/JsFetchBridgeTest.java +++ b/parser/src/test/java/cn/qaiu/parser/customjs/JsFetchBridgeTest.java @@ -7,6 +7,8 @@ import cn.qaiu.parser.ParserCreate; import cn.qaiu.parser.custom.CustomParserConfig; import cn.qaiu.parser.custom.CustomParserRegistry; import io.vertx.core.Vertx; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,18 +18,29 @@ import org.slf4j.LoggerFactory; * 测试fetch API和Promise polyfill功能 */ public class JsFetchBridgeTest { - + private static final Logger log = LoggerFactory.getLogger(JsFetchBridgeTest.class); - + + private Vertx vertx; + + @Before + public void setUp() { + vertx = Vertx.vertx(); + WebClientVertxInit.init(vertx); + } + + @After + public void tearDown() { + if (vertx != null) { + vertx.close(); + } + } + @Test public void testFetchPolyfillLoaded() { - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - // 清理注册表 CustomParserRegistry.clear(); - + // 创建一个简单的解析器配置 String jsCode = """ // 测试Promise是否可用 @@ -83,13 +96,9 @@ public class JsFetchBridgeTest { @Test public void testPromiseBasicUsage() { - // 初始化Vertx - Vertx vertx = Vertx.vertx(); - WebClientVertxInit.init(vertx); - // 清理注册表 CustomParserRegistry.clear(); - + String jsCode = """ function parse(shareLinkInfo, http, logger) { logger.info("测试Promise基本用法"); From 7ca63985bd46e95cef029e7c76b2c13caa13718d Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 04:06:21 +0800 Subject: [PATCH 49/93] =?UTF-8?q?fix(test):=20=E5=88=A0=E9=99=A4=E7=A9=BA?= =?UTF-8?q?=E7=9A=84=20ParserApiClientLinkTest=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 该文件仅包含空行,无实际测试代码,直接删除。 --- .../java/cn/qaiu/lz/web/controller/ParserApiClientLinkTest.java | 1 - 1 file changed, 1 deletion(-) delete mode 100644 web-service/src/test/java/cn/qaiu/lz/web/controller/ParserApiClientLinkTest.java diff --git a/web-service/src/test/java/cn/qaiu/lz/web/controller/ParserApiClientLinkTest.java b/web-service/src/test/java/cn/qaiu/lz/web/controller/ParserApiClientLinkTest.java deleted file mode 100644 index 0519ecb..0000000 --- a/web-service/src/test/java/cn/qaiu/lz/web/controller/ParserApiClientLinkTest.java +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 7d5831b5f4c3b2b8f8c7d1fc06f32b9e621f3025 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 05:53:40 +0800 Subject: [PATCH 50/93] =?UTF-8?q?fix:=20=E5=BD=BB=E5=BA=95=E6=B6=88?= =?UTF-8?q?=E9=99=A4=E7=94=A8=E6=88=B7=E6=9E=9A=E4=B8=BE=E5=92=8C=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BF=A1=E6=81=AF=E6=B3=84=E9=9C=B2=E7=9A=84=E9=81=97?= =?UTF-8?q?=E7=95=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserServiceImpl: 3处"用户不存在"统一改为"用户名或密码错误"/"认证失败" - RouterHandlerFactory: failureHandler 中 ctx.failure().getMessage() 改为"服务器内部错误" --- .../vx/core/handlerfactory/RouterHandlerFactory.java | 2 +- .../cn/qaiu/lz/web/service/impl/UserServiceImpl.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java index f573f6a..6f704a3 100644 --- a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java +++ b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java @@ -181,7 +181,7 @@ public class RouterHandlerFactory implements BaseHttpApi { doFireJsonResultResponse(ctx, JsonResult.error("未知异常, 请联系管理员"), 503); } else { LOGGER.error("路由处理失败", ctx.failure()); - doFireJsonResultResponse(ctx, JsonResult.error(ctx.failure().getMessage()), 500); + doFireJsonResultResponse(ctx, JsonResult.error("服务器内部错误"), 500); } }); } else if (method.isAnnotationPresent(SockRouteMapper.class)) { diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java index ac567ef..c428111 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/UserServiceImpl.java @@ -189,10 +189,10 @@ public class UserServiceImpl implements UserService { .execute(Tuple.of(username)) .onSuccess(rows -> { if (rows.size() == 0) { - promise.fail("用户不存在"); + promise.fail("用户名或密码错误"); return; } - + Row row = rows.iterator().next(); SysUser user = rowToUser(row); promise.complete(filterSensitiveInfo(user)); @@ -296,10 +296,10 @@ public class UserServiceImpl implements UserService { .execute(Tuple.of(user.getUsername())) .onSuccess(rows -> { if (rows.size() == 0) { - promise.fail("用户不存在"); + promise.fail("用户名或密码错误"); return; } - + Row row = rows.iterator().next(); SysUser existUser = rowToUser(row); @@ -406,7 +406,7 @@ public class UserServiceImpl implements UserService { .onFailure(err -> { promise.complete(new JsonObject() .put("success", false) - .put("message", "用户不存在")); + .put("message", "认证失败,请重新登录")); }); return promise.future(); From 206981d4b41abe7609ed6821f4cdd08b5a66a36e Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:15:56 +0800 Subject: [PATCH 51/93] =?UTF-8?q?revert:=20RouterHandlerFactory=20failureH?= =?UTF-8?q?andler=20=E6=81=A2=E5=A4=8D=E8=BF=94=E5=9B=9E=20failure=20messa?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 ctx.failure().getMessage() 是故意设计——RateLimiter 等组件通过 promise.fail() 传递用户友好的错误消息(如"请求次数太多了"),这些消息需要通过 failureHandler 返回给客户端。改为固定"服务器内部错误"会导致这些消息丢失。 仅添加 null 检查防止 NPE。 --- .../cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java index 6f704a3..736d78e 100644 --- a/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java +++ b/core/src/main/java/cn/qaiu/vx/core/handlerfactory/RouterHandlerFactory.java @@ -181,7 +181,8 @@ public class RouterHandlerFactory implements BaseHttpApi { doFireJsonResultResponse(ctx, JsonResult.error("未知异常, 请联系管理员"), 503); } else { LOGGER.error("路由处理失败", ctx.failure()); - doFireJsonResultResponse(ctx, JsonResult.error("服务器内部错误"), 500); + String msg = ctx.failure() != null ? ctx.failure().getMessage() : "未知异常"; + doFireJsonResultResponse(ctx, JsonResult.error(msg), 500); } }); } else if (method.isAnnotationPresent(SockRouteMapper.class)) { From 86b9c43b8b09be283e707cbb6d56f8e06abb5890 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:27:51 +0800 Subject: [PATCH 52/93] fix: narrow catch exception type in ParserCreate.java Replace 5 instances of `catch (Exception ignored)` with `catch (IllegalStateException ignored)` around matcher.group() calls, since that method only throws IllegalStateException when a named group does not exist. --- .../main/java/cn/qaiu/parser/ParserCreate.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java index 71f0e13..b1b630a 100644 --- a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java +++ b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java @@ -81,16 +81,16 @@ public class ParserCreate { if (shareKey != null) { shareLinkInfo.setShareKey(shareKey); } - } catch (Exception ignored) {} - + } catch (IllegalStateException ignored) {} + // 提取密码 try { String pwd = matcher.group("PWD"); if (StringUtils.isNotEmpty(pwd)) { shareLinkInfo.setSharePassword(pwd); } - } catch (Exception ignored) {} - + } catch (IllegalStateException ignored) {} + // 设置标准URL if (customParserConfig.getStandardUrlTemplate() != null) { String standardUrl = customParserConfig.getStandardUrlTemplate() @@ -133,7 +133,7 @@ public class ParserCreate { shareLinkInfo.setSharePassword(pwd); } standardUrl = standardUrl.replace("{pwd}", pwd); - } catch (Exception ignored) {} + } catch (IllegalStateException ignored) {} shareLinkInfo.setShareUrl(shareUrl); shareLinkInfo.setShareKey(shareKey); @@ -266,15 +266,15 @@ public class ParserCreate { if (shareKey != null) { shareLinkInfo.setShareKey(shareKey); } - } catch (Exception ignored) {} - + } catch (IllegalStateException ignored) {} + try { String password = matcher.group("PWD"); if (password != null) { shareLinkInfo.setSharePassword(password); } - } catch (Exception ignored) {} - + } catch (IllegalStateException ignored) {} + // 设置标准URL(如果有模板) if (customConfig.getStandardUrlTemplate() != null) { String standardUrl = customConfig.getStandardUrlTemplate() From d06a80dc7363323b3d5bb366ff7b7d253601039a Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:28:20 +0800 Subject: [PATCH 53/93] fix: narrow catch exception type in LzTool.java Replace 2 instances of `catch (Exception ignored)` with `catch (MalformedURLException ignored)` around `new java.net.URL(url)` calls, since that constructor only throws MalformedURLException. --- parser/src/main/java/cn/qaiu/parser/impl/LzTool.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java index 63900e3..298e9ea 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java @@ -14,6 +14,7 @@ import io.vertx.ext.web.client.WebClientSession; import org.openjdk.nashorn.api.scripting.ScriptObjectMirror; import javax.script.ScriptException; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -175,7 +176,7 @@ public class LzTool extends PanBase { if (firstDot >= 0) { domain = host.substring(firstDot); // e.g. ".lanzoum.com" } - } catch (Exception ignored) {} + } catch (MalformedURLException ignored) {} // 创建一个 Cookie 并放入 CookieStore DefaultCookie nettyCookie = new DefaultCookie("acw_sc__v2", acw_sc__v2); nettyCookie.setDomain(domain); @@ -275,7 +276,7 @@ public class LzTool extends PanBase { String h = du.getHost(); int dot = h.indexOf('.'); if (dot >= 0) downDomain = h.substring(dot); - } catch (Exception ignored) {} + } catch (MalformedURLException ignored) {} // 创建一个 Cookie 并放入 CookieStore DefaultCookie nettyCookie = new DefaultCookie("acw_sc__v2", acw_sc__v2); nettyCookie.setDomain(downDomain); From 741d7aa8cadfae73c9488798c44cc8b026f128e1 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:28:39 +0800 Subject: [PATCH 54/93] fix: implement MyData @DataObject constructor deserialization Implement the MyData(JsonObject) constructor to deserialize `id` and `maxSize` fields from the provided JsonObject, replacing the empty TODO. --- web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java b/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java index 4614000..d7793d0 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java @@ -24,6 +24,7 @@ public class MyData implements Serializable { public MyData(JsonObject jsonObject) { - // TODO + this.id = jsonObject.getString("id"); + this.maxSize = jsonObject.getString("maxSize"); } } From 0cd77ee9b99a8ff98cbb5515d100907431306297 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:36:43 +0800 Subject: [PATCH 55/93] =?UTF-8?q?fix(IzTool):=20=E4=BF=AE=E5=A4=8D=20parse?= =?UTF-8?q?FileList=20=E4=B8=AD=20get("uuid")=20=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 otherParam 中缺少 "uuid" 键时,原代码直接调用 .toString() 会抛出 NullPointerException。改为先取出 Object 再做 null 检查。 --- parser/src/main/java/cn/qaiu/parser/impl/IzTool.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index 044b7e8..11196d9 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -465,7 +465,10 @@ public class IzTool extends PanBase { // 如果参数里的目录ID不为空,则直接解析目录 String dirId = (String) shareLinkInfo.getOtherParam().get("dirId"); if (dirId != null && !dirId.isEmpty()) { - uuid = shareLinkInfo.getOtherParam().get("uuid").toString(); + Object uuidObj = shareLinkInfo.getOtherParam().get("uuid"); + if (uuidObj != null) { + uuid = uuidObj.toString(); + } parserDir(dirId, shareId, promise); return promise.future(); } From c0a0d0dc47dfbfcb1a774b7b1f9dc78bc74030d4 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:37:12 +0800 Subject: [PATCH 56/93] =?UTF-8?q?fix(FjTool):=20=E4=BF=AE=E5=A4=8D=20parse?= =?UTF-8?q?ById=20=E4=B8=AD=20get("paramJson")=20=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 otherParam 中缺少 "paramJson" 键时,后续 getString 调用会抛出 NPE。 添加 null 检查并提前返回失败。 --- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index b46137f..a7d1969 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -581,6 +581,10 @@ public class FjTool extends PanBase { // 第二次请求 JsonObject paramJson = (JsonObject)shareLinkInfo.getOtherParam().get("paramJson"); + if (paramJson == null) { + promise.fail("缺少 paramJson 参数"); + return promise.future(); + } clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL_VIP)) .setTemplateParam("fidEncode", paramJson.getString("fidEncode")) .setTemplateParam("uuid", paramJson.getString("uuid")) From 31f33339f13d57f4b83be5d56610da4a9adf9f7d Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:37:53 +0800 Subject: [PATCH 57/93] =?UTF-8?q?fix(FsTool):=20=E4=BF=AE=E5=A4=8D=20parse?= =?UTF-8?q?ById=20=E4=B8=AD=20get("paramJson")=20=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 otherParam 中缺少 "paramJson" 键时,后续 getString 调用会抛出 NPE。 添加 null 检查并提前返回失败。 --- parser/src/main/java/cn/qaiu/parser/impl/FsTool.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java index 1f0c09b..74cc214 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java @@ -389,6 +389,10 @@ public class FsTool extends PanBase { try { JsonObject paramJson = (JsonObject) shareLinkInfo.getOtherParam().get("paramJson"); + if (paramJson == null) { + parsePromise.fail("缺少 paramJson 参数"); + return parsePromise.future(); + } String shareUrl = paramJson.getString("shareUrl"); String objToken = paramJson.getString("objToken"); String tenant = extractTenant(shareUrl); From 74840ab63f869b8a999cbe6a5a02f82c966f6c73 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:38:35 +0800 Subject: [PATCH 58/93] =?UTF-8?q?fix(FsTool):=20=E6=94=B6=E7=AA=84=20parse?= =?UTF-8?q?FileNameFromContentDisposition=20=E4=B8=AD=E7=9A=84=20catch=20?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 catch(Exception) 改为 catch(IllegalArgumentException), 只捕获 URLDecoder.decode 在遇到非法百分比编码时抛出的具体异常。 --- parser/src/main/java/cn/qaiu/parser/impl/FsTool.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java index 74cc214..ad687e2 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FsTool.java @@ -448,7 +448,7 @@ public class FsTool extends PanBase { if (m1.find()) { try { return URLDecoder.decode(m1.group(1).trim(), StandardCharsets.UTF_8); - } catch (Exception ignored) { + } catch (IllegalArgumentException ignored) { } } @@ -457,7 +457,7 @@ public class FsTool extends PanBase { if (m2.find()) { try { return URLDecoder.decode(m2.group(1).trim(), StandardCharsets.UTF_8); - } catch (Exception ignored) { + } catch (IllegalArgumentException ignored) { } } From 0ea31d631a40bd24c8dea425260ae0c77e9e7f57 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:57:44 +0800 Subject: [PATCH 59/93] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=20IzTool/IzTool?= =?UTF-8?q?WithAuth=20login()=20=E4=B8=AD=E6=9C=AA=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=9A=84=20h=20=E5=8F=98=E9=87=8F=EF=BC=88=E6=AD=BB=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 并发安全修复引入的 h 变量创建后从未使用,后续请求仍通过 setTemplateParam("appToken", token) 传递 token。删除死代码并为 同一行的 token.substring 添加 null 保护。 --- parser/src/main/java/cn/qaiu/parser/impl/IzTool.java | 5 +---- parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index 11196d9..c135845 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -311,10 +311,7 @@ public class IzTool extends PanBase { JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); - MultiMap h = MultiMap.caseInsensitiveMultiMap(); - h.addAll(header); - h.set("appToken", token); - log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); + log.info("登录成功 token: {}...", token != null ? token.substring(0, Math.min(8, token.length())) : "null"); promise1.complete(); } else { // 检查是否为临时认证 diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java index ee1a095..bae5d20 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java @@ -280,10 +280,7 @@ public class IzToolWithAuth extends PanBase { JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { token = json.getJsonObject("data").getString("appToken"); - MultiMap h = MultiMap.caseInsensitiveMultiMap(); - h.addAll(header); - h.set("appToken", token); - log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); + log.info("登录成功 token: {}...", token != null ? token.substring(0, Math.min(8, token.length())) : "null"); promise1.complete(); } else { // 检查是否为临时认证 From cf7fc4f5023d17631e26d5f569f20fe3a31924ee Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:58:09 +0800 Subject: [PATCH 60/93] =?UTF-8?q?fix:=20FjTool=20login()=20=E4=B8=AD=20tok?= =?UTF-8?q?en.substring=20=E6=B7=BB=E5=8A=A0=20null=20=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit token 脱敏日志在 token 可能为 null 时会抛 NPE,添加 null 检查。 --- parser/src/main/java/cn/qaiu/parser/impl/FjTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index a7d1969..6b991b4 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -292,7 +292,7 @@ public class FjTool extends PanBase { MultiMap h0 = MultiMap.caseInsensitiveMultiMap(); h0.addAll(header0); h0.set("appToken", token); - log.info("登录成功 token: {}...", token.substring(0, Math.min(8, token.length()))); + log.info("登录成功 token: {}...", token != null ? token.substring(0, Math.min(8, token.length())) : "null"); client.postAbs(UriTemplate.of(TOKEN_VERIFY_URL)) .setTemplateParam("uuid", uuid) .setTemplateParam("ts", tsEncode2) From 5eed1fdfa03cceebde13d2dd17cc39d1ee0f167d Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 06:58:41 +0800 Subject: [PATCH 61/93] =?UTF-8?q?revert:=20=E5=9B=9E=E9=80=80=20MyData.jav?= =?UTF-8?q?a=20=E7=9A=84=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E6=81=A2=E5=A4=8D=E4=B8=BA=E7=A9=BA=20TODO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户明确表示不需要改动 MyData 的 TODO,回退 741d7aa 对该文件的修改。 --- web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java b/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java index d7793d0..4614000 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/model/MyData.java @@ -24,7 +24,6 @@ public class MyData implements Serializable { public MyData(JsonObject jsonObject) { - this.id = jsonObject.getString("id"); - this.maxSize = jsonObject.getString("maxSize"); + // TODO } } From 2a9fa81e560afc2b144e153f10b9857a44313928 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 07:02:23 +0800 Subject: [PATCH 62/93] =?UTF-8?q?fix:=20CacheManager=20registerPeriodicCle?= =?UTF-8?q?anup=20=E6=B7=BB=E5=8A=A0=E9=98=B2=E9=87=8D=E5=85=A5=E5=92=8C?= =?UTF-8?q?=20Vertx=20=E5=B0=B1=E7=BB=AA=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审查发现 static 块中注册定时任务存在时序风险:如果 CacheServiceImpl 在 Vertx 初始化前被加载,定时任务将注册失败且无法恢复。添加 cleanupRegistered 标志防止 重复注册,Vertx 未就绪时跳过并等待下次调用。 --- .../main/java/cn/qaiu/lz/common/cache/CacheManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java index 3980721..947670d 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/cache/CacheManager.java @@ -232,9 +232,17 @@ public class CacheManager { * 注册定时清理过期缓存任务(每小时执行一次) * 应在应用启动后调用 */ + private static volatile boolean cleanupRegistered = false; + public static void registerPeriodicCleanup() { + if (cleanupRegistered) return; try { io.vertx.core.Vertx vertx = cn.qaiu.vx.core.util.VertxHolder.getVertxInstance(); + if (vertx == null) { + LOGGER.warn("Vertx 未就绪,缓存定时清理任务延迟注册"); + return; + } + cleanupRegistered = true; vertx.setPeriodic(3600_000, 3600_000, id -> { try { new CacheManager().cleanupExpiredCache(); From d6e88f0c53effc9a6dcff34689e2afa4d6e450bb Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 07:06:53 +0800 Subject: [PATCH 63/93] =?UTF-8?q?fix:=20PlaygroundApi=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=20import=20=E5=92=8C=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=20getStackTrace=20=E6=AD=BB=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审查发现 42925c8 引入了重复的 StandardCharsets import,且 getStackTrace 方法在移除堆栈泄露后无任何调用方,属于死代码。 --- .../cn/qaiu/lz/web/controller/PlaygroundApi.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java index fb54307..09ae694 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java @@ -28,7 +28,6 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; @@ -696,19 +695,5 @@ public class PlaygroundApi { } return ip; } - - /** - * 获取异常堆栈信息 - */ - private String getStackTrace(Throwable throwable) { - if (throwable == null) { - return ""; - } - log.error("获取异常堆栈信息", throwable); - java.io.StringWriter sw = new java.io.StringWriter(); - java.io.PrintWriter pw = new java.io.PrintWriter(sw); - throwable.printStackTrace(pw); - return sw.toString(); - } } From d1569195e46334351700fbce4e84b5ac1eb1ea0b Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 07:22:57 +0800 Subject: [PATCH 64/93] =?UTF-8?q?fix:=20AppMain=20=E6=B3=A8=E5=86=8C=20Shu?= =?UTF-8?q?tdownHook=20=E5=85=B3=E9=97=AD=20JDBCPoolInit=20=E5=92=8C=20JsP?= =?UTF-8?q?arserExecutor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审查发现 9c3945f 因模块依赖问题回退了 ShutdownHook 中的清理逻辑, 导致 JDBCPoolInit 连接池和 JsParserExecutor WorkerExecutor 在进程退出时 无法被显式关闭。将清理逻辑移到 web-service 模块的 AppMain(可依赖所有模块)。 --- web-service/src/main/java/cn/qaiu/lz/AppMain.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web-service/src/main/java/cn/qaiu/lz/AppMain.java b/web-service/src/main/java/cn/qaiu/lz/AppMain.java index 61bf631..bebaf76 100644 --- a/web-service/src/main/java/cn/qaiu/lz/AppMain.java +++ b/web-service/src/main/java/cn/qaiu/lz/AppMain.java @@ -38,6 +38,19 @@ public class AppMain { public static void main(String[] args) { // start Deploy.instance().start(args, AppMain::exec); + // 注册补充 ShutdownHook,关闭 core 模块无法直接依赖的资源 + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + JDBCPoolInit.instance().close(); + } catch (Exception e) { + // ignore + } + try { + cn.qaiu.parser.customjs.JsParserExecutor.shutdownExecutor(); + } catch (Exception e) { + // ignore + } + })); } /** From dd4027c9312c9c085035497d721da6a9021c4b2c Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 07:54:33 +0800 Subject: [PATCH 65/93] =?UTF-8?q?fix:=20LzTool/IzToolWithAuth=20=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E4=B8=A4=E5=A4=84=20.get().toString()=20NPE=20?= =?UTF-8?q?=E9=A3=8E=E9=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LzTool:221 — obj.get("url").toString() 改为 String.valueOf() - IzToolWithAuth:434 — get("uuid").toString() 添加 null 检查 --- parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java | 3 ++- parser/src/main/java/cn/qaiu/parser/impl/LzTool.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java index bae5d20..074d506 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java @@ -431,7 +431,8 @@ public class IzToolWithAuth extends PanBase { // 如果参数里的目录ID不为空,则直接解析目录 String dirId = (String) shareLinkInfo.getOtherParam().get("dirId"); if (dirId != null && !dirId.isEmpty()) { - uuid = shareLinkInfo.getOtherParam().get("uuid").toString(); + Object uuidObj = shareLinkInfo.getOtherParam().get("uuid"); + uuid = uuidObj != null ? uuidObj.toString() : null; parserDir(dirId, shareId, promise); return promise.future(); } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java index 298e9ea..4a2e2dc 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java @@ -218,7 +218,7 @@ public class LzTool extends PanBase { return; } Map signMap = (Map)obj.get("data"); - String url0 = obj.get("url").toString(); + String url0 = String.valueOf(obj.get("url")); MultiMap map = MultiMap.caseInsensitiveMultiMap(); signMap.forEach((k, v) -> { map.add((String) k, v.toString()); From df600eaada247ed76c8807170fa35e8c04c4a6d7 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 08:34:59 +0800 Subject: [PATCH 66/93] =?UTF-8?q?fix:=20Dockerfile=20=E9=A2=84=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=20db=20=E5=92=8C=20logs=20=E7=9B=AE=E5=BD=95=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9D=9E=20root=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=86=99=E5=85=A5=20H2=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit appuser 运行时无法在 /app 下创建新子目录,H2 尝试创建 /app/db/nfdData.mv.db 时因目录不存在导致 AccessDeniedException。在 chown 之前预创建目录。 --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 853eb64..1104a62 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,8 @@ COPY ./web-service/target/netdisk-fast-download-bin.zip . RUN unzip netdisk-fast-download-bin.zip && \ mv netdisk-fast-download/* ./ && \ rm netdisk-fast-download-bin.zip && \ - chmod +x run.sh + chmod +x run.sh && \ + mkdir -p db logs EXPOSE 6400 6401 From bff17f2d4e28bfa00a49518357c0eb9fa5f3a75f Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 08:46:57 +0800 Subject: [PATCH 67/93] =?UTF-8?q?fix:=20run.sh=20=E6=94=B9=E7=94=A8=20exec?= =?UTF-8?q?=20=E7=9B=B4=E6=8E=A5=E8=BF=90=E8=A1=8C=20Java=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Docker=20=E4=B8=AD=20ShutdownHook=20?= =?UTF-8?q?=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 nohup+tail-f 模式下,Docker SIGTERM 发给 tail 而非 Java 进程, 导致 ShutdownHook 永远不会触发,资源无法优雅关闭。 改为 exec 让 Java 成为 PID 1,正确接收信号。 同时支持通过 JVM_XMX/JVM_OPTS 环境变量自定义 JVM 参数。 --- bin/run.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/run.sh b/bin/run.sh index 06e7c53..04c111c 100644 --- a/bin/run.sh +++ b/bin/run.sh @@ -1,6 +1,5 @@ #!/bin/bash # set -x LAUNCH_JAR="netdisk-fast-download.jar" -nohup java -Xmx512M -jar "$LAUNCH_JAR" "$@" >startup.log 2>&1 & -tail -f startup.log +exec java -Xmx${JVM_XMX:-512M} ${JVM_OPTS} -jar "$LAUNCH_JAR" "$@" From 3c428f6a6de71ca62ee0f263ad9ec05ede807cad Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 09:01:08 +0800 Subject: [PATCH 68/93] =?UTF-8?q?fix:=20ShutdownHook=20=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E8=B0=83=E6=95=B4=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=20Vert.x=20=E5=85=88=E4=BA=8E=20JDBCPoolInit=20=E5=85=B3?= =?UTF-8?q?=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JVM ShutdownHook 按注册逆序执行。将 AppMain 的 hook 移到 Deploy.start() 之前注册, 使执行顺序变为:Deploy hook(关闭 Vert.x)-> AppMain hook(关闭 JDBCPoolInit/JsParserExecutor)。 --- web-service/src/main/java/cn/qaiu/lz/AppMain.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web-service/src/main/java/cn/qaiu/lz/AppMain.java b/web-service/src/main/java/cn/qaiu/lz/AppMain.java index bebaf76..933a0f5 100644 --- a/web-service/src/main/java/cn/qaiu/lz/AppMain.java +++ b/web-service/src/main/java/cn/qaiu/lz/AppMain.java @@ -36,9 +36,8 @@ import static cn.qaiu.vx.core.util.ConfigConstant.LOCAL; public class AppMain { public static void main(String[] args) { - // start - Deploy.instance().start(args, AppMain::exec); - // 注册补充 ShutdownHook,关闭 core 模块无法直接依赖的资源 + // 先注册 ShutdownHook(JVM 逆序执行,先注册的后执行) + // 确保关闭顺序:Vert.x -> JDBCPoolInit -> JsParserExecutor Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { JDBCPoolInit.instance().close(); @@ -51,6 +50,8 @@ public class AppMain { // ignore } })); + // start + Deploy.instance().start(args, AppMain::exec); } /** From 732a7f86fe1d0db698bd6c9fb2d9835599b80158 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 09:32:39 +0800 Subject: [PATCH 69/93] =?UTF-8?q?fix:=20Docker=20entrypoint=20=E4=BB=A5=20?= =?UTF-8?q?root=20=E8=BF=90=E8=A1=8C=E5=86=8D=E9=99=8D=E6=9D=83=EF=BC=8C?= =?UTF-8?q?=E5=BD=BB=E5=BA=95=E8=A7=A3=E5=86=B3=20volume=20=E6=9D=83?= =?UTF-8?q?=E9=99=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 去掉 USER appuser,entrypoint 以 root 身份运行,先 chown 修复 volume 挂载目录的权限,再通过 su 降权到 appuser 执行应用。 --- Dockerfile | 10 +++++----- docker-entrypoint.sh | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 docker-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 1104a62..a4cf774 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,10 +13,10 @@ RUN unzip netdisk-fast-download-bin.zip && \ chmod +x run.sh && \ mkdir -p db logs +COPY ./docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + EXPOSE 6400 6401 -RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser && \ - chown -R appuser:appgroup /app -USER appuser - -ENTRYPOINT ["sh", "run.sh"] +RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..762ca39 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +# Fix permissions on volume-mounted directories (runs as root) +chown -R appuser:appgroup /app/db /app/logs /app/resources 2>/dev/null || true + +# Run Java directly - entrypoint is PID 1, exec makes Java PID 1 +# Docker SIGTERM goes directly to Java, triggering ShutdownHook +exec java -Xmx${JVM_XMX:-512M} ${JVM_OPTS} -jar /app/netdisk-fast-download.jar From 1d243b8f1b67a5cf6312c144f320c20981e71969 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 09:57:05 +0800 Subject: [PATCH 70/93] =?UTF-8?q?fix:=20Docker=20EXPOSE=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E4=BB=85=206401=EF=BC=8Centrypoint=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20-Duser.timezone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审查发现: - EXPOSE 6400 误导用户映射后端端口,实际只需 6401(反向代理) - TZ 环境变量不如 JVM -Duser.timezone 可靠 --- Dockerfile | 2 +- docker-entrypoint.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a4cf774..be3c89b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN unzip netdisk-fast-download-bin.zip && \ COPY ./docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh -EXPOSE 6400 6401 +EXPOSE 6401 RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 762ca39..2bc18db 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -6,4 +6,4 @@ chown -R appuser:appgroup /app/db /app/logs /app/resources 2>/dev/null || true # Run Java directly - entrypoint is PID 1, exec makes Java PID 1 # Docker SIGTERM goes directly to Java, triggering ShutdownHook -exec java -Xmx${JVM_XMX:-512M} ${JVM_OPTS} -jar /app/netdisk-fast-download.jar +exec java -Xmx${JVM_XMX:-512M} ${JVM_OPTS} -Duser.timezone=${TZ:-Asia/Shanghai} -jar /app/netdisk-fast-download.jar From c62e109affa5a2ffc156d8aad68e198a5bec1165 Mon Sep 17 00:00:00 2001 From: yukaidi Date: Fri, 29 May 2026 10:09:49 +0800 Subject: [PATCH 71/93] =?UTF-8?q?fix:=20=E5=B0=86=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E7=9A=84=E4=B8=8A=E6=B8=B8=20GitHub=20URL=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20fork=20=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Home.vue、Playground.vue、parser/pom.xml 中的 qaiu/netdisk-fast-download URL 全部替换为 yukaidi1220/netdisk-fast-download。 --- parser/pom.xml | 6 +++--- web-front/src/views/Home.vue | 8 ++++---- web-front/src/views/Playground.vue | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/parser/pom.xml b/parser/pom.xml index 4d991c4..12713c1 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -35,9 +35,9 @@ - scm:git:https://github.com/qaiu/netdisk-fast-download.git - scm:git:ssh://git@github.com:qaiu/netdisk-fast-download.git - https://github.com/qaiu/netdisk-fast-download + scm:git:https://github.com/yukaidi1220/netdisk-fast-download.git + scm:git:ssh://git@github.com:yukaidi1220/netdisk-fast-download.git + https://github.com/yukaidi1220/netdisk-fast-download diff --git a/web-front/src/views/Home.vue b/web-front/src/views/Home.vue index e6999ec..dc770fc 100644 --- a/web-front/src/views/Home.vue +++ b/web-front/src/views/Home.vue @@ -19,11 +19,11 @@ -->