minecraft-src/net/minecraft/world/level/validation/PathAllowList.java
2025-07-04 01:41:11 +03:00

104 lines
3.6 KiB
Java

package net.minecraft.world.level.validation;
import com.mojang.logging.LogUtils;
import java.io.BufferedReader;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
public class PathAllowList implements PathMatcher {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String COMMENT_PREFIX = "#";
private final List<PathAllowList.ConfigEntry> entries;
private final Map<String, PathMatcher> compiledPaths = new ConcurrentHashMap();
public PathAllowList(List<PathAllowList.ConfigEntry> entries) {
this.entries = entries;
}
public PathMatcher getForFileSystem(FileSystem fileSystem) {
return (PathMatcher)this.compiledPaths.computeIfAbsent(fileSystem.provider().getScheme(), string -> {
List<PathMatcher> list;
try {
list = this.entries.stream().map(configEntry -> configEntry.compile(fileSystem)).toList();
} catch (Exception var5) {
LOGGER.error("Failed to compile file pattern list", (Throwable)var5);
return path -> false;
}
return switch (list.size()) {
case 0 -> path -> false;
case 1 -> (PathMatcher)list.get(0);
default -> path -> {
for (PathMatcher pathMatcher : list) {
if (pathMatcher.matches(path)) {
return true;
}
}
return false;
};
};
});
}
public boolean matches(Path path) {
return this.getForFileSystem(path.getFileSystem()).matches(path);
}
public static PathAllowList readPlain(BufferedReader reader) {
return new PathAllowList(reader.lines().flatMap(string -> PathAllowList.ConfigEntry.parse(string).stream()).toList());
}
public record ConfigEntry(PathAllowList.EntryType type, String pattern) {
public PathMatcher compile(FileSystem fileSystem) {
return this.type().compile(fileSystem, this.pattern);
}
static Optional<PathAllowList.ConfigEntry> parse(String string) {
if (string.isBlank() || string.startsWith("#")) {
return Optional.empty();
} else if (!string.startsWith("[")) {
return Optional.of(new PathAllowList.ConfigEntry(PathAllowList.EntryType.PREFIX, string));
} else {
int i = string.indexOf(93, 1);
if (i == -1) {
throw new IllegalArgumentException("Unterminated type in line '" + string + "'");
} else {
String string2 = string.substring(1, i);
String string3 = string.substring(i + 1);
return switch (string2) {
case "glob", "regex" -> Optional.of(new PathAllowList.ConfigEntry(PathAllowList.EntryType.FILESYSTEM, string2 + ":" + string3));
case "prefix" -> Optional.of(new PathAllowList.ConfigEntry(PathAllowList.EntryType.PREFIX, string3));
default -> throw new IllegalArgumentException("Unsupported definition type in line '" + string + "'");
};
}
}
}
static PathAllowList.ConfigEntry glob(String glob) {
return new PathAllowList.ConfigEntry(PathAllowList.EntryType.FILESYSTEM, "glob:" + glob);
}
static PathAllowList.ConfigEntry regex(String regex) {
return new PathAllowList.ConfigEntry(PathAllowList.EntryType.FILESYSTEM, "regex:" + regex);
}
static PathAllowList.ConfigEntry prefix(String prefix) {
return new PathAllowList.ConfigEntry(PathAllowList.EntryType.PREFIX, prefix);
}
}
@FunctionalInterface
public interface EntryType {
PathAllowList.EntryType FILESYSTEM = FileSystem::getPathMatcher;
PathAllowList.EntryType PREFIX = (fileSystem, string) -> path -> path.toString().startsWith(string);
PathMatcher compile(FileSystem fileSystem, String string);
}
}