Fixes migration removing password keys, and removes more static strings
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good

This commit is contained in:
2025-08-17 14:02:11 +02:00
parent dc5d18550f
commit 57ca6ff2e9
11 changed files with 91 additions and 22 deletions

View File

@@ -113,10 +113,12 @@ public class CommandDecrypt implements TabExecutor {
String key = ""; String key = "";
for (String encryptedFile : encryptedFiles) { for (String encryptedFile : encryptedFiles) {
if (encryptedFile.contains(BookHelper.getBookFile(bookMetadata, player, true).replace(" ", "_"))) { if (encryptedFile.contains(BookHelper.getBookFile(bookMetadata, player, true).replace(" ", "_"))) {
key = encryptedFile.substring(encryptedFile.indexOf("[") + 1, encryptedFile.indexOf("]")); key = EncryptionHelper.extractLegacyKey(encryptedFile);
if (!key.isBlank()) {
break; break;
} }
} }
}
if (!key.isBlank()) { if (!key.isBlank()) {
//Decrypt the book //Decrypt the book

View File

@@ -111,7 +111,7 @@ public class CommandGive implements TabExecutor {
try { try {
return loadAndGiveBook(bookIdentifier, sender, receivingPlayer, isSigned, folder, copies); return loadAndGiveBook(bookIdentifier, sender, receivingPlayer, isSigned, folder, copies);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_GIVE_INVALID_COPIES_AMOUNT); stringFormatter.displayErrorMessage(sender, Translatable.ERROR_INVALID_COPIES_AMOUNT);
return false; return false;
} }
} }

View File

@@ -1,7 +1,9 @@
package net.knarcraft.bookswithoutborders.command; package net.knarcraft.bookswithoutborders.command;
import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.config.Translatable;
import net.knarcraft.bookswithoutborders.encryption.EncryptionStyle; import net.knarcraft.bookswithoutborders.encryption.EncryptionStyle;
import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
@@ -19,8 +21,14 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] arguments) { @NotNull String[] arguments) {
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
if (!(sender instanceof Player player)) {
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY);
return false;
}
BookMeta bookMetadata = performPreChecks(sender, arguments, 2, BookMeta bookMetadata = performPreChecks(sender, arguments, 2,
"You must specify a group name and key to encrypt a book!"); stringFormatter.getUnFormattedColoredMessage(Translatable.ERROR_GROUP_ENCRYPT_ARGUMENTS_MISSING));
if (bookMetadata == null) { if (bookMetadata == null) {
return false; return false;
@@ -29,12 +37,12 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
//Check if book is already group encrypted //Check if book is already group encrypted
List<String> lore = bookMetadata.getLore(); List<String> lore = bookMetadata.getLore();
if (bookMetadata.hasLore() && lore != null && lore.get(0).contains(" encrypted]")) { if (bookMetadata.hasLore() && lore != null && lore.get(0).contains(" encrypted]")) {
BooksWithoutBorders.sendErrorMessage(sender, "Book is already group encrypted!"); stringFormatter.displayErrorMessage(sender, Translatable.ERROR_GROUP_ENCRYPTED_ALREADY);
return false; return false;
} }
EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.SUBSTITUTION; EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.SUBSTITUTION;
return encryptBook(encryptionStyle, (Player) sender, arguments[1], arguments[0]); return encryptBook(encryptionStyle, player, arguments[1], arguments[0]);
} }
@Override @Override

View File

@@ -1,10 +1,12 @@
package net.knarcraft.bookswithoutborders.command; package net.knarcraft.bookswithoutborders.command;
import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.config.Translatable;
import net.knarcraft.bookswithoutborders.gui.PagedBookIndex; import net.knarcraft.bookswithoutborders.gui.PagedBookIndex;
import net.knarcraft.bookswithoutborders.utility.BookLoader; import net.knarcraft.bookswithoutborders.utility.BookLoader;
import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper; import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper;
import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeHelper; import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeHelper;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.util.TabCompletionHelper; import net.knarcraft.knarlib.util.TabCompletionHelper;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -38,13 +40,14 @@ public class CommandLoad implements TabExecutor {
*/ */
public boolean loadBook(@NotNull CommandSender sender, @NotNull String[] arguments, @NotNull String directory, public boolean loadBook(@NotNull CommandSender sender, @NotNull String[] arguments, @NotNull String directory,
boolean loadPublic) { boolean loadPublic) {
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
BooksWithoutBorders.sendErrorMessage(sender, "This command can only be used by a player!"); stringFormatter.displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY);
return false; return false;
} }
if (player.getInventory().firstEmpty() == -1) { if (player.getInventory().firstEmpty() == -1) {
BooksWithoutBorders.sendErrorMessage(player, "You must have space in your inventory to load books!"); stringFormatter.displayErrorMessage(player, Translatable.ERROR_INVENTORY_FULL);
return false; return false;
} }
@@ -60,6 +63,7 @@ public class CommandLoad implements TabExecutor {
String copies = "1"; String copies = "1";
String isSigned = "true"; String isSigned = "true";
// Parse arguments at the end of the command, and treat the rest as the book name
if (argumentCount > 1) { if (argumentCount > 1) {
if (argumentCount > 2 && InputCleaningHelper.isInt(arguments[argumentCount - 2]) && if (argumentCount > 2 && InputCleaningHelper.isInt(arguments[argumentCount - 2]) &&
InputCleaningHelper.isBoolean(arguments[argumentCount - 1])) { InputCleaningHelper.isBoolean(arguments[argumentCount - 1])) {
@@ -90,14 +94,14 @@ public class CommandLoad implements TabExecutor {
ItemStack newBook = BookLoader.loadBook(player, bookToLoad, isSigned, directory, Integer.parseInt(copies)); ItemStack newBook = BookLoader.loadBook(player, bookToLoad, isSigned, directory, Integer.parseInt(copies));
if (newBook != null) { if (newBook != null) {
player.getInventory().addItem(newBook); player.getInventory().addItem(newBook);
BooksWithoutBorders.sendSuccessMessage(player, "Book created!"); stringFormatter.displaySuccessMessage(player, Translatable.SUCCESS_BOOK_LOADED);
return true; return true;
} else { } else {
BooksWithoutBorders.sendErrorMessage(player, "Book failed to load!"); stringFormatter.displayErrorMessage(player, Translatable.ERROR_LOAD_FAILED);
return false; return false;
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
BooksWithoutBorders.sendErrorMessage(player, "Invalid number of book copies specified!"); stringFormatter.displayErrorMessage(player, Translatable.ERROR_INVALID_COPIES_AMOUNT);
return false; return false;
} }
} }

View File

@@ -4,6 +4,7 @@ import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.config.Translatable; import net.knarcraft.bookswithoutborders.config.Translatable;
import net.knarcraft.bookswithoutborders.container.MigrationRequest; import net.knarcraft.bookswithoutborders.container.MigrationRequest;
import net.knarcraft.bookswithoutborders.thread.MigrationQueueThread; import net.knarcraft.bookswithoutborders.thread.MigrationQueueThread;
import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
@@ -25,12 +26,13 @@ public class CommandMigrate implements TabExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) { @NotNull String[] arguments) {
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY); BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY);
return false; return false;
} }
File bookDirectory = new File(BooksWithoutBorders.getConfiguration().getBookFolder()); File bookDirectory = new File(BooksWithoutBorders.getConfiguration().getBookFolder());
BooksWithoutBorders.sendSuccessMessage(player, "Starting book migration..."); stringFormatter.displaySuccessMessage(player, Translatable.SUCCESS_MIGRATION_STARTED);
Queue<MigrationRequest> filesToMigrate = new LinkedList<>(); Queue<MigrationRequest> filesToMigrate = new LinkedList<>();
findFilesToMigrate(bookDirectory, filesToMigrate, player); findFilesToMigrate(bookDirectory, filesToMigrate, player);
BooksWithoutBorders.getMigrationQueue().addAll(filesToMigrate); BooksWithoutBorders.getMigrationQueue().addAll(filesToMigrate);

View File

@@ -58,6 +58,16 @@ public enum Translatable implements TranslatableMessage {
*/ */
SUCCESS_PAGE_DELETED, SUCCESS_PAGE_DELETED,
/**
* The success message displayed after a book has been loaded
*/
SUCCESS_BOOK_LOADED,
/**
* The success message displayed after book migration has started
*/
SUCCESS_MIGRATION_STARTED,
/** /**
* The error to display when the console attempts to run a player-only command * The error to display when the console attempts to run a player-only command
*/ */
@@ -186,7 +196,7 @@ public enum Translatable implements TranslatableMessage {
/** /**
* The error displayed when using the give command with an invalid number of copies (unlikely to ever happen) * The error displayed when using the give command with an invalid number of copies (unlikely to ever happen)
*/ */
ERROR_GIVE_INVALID_COPIES_AMOUNT, ERROR_INVALID_COPIES_AMOUNT,
/** /**
* The error displayed when a book is not properly loaded when using the give command * The error displayed when a book is not properly loaded when using the give command
@@ -213,6 +223,21 @@ public enum Translatable implements TranslatableMessage {
*/ */
ERROR_OUT_OF_RANGE_BOOK_PAGE, ERROR_OUT_OF_RANGE_BOOK_PAGE,
/**
* The error displayed when a player fails to provide necessary arguments for group encryption
*/
ERROR_GROUP_ENCRYPT_ARGUMENTS_MISSING,
/**
* The error displayed when trying to attempt a group encrypted book twice
*/
ERROR_GROUP_ENCRYPTED_ALREADY,
/**
* The error displayed when a book fails to be loaded
*/
ERROR_LOAD_FAILED,
/** /**
* The header displayed before printing all commands * The header displayed before printing all commands
*/ */

View File

@@ -28,9 +28,9 @@ public class PlayerEventListener implements Listener {
//If a book directory exists with this player's name, move it to this player's UUID //If a book directory exists with this player's name, move it to this player's UUID
String bookFolder = config.getBookFolder(); String bookFolder = config.getBookFolder();
File file = new File(bookFolder + InputCleaningHelper.cleanString(player.getName())); File file = new File(bookFolder, InputCleaningHelper.cleanString(player.getName()));
if (file.exists()) { if (file.exists()) {
if (!file.renameTo(new File(bookFolder + player.getUniqueId()))) { if (!file.renameTo(new File(bookFolder, player.getUniqueId().toString()))) {
BooksWithoutBorders.log(Level.WARNING, "Unable to migrate player book " + BooksWithoutBorders.log(Level.WARNING, "Unable to migrate player book " +
"directory for player " + player.getName()); "directory for player " + player.getName());
} }

View File

@@ -5,6 +5,7 @@ import net.knarcraft.bookswithoutborders.container.MigrationRequest;
import net.knarcraft.bookswithoutborders.utility.BookFileHelper; import net.knarcraft.bookswithoutborders.utility.BookFileHelper;
import net.knarcraft.bookswithoutborders.utility.BookHelper; import net.knarcraft.bookswithoutborders.utility.BookHelper;
import net.knarcraft.bookswithoutborders.utility.BookToFromTextHelper; import net.knarcraft.bookswithoutborders.utility.BookToFromTextHelper;
import net.knarcraft.bookswithoutborders.utility.EncryptionHelper;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@@ -88,6 +89,7 @@ public class MigrationQueueThread implements Runnable {
if (bookMeta == null) { if (bookMeta == null) {
return false; return false;
} }
BookMeta loadedBook; BookMeta loadedBook;
String extension = BookFileHelper.getExtensionFromPath(file.getName()); String extension = BookFileHelper.getExtensionFromPath(file.getName());
if (extension.equalsIgnoreCase("yml")) { if (extension.equalsIgnoreCase("yml")) {
@@ -116,6 +118,13 @@ public class MigrationQueueThread implements Runnable {
try { try {
String newName = BookHelper.getBookFile(loadedBook, author, isPublic); String newName = BookHelper.getBookFile(loadedBook, author, isPublic);
// Retain legacy key
String key = EncryptionHelper.extractLegacyKey(file.getName());
if (!key.isBlank()) {
newName = "[" + key + "]" + newName;
}
return saveBook(file.getParentFile(), newName, loadedBook, file); return saveBook(file.getParentFile(), newName, loadedBook, file);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
BooksWithoutBorders.sendErrorMessage(player, "Failed to migrate book: " + file.getName() + " Cause:"); BooksWithoutBorders.sendErrorMessage(player, "Failed to migrate book: " + file.getName() + " Cause:");

View File

@@ -163,7 +163,6 @@ public final class BookToFromTextHelper {
userKey = realKey; userKey = realKey;
} }
if (!userKey.equals(realKey)) { if (!userKey.equals(realKey)) {
BooksWithoutBorders.log(Level.INFO, "Supplied key: " + userKey + " does not match real key: " + realKey);
return null; return null;
} }

View File

@@ -351,6 +351,21 @@ public final class EncryptionHelper {
return newBook; return newBook;
} }
/**
* Attempts to extract a legacy password key from a filename
*
* @param fileName <p>The filename to get the legacy key from</p>
* @return <p>The legacy key, or an empty string if not found</p>
*/
@NotNull
public static String extractLegacyKey(@NotNull String fileName) {
if (fileName.matches("^\\[[0-9]+].*")) {
return fileName.substring(fileName.indexOf("[") + 1, fileName.indexOf("]"));
} else {
return "";
}
}
/** /**
* Converts a byte array to a hexadecimal string * Converts a byte array to a hexadecimal string
* *

View File

@@ -10,17 +10,19 @@ en:
SUCCESS_GIVE_RECEIVED: "Book received!" SUCCESS_GIVE_RECEIVED: "Book received!"
SUCCESS_TITLE_PAGE_ADDED: "Title page added!" SUCCESS_TITLE_PAGE_ADDED: "Title page added!"
SUCCESS_PAGE_DELETED: "Page deleted!" SUCCESS_PAGE_DELETED: "Page deleted!"
ERROR_PLAYER_ONLY: "This command can only be used by a player!" SUCCESS_BOOK_LOADED: "Book created!"
ERROR_NOT_HOLDING_WRITTEN_BOOK: "You must be holding a written book to {action} it!" SUCCESS_MIGRATION_STARTED: "Starting book migration..."
ERROR_NOT_HOLDING_WRITABLE_BOOK: "You must be holding a writable book to {action} it!"
ERROR_NOT_HOLDING_ANY_BOOK: "You must be holding a book to perform this command"
ERROR_ONLY_ONE_BOOK: "You cannot {action} two books at once!"
ACTION_COPY: "copy" ACTION_COPY: "copy"
ACTION_CLEAR: "clear" ACTION_CLEAR: "clear"
ACTION_DECRYPT: "decrypt" ACTION_DECRYPT: "decrypt"
ACTION_ENCRYPT: "encrypt" ACTION_ENCRYPT: "encrypt"
ACTION_FORMAT: "format" ACTION_FORMAT: "format"
ACTION_ADD_TITLE_AUTHOR_PAGE: "add an author title page to" ACTION_ADD_TITLE_AUTHOR_PAGE: "add an author title page to"
ERROR_PLAYER_ONLY: "This command can only be used by a player!"
ERROR_NOT_HOLDING_WRITTEN_BOOK: "You must be holding a written book to {action} it!"
ERROR_NOT_HOLDING_WRITABLE_BOOK: "You must be holding a writable book to {action} it!"
ERROR_NOT_HOLDING_ANY_BOOK: "You must be holding a book to perform this command"
ERROR_ONLY_ONE_BOOK: "You cannot {action} two books at once!"
ERROR_COPY_COUNT_NOT_SPECIFIED: "You must specify the number of copies to be made!" ERROR_COPY_COUNT_NOT_SPECIFIED: "You must specify the number of copies to be made!"
ERROR_COPY_NEGATIVE_AMOUNT: "Number of copies must be larger than 0!" ERROR_COPY_NEGATIVE_AMOUNT: "Number of copies must be larger than 0!"
ERROR_COPY_INVALID_AMOUNT: | ERROR_COPY_INVALID_AMOUNT: |
@@ -44,11 +46,14 @@ en:
ERROR_GIVE_NO_RECIPIENT: "You have not specified the recipient of the book!" ERROR_GIVE_NO_RECIPIENT: "You have not specified the recipient of the book!"
ERROR_GIVE_RECIPIENT_UNKNOWN: "Player not found!" ERROR_GIVE_RECIPIENT_UNKNOWN: "Player not found!"
ERROR_GIVE_RECIPIENT_FULL: "Receiving player must have space in their inventory to receive books!" ERROR_GIVE_RECIPIENT_FULL: "Receiving player must have space in their inventory to receive books!"
ERROR_GIVE_INVALID_COPIES_AMOUNT: "Invalid number of book copies specified!" ERROR_INVALID_COPIES_AMOUNT: "Invalid number of book copies specified!"
ERROR_GIVE_LOAD_FAILED: "Book failed to load!" ERROR_GIVE_LOAD_FAILED: "Book failed to load!"
ERROR_INVALID_BOOK_PAGE: "Invalid page index given!" ERROR_INVALID_BOOK_PAGE: "Invalid page index given!"
ERROR_OUT_OF_RANGE_BOOK_PAGE: "The given page index is out of bounds!" ERROR_OUT_OF_RANGE_BOOK_PAGE: "The given page index is out of bounds!"
ERROR_NO_BOOK_PAGE: "You must supply a page index" ERROR_NO_BOOK_PAGE: "You must supply a page index"
ERROR_GROUP_ENCRYPT_ARGUMENTS_MISSING: "You must specify a group name and key to encrypt a book!"
ERROR_GROUP_ENCRYPTED_ALREADY: "Book is already group encrypted!"
ERROR_LOAD_FAILED: "Book failed to load!"
NEUTRAL_COMMANDS_HEADER: | NEUTRAL_COMMANDS_HEADER: |
&e[] denote optional parameters &e[] denote optional parameters
<> denote required parameters <> denote required parameters