mirror of https://github.com/halo-dev/halo
Filter reserved characters in file names (#2143)
* 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 filteredpull/2149/head
parent
36b99d2476
commit
127a8b71c0
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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|字符替换\\星号*大于>小于<slash/中文字符、";
|
||||
String filteredFilename2 = FilenameUtils.sanitizeFilename(filename2);
|
||||
assertEquals("abcde字符替换星号大于小于slash中文字符、", filteredFilename2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNameWithReversedNameWillBeReplaced() {
|
||||
String filename1 = "CON ";
|
||||
String sanitizedName = FilenameUtils.sanitizeFilename(filename1);
|
||||
assertEquals("CON_file", sanitizedName);
|
||||
|
||||
String filename2 = "LPT19";
|
||||
sanitizedName = FilenameUtils.sanitizeFilename(filename2);
|
||||
assertEquals("LPT19", sanitizedName);
|
||||
|
||||
String filename3 = "CON 12345";
|
||||
sanitizedName = FilenameUtils.sanitizeFilename(filename3);
|
||||
assertEquals("CON 12345", sanitizedName);
|
||||
|
||||
String filename4 = "COM3";
|
||||
sanitizedName = FilenameUtils.sanitizeFilename(filename4);
|
||||
assertEquals("COM3_file", sanitizedName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filenameLengthLimit() {
|
||||
StringBuilder filename = new StringBuilder("haloe");
|
||||
while (filename.length() < 300) {
|
||||
filename.append("haloe");
|
||||
}
|
||||
assertEquals(300, filename.length());
|
||||
String sanitizedName = FilenameUtils.sanitizeFilename(filename.toString());
|
||||
assertEquals(200, sanitizedName.length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filenameMixTest() {
|
||||
String filename = "halo |I'd like.to $be a: CONtributor。。...";
|
||||
String sanitizedName = FilenameUtils.sanitizeFilename(filename);
|
||||
assertEquals("halo I'd liketo $be a CONtributor。。", sanitizedName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filenameWithDotsWillBeSanitized() {
|
||||
String filename = "pls.approve...my..PR..... ";
|
||||
String sanitizedName = FilenameUtils.sanitizeFilename(filename);
|
||||
assertEquals("plsapprovemyPR", sanitizedName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNameExtremelyInvalid() {
|
||||
String filename = "?<>\\:*|...";
|
||||
FileOperationException exception = assertThrows(FileOperationException.class,
|
||||
() -> FilenameUtils.sanitizeFilename(filename));
|
||||
assertEquals("文件名不合法: ?<>\\:*|...", exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue