From 127a8b71c0efe9ee844bbaf0616e72281f3a32e7 Mon Sep 17 00:00:00 2001 From: ezio <54128896+eziosudo@users.noreply.github.com> Date: Thu, 9 Jun 2022 15:48:13 +0800 Subject: [PATCH] Filter reserved characters in file names (#2143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Issue-2121 bugfix 过滤文件名中的非法字符 * Issue-2121 todo: 需要增加一些单元测试 * Issue-2121 add UT * Issue-2121 add UT * Issue-2121 move filter method to FileUtils * Issue-2121 move filter method to FilenameUtils * Issue-2121 checkstyle formatted * Issue-2121 1. add regex to filter more reversed info 2. limit filename length in 200 2. add UT * Issue-2121 remove tail dots * Issue-2121 throw FileOperationException if filename is empty * Issue-2121 trim() string after substring it * Issue-2121 change pattern name * Issue-2121 revert irrelevant code * Issue-2121 bug, '+' should not be filtered --- .../app/service/impl/BackupServiceImpl.java | 4 +- .../run/halo/app/utils/FilenameUtils.java | 28 ++++++++ .../run/halo/app/utils/FilenameUtilsTest.java | 65 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java b/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java index ed9a861ee..ef5957ff9 100644 --- a/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java @@ -106,6 +106,7 @@ import run.halo.app.service.UserService; import run.halo.app.utils.DateTimeUtils; import run.halo.app.utils.DateUtils; import run.halo.app.utils.FileUtils; +import run.halo.app.utils.FilenameUtils; import run.halo.app.utils.HaloUtils; import run.halo.app.utils.JsonUtils; import run.halo.app.utils.VersionUtil; @@ -630,8 +631,9 @@ public class BackupServiceImpl implements BackupService { } content.append(postMarkdownVo.getOriginalContent()); try { + String filename = postMarkdownVo.getTitle() + "-" + postMarkdownVo.getSlug(); String markdownFileName = - postMarkdownVo.getTitle() + "-" + postMarkdownVo.getSlug() + ".md"; + FilenameUtils.sanitizeFilename(filename) + ".md"; Path markdownFilePath = Paths.get(markdownFileTempPathName, markdownFileName); if (!Files.exists(markdownFilePath.getParent())) { Files.createDirectories(markdownFilePath.getParent()); diff --git a/src/main/java/run/halo/app/utils/FilenameUtils.java b/src/main/java/run/halo/app/utils/FilenameUtils.java index f719b7a84..62432e748 100644 --- a/src/main/java/run/halo/app/utils/FilenameUtils.java +++ b/src/main/java/run/halo/app/utils/FilenameUtils.java @@ -3,9 +3,12 @@ package run.halo.app.utils; import java.io.File; import java.util.Arrays; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.util.Assert; +import run.halo.app.exception.FileOperationException; /** * Filename utilities. @@ -15,6 +18,14 @@ import org.springframework.util.Assert; */ public class FilenameUtils { + private static final Pattern FILENAME_RESERVED_CHARS_PATTERN = + Pattern.compile("[\\\\/:*?\"<>|.]"); + + private static final Pattern FILENAME_WIN_RESERVED_NAMES_PATTERN = + Pattern.compile("^(CON|PRM|AUX|NUL|COM[0-9]|LPT[0-9])$"); + + private static final int FILENAME_MAX_LENGTH = 200; + private FilenameUtils() { } @@ -104,4 +115,21 @@ public class FilenameUtils { return filename.substring(dotLastIndex + 1); } + /** + * @param filename filename + * @return sanitized filename, without any reserved character + */ + public static String sanitizeFilename(String filename) { + String sanitizedFilename = + FILENAME_RESERVED_CHARS_PATTERN.matcher(filename.trim()).replaceAll(""); + if (StringUtils.isEmpty(sanitizedFilename)) { + throw new FileOperationException("文件名不合法: " + filename); + } + Matcher matcher = FILENAME_WIN_RESERVED_NAMES_PATTERN.matcher(sanitizedFilename); + if (matcher.matches()) { + sanitizedFilename = sanitizedFilename + "_file"; + } + return sanitizedFilename.length() < FILENAME_MAX_LENGTH ? sanitizedFilename : + sanitizedFilename.substring(0, FILENAME_MAX_LENGTH).trim(); + } } diff --git a/src/test/java/run/halo/app/utils/FilenameUtilsTest.java b/src/test/java/run/halo/app/utils/FilenameUtilsTest.java index be60b1655..729f5f19a 100644 --- a/src/test/java/run/halo/app/utils/FilenameUtilsTest.java +++ b/src/test/java/run/halo/app/utils/FilenameUtilsTest.java @@ -1,8 +1,10 @@ package run.halo.app.utils; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; +import run.halo.app.exception.FileOperationException; /** * Filename utilities test. @@ -45,4 +47,67 @@ class FilenameUtilsTest { assertEquals("tar.gz", FilenameUtils.getExtension("he/ll/o.tar.gz")); assertEquals("tar.bz2", FilenameUtils.getExtension("he/ll/o.tar.bz2")); } + + @Test + public void fileNameWithReservedCharsWillBeReplaced() { + String filename1 = "abcde"; + String filteredFilename1 = FilenameUtils.sanitizeFilename(filename1); + assertEquals("abcde", filteredFilename1); + + String filename2 = "abcde|字符替换\\星号*大于>小于 FilenameUtils.sanitizeFilename(filename)); + assertEquals("文件名不合法: ?<>\\:*|...", exception.getMessage()); + } }