From 7ef274d3761bb2460c78bfe28318cfb215b0f488 Mon Sep 17 00:00:00 2001 From: kl Date: Thu, 8 Oct 2026 13:04:51 +0800 Subject: [PATCH] fix: preserve spreadsheet URLs for JavaScript escaping --- .../service/impl/OfficeFilePreviewImpl.java | 4 +- .../cn/keking/PreviewUrlEscapingTests.java | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 server/src/test/java/cn/keking/PreviewUrlEscapingTests.java diff --git a/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java index 00051a44..be99cd8e 100644 --- a/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java @@ -75,11 +75,11 @@ public class OfficeFilePreviewImpl implements FilePreview { if (!officePreviewType.equalsIgnoreCase("html")) { if (ConfigConstants.getOfficeTypeWeb().equalsIgnoreCase("web")) { if (suffix.equalsIgnoreCase("xlsx")) { - model.addAttribute("pdfUrl", KkFileUtils.htmlEscape(url)); //特殊符号处理 + model.addAttribute("pdfUrl", url); //模板使用 ?js_string 按 JavaScript 字符串上下文转义 return XLSX_FILE_PREVIEW_PAGE; } if (suffix.equalsIgnoreCase("csv")) { - model.addAttribute("csvUrl", KkFileUtils.htmlEscape(url)); + model.addAttribute("csvUrl", url); return CSV_FILE_PREVIEW_PAGE; } } diff --git a/server/src/test/java/cn/keking/PreviewUrlEscapingTests.java b/server/src/test/java/cn/keking/PreviewUrlEscapingTests.java new file mode 100644 index 00000000..23c40176 --- /dev/null +++ b/server/src/test/java/cn/keking/PreviewUrlEscapingTests.java @@ -0,0 +1,76 @@ +package cn.keking; + +import cn.keking.config.ConfigConstants; +import cn.keking.model.FileAttribute; +import cn.keking.service.impl.OfficeFilePreviewImpl; +import cn.keking.service.impl.PdfFilePreviewImpl; +import freemarker.template.Configuration; +import freemarker.template.Template; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.ui.ExtendedModelMap; + +import java.io.StringWriter; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PreviewUrlEscapingTests { + + @ParameterizedTest + @ValueSource(strings = {"pdf", "csv", "xlsx"}) + void shouldPreserveSourceUrlThroughPreviewModelAndTemplate(String suffix) throws Exception { + String sourceUrl = "https://files.example/Int'l/report%20one." + suffix + "?token=a&mode=b"; + String previousOfficeTypeWeb = ConfigConstants.getOfficeTypeWeb(); + ConfigConstants.setOfficeTypeWebValue("web"); + try { + FileAttribute file = new FileAttribute(); + file.setName("report." + suffix); + file.setSuffix(suffix); + file.setOfficePreviewType("pdf"); + file.setCacheName("url-escaping-test." + suffix); + + ExtendedModelMap model = new ExtendedModelMap(); + model.addAttribute("file", file); + model.addAttribute("baseUrl", "https://preview.example/"); + model.addAttribute("kkagent", "false"); + model.addAttribute("page", "0"); + model.addAttribute("switchDisabled", "true"); + model.addAttribute("watermarkTxt", ""); + model.addAttribute("xlsxshowtoolbar", false); + for (String name : new String[]{"watermarkXSpace", "watermarkYSpace", "watermarkAlpha", + "watermarkWidth", "watermarkHeight", "watermarkAngle"}) { + model.addAttribute(name, "0"); + } + for (String name : new String[]{"watermarkFont", "watermarkFontsize", "watermarkColor", + "highlightall", "pdfPresentationModeDisable", "pdfOpenFileDisable", "pdfPrintDisable", + "pdfDownloadDisable", "pdfBookmarkDisable", "pdfDisableEditing", "pdfSidebarOpen", "kkkey"}) { + model.addAttribute(name, ""); + } + + OfficeFilePreviewImpl office = new OfficeFilePreviewImpl(null, null, null, null); + String view = suffix.equals("pdf") + ? new PdfFilePreviewImpl(null, null, office, null).filePreviewHandle(sourceUrl, model, file) + : office.filePreviewHandle(sourceUrl, model, file); + assertEquals(Map.of("pdf", "pdf", "csv", "csv", "xlsx", "officeweb").get(suffix), view); + assertEquals(sourceUrl, model.get(suffix.equals("csv") ? "csvUrl" : "pdfUrl")); + + Configuration configuration = new Configuration(Configuration.VERSION_2_3_32); + configuration.setClassForTemplateLoading(getClass(), "/web"); + configuration.setDefaultEncoding("UTF-8"); + configuration.setClassicCompatible(true); + Template template = configuration.getTemplate(view + ".ftl"); + StringWriter output = new StringWriter(); + template.process(model, output); + String html = output.toString(); + + assertTrue(html.contains("var url = 'https://files.example/Int\\'l/report%20one." + + suffix + "?token=a&mode=b';"), html); + assertFalse(html.contains("'"), html); + } finally { + ConfigConstants.setOfficeTypeWebValue(previousOfficeTypeWeb); + } + } +}