Sanitizes blueprint and bundle names

https://github.com/BentoBoxWorld/BentoBox/issues/1038

Allows spaces to exist in the bundle names.

Added tests to check for bad chars and foreign chars in names.
This commit is contained in:
tastybento 2019-11-25 19:57:11 -08:00
parent 18eeec400d
commit ff60127762
3 changed files with 113 additions and 24 deletions

View File

@ -91,13 +91,13 @@ public class BlueprintClipboardManager {
* @throws IOException exception if there's an issue loading or unzipping
*/
public Blueprint loadBlueprint(String fileName) throws IOException {
File zipFile = new File(blueprintFolder, fileName + BlueprintsManager.BLUEPRINT_SUFFIX);
File zipFile = new File(blueprintFolder, BlueprintsManager.sanitizeFileName(fileName) + BlueprintsManager.BLUEPRINT_SUFFIX);
if (!zipFile.exists()) {
plugin.logError(LOAD_ERROR + zipFile.getName());
throw new IOException(LOAD_ERROR + zipFile.getName());
}
unzip(zipFile.getAbsolutePath());
File file = new File(blueprintFolder, fileName);
File file = new File(blueprintFolder, BlueprintsManager.sanitizeFileName(fileName));
if (!file.exists()) {
plugin.logError(LOAD_ERROR + file.getName());
throw new IOException(LOAD_ERROR + file.getName() + " temp file");
@ -114,7 +114,7 @@ public class BlueprintClipboardManager {
if (bp.getBedrock() == null) {
bp.setBedrock(new Vector(bp.getxSize() / 2, bp.getySize() / 2, bp.getzSize() / 2));
bp.getBlocks().put(bp.getBedrock(), new BlueprintBlock(Material.BEDROCK.createBlockData().getAsString()));
plugin.logWarning("Blueprint " + fileName + " had no bedrock block in it so one was added automatically in the center. You should check it.");
plugin.logWarning("Blueprint " + BlueprintsManager.sanitizeFileName(fileName) + BlueprintsManager.BLUEPRINT_SUFFIX + " had no bedrock block in it so one was added automatically in the center. You should check it.");
}
return bp;
}
@ -130,7 +130,7 @@ public class BlueprintClipboardManager {
load(fileName);
} catch (IOException e1) {
user.sendMessage("commands.admin.blueprint.could-not-load");
plugin.logError("Could not load blueprint file: " + fileName + " " + e1.getMessage());
plugin.logError("Could not load blueprint file: " + BlueprintsManager.sanitizeFileName(fileName) + BlueprintsManager.BLUEPRINT_SUFFIX + " " + e1.getMessage());
return false;
}
user.sendMessage("general.success");
@ -163,7 +163,7 @@ public class BlueprintClipboardManager {
plugin.logError("Blueprint name was empty - could not save it");
return false;
}
File file = new File(blueprintFolder, blueprint.getName());
File file = new File(blueprintFolder, BlueprintsManager.sanitizeFileName(blueprint.getName()));
String toStore = gson.toJson(blueprint, Blueprint.class);
try (FileWriter fileWriter = new FileWriter(file)) {
fileWriter.write(toStore);

View File

@ -347,7 +347,7 @@ public class BlueprintsManager {
if (!bpf.exists()) {
bpf.mkdirs();
}
File fileName = new File(bpf, bb.getUniqueId() + BLUEPRINT_BUNDLE_SUFFIX);
File fileName = new File(bpf, sanitizeFileName(bb.getUniqueId()) + BLUEPRINT_BUNDLE_SUFFIX);
String toStore = gson.toJson(bb, BlueprintBundle.class);
try (FileWriter fileWriter = new FileWriter(fileName)) {
fileWriter.write(toStore);
@ -357,6 +357,21 @@ public class BlueprintsManager {
});
}
/**
* Sanitizes a filename as much as possible retaining the original name
* @param name - filename to sanitize
* @return sanitized name
*/
public static String sanitizeFileName(String name) {
return name
.chars()
.mapToObj(i -> (char) i)
.map(c -> Character.isWhitespace(c) ? '_' : c)
.filter(c -> Character.isLetterOrDigit(c) || c == '-' || c == '_')
.map(String::valueOf)
.collect(Collectors.joining());
}
/**
* Saves all the blueprint bundles
*/
@ -506,7 +521,7 @@ public class BlueprintsManager {
blueprintBundles.get(addon).removeIf(k -> k.getUniqueId().equals(bb.getUniqueId()));
}
File bpf = getBlueprintsFolder(addon);
File fileName = new File(bpf, bb.getUniqueId() + BLUEPRINT_BUNDLE_SUFFIX);
File fileName = new File(bpf, sanitizeFileName(bb.getUniqueId()) + BLUEPRINT_BUNDLE_SUFFIX);
try {
Files.deleteIfExists(fileName.toPath());
} catch (IOException e) {
@ -528,7 +543,7 @@ public class BlueprintsManager {
}
File bpf = getBlueprintsFolder(addon);
// Get the filename
File fileName = new File(bpf, bp.getName() + BLUEPRINT_SUFFIX);
File fileName = new File(bpf, sanitizeFileName(bp.getName()) + BLUEPRINT_SUFFIX);
// Delete the old file
try {
Files.deleteIfExists(fileName.toPath());

View File

@ -3,6 +3,7 @@ package world.bentobox.bentobox.managers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ -28,7 +29,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@ -46,6 +46,8 @@ import world.bentobox.bentobox.blueprints.BlueprintClipboard;
@PrepareForTest( {Bukkit.class, BentoBox.class} )
public class BlueprintClipboardManagerTest {
private static final String BLUEPRINT = "blueprint";
@Mock
private BentoBox plugin;
@Mock
@ -120,9 +122,11 @@ public class BlueprintClipboardManagerTest {
@Before
public void setUp() throws Exception {
blueprintFolder = new File("blueprints");
// Clear any residual files
tearDown();
PowerMockito.mockStatic(Bukkit.class);
BlockData blockData = mock(BlockData.class);
when(Bukkit.createBlockData(Mockito.any(Material.class))).thenReturn(blockData);
when(Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
when(blockData.getAsString()).thenReturn("test123");
}
@ -131,6 +135,7 @@ public class BlueprintClipboardManagerTest {
*/
@After
public void tearDown() throws Exception {
if (blueprintFolder.exists()) {
// Clean up file system
Files.walk(blueprintFolder.toPath())
@ -198,7 +203,7 @@ public class BlueprintClipboardManagerTest {
assertTrue(configFile.exists());
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
try {
bcm.loadBlueprint("blueprint");
bcm.loadBlueprint(BLUEPRINT);
} catch (Exception e) {
assertTrue(e instanceof IOException);
} finally {
@ -216,13 +221,13 @@ public class BlueprintClipboardManagerTest {
// Make a blueprint file
YamlConfiguration config = new YamlConfiguration();
config.set("hello", "this is a test");
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
config.save(configFile);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
try {
bcm.loadBlueprint("blueprint");
bcm.loadBlueprint(BLUEPRINT);
} catch (Exception e) {
assertTrue(e instanceof IOException);
} finally {
@ -238,13 +243,13 @@ public class BlueprintClipboardManagerTest {
public void testLoadBlueprintFileInZipNoBedrock() throws IOException {
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = jsonNoBedrock.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
Blueprint bp = bcm.loadBlueprint("blueprint");
Blueprint bp = bcm.loadBlueprint(BLUEPRINT);
verify(plugin).logWarning("Blueprint blueprint had no bedrock block in it so one was added automatically in the center. You should check it.");
// Verify bedrock was placed in the center of the blueprint
assertEquals(5, bp.getBedrock().getBlockX());
@ -260,13 +265,13 @@ public class BlueprintClipboardManagerTest {
public void testLoadBlueprintFileInZip() throws IOException {
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
Blueprint bp = bcm.loadBlueprint("blueprint");
Blueprint bp = bcm.loadBlueprint(BLUEPRINT);
assertEquals(-2, bp.getBedrock().getBlockX());
assertEquals(-16, bp.getBedrock().getBlockY());
assertEquals(-1, bp.getBedrock().getBlockZ());
@ -283,13 +288,13 @@ public class BlueprintClipboardManagerTest {
public void testLoadString() throws IOException {
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
bcm.load("blueprint");
bcm.load(BLUEPRINT);
Blueprint bp = bcm.getClipboard().getBlueprint();
assertEquals(-2, bp.getBedrock().getBlockX());
assertEquals(-16, bp.getBedrock().getBlockY());
@ -307,14 +312,14 @@ public class BlueprintClipboardManagerTest {
public void testLoadUserString() throws IOException {
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
User user = mock(User.class);
assertTrue(bcm.load(user, "blueprint"));
assertTrue(bcm.load(user, BLUEPRINT));
verify(user).sendMessage("general.success");
}
@ -326,7 +331,7 @@ public class BlueprintClipboardManagerTest {
public void testLoadUserStringFail() throws IOException {
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
User user = mock(User.class);
assertFalse(bcm.load(user, "blueprint"));
assertFalse(bcm.load(user, BLUEPRINT));
verify(user).sendMessage("commands.admin.blueprint.could-not-load");
verify(plugin).logError("Could not load blueprint file - does not exist : blueprint.blu");
}
@ -340,13 +345,13 @@ public class BlueprintClipboardManagerTest {
// Load a blueprint, then save it
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, "blueprint");
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
bcm.load("blueprint");
bcm.load(BLUEPRINT);
User user = mock(User.class);
assertTrue(bcm.save(user, "test1234"));
File bp = new File(blueprintFolder, "test1234.blu");
@ -354,6 +359,75 @@ public class BlueprintClipboardManagerTest {
verify(user).sendMessage("general.success");
}
/**
* Test method for {@link world.bentobox.bentobox.managers.BlueprintClipboardManager#save(world.bentobox.bentobox.api.user.User, java.lang.String)}.
* @throws IOException
*/
@Test
public void testSaveBadChars() throws IOException {
// Load a blueprint, then save it
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
bcm.load(BLUEPRINT);
User user = mock(User.class);
assertTrue(bcm.save(user, "test.1234/../../film"));
File bp = new File(blueprintFolder, "test1234film.blu");
assertTrue(bp.exists());
verify(user).sendMessage("general.success");
}
/**
* Test method for {@link world.bentobox.bentobox.managers.BlueprintClipboardManager#save(world.bentobox.bentobox.api.user.User, java.lang.String)}.
* @throws IOException
*/
@Test
public void testSaveForeignChars() throws IOException {
// Load a blueprint, then save it
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
bcm.load(BLUEPRINT);
User user = mock(User.class);
assertTrue(bcm.save(user, "日本語の言葉"));
File bp = new File(blueprintFolder, "日本語の言葉.blu");
assertTrue(bp.exists());
verify(user).sendMessage("general.success");
}
/**
* Test method for {@link world.bentobox.bentobox.managers.BlueprintClipboardManager#save(world.bentobox.bentobox.api.user.User, java.lang.String)}.
* @throws IOException
*/
@Test
public void testSaveForeignBadChars() throws IOException {
// Load a blueprint, then save it
blueprintFolder.mkdirs();
// Make a blueprint file
File configFile = new File(blueprintFolder, BLUEPRINT);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Files.write(configFile.toPath(), bytes, StandardOpenOption.CREATE);
// Zip it
zip(configFile);
BlueprintClipboardManager bcm = new BlueprintClipboardManager(plugin, blueprintFolder);
bcm.load(BLUEPRINT);
User user = mock(User.class);
assertTrue(bcm.save(user, "日本語の言葉/../../../config"));
File bp = new File(blueprintFolder, "日本語の言葉config.blu");
assertTrue(bp.exists());
verify(user).sendMessage("general.success");
}
/**
* Test method for {@link world.bentobox.bentobox.managers.BlueprintClipboardManager#saveBlueprint(world.bentobox.bentobox.blueprints.Blueprint)}.
*/