Fixes incorrect migration of legacy encrypted books
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good

This commit is contained in:
2025-08-22 00:11:29 +02:00
parent cbe3a977ac
commit e342f4cff5
5 changed files with 60 additions and 32 deletions

View File

@@ -41,7 +41,7 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
return false;
}
EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.SUBSTITUTION;
EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.AES;
return encryptBook(encryptionStyle, player, arguments[1], arguments[0], false);
}

View File

@@ -28,7 +28,9 @@ public enum StaticMessage {
WARNING_USER_BOOK_MIGRATION_IMPOSSIBLE("Unable to migrate player book directory for player {player}"),
EXCEPTION_BOOK_LOAD_NULL("Text file's first line was null"),
EXCEPTION_BOOK_LOAD_FAILED("Unable to read text file"),
EXCEPTION_BOOK_UNKNOWN_EXTENSION("Trying to load a book file with an unrecognized extension");
EXCEPTION_BOOK_UNKNOWN_EXTENSION("Trying to load a book file with an unrecognized extension"),
EXCEPTION_UNEXPECTED_ENCRYPTED_BOOK("Attempted to load a normal book, but found an encrypted book instead"),
;
private final @NotNull String messageString;

View File

@@ -95,16 +95,23 @@ public class MigrationQueueThread implements Runnable {
EncryptedBook encryptedBook = null;
BookMeta loadedBook = null;
String extension = BookFileHelper.getExtensionFromPath(file.getName());
if (!extension.equalsIgnoreCase("txt") && !extension.equalsIgnoreCase("yml")) {
BooksWithoutBorders.log(Level.WARNING, "File with unexpected extension " + extension + " encountered!");
return true;
}
// Attempt loading an encrypted book if necessary
if (file.getAbsolutePath().contains("Books" + slash + "Encrypted")) {
encryptedBook = BookToFromTextHelper.encryptedBookFromYml(file, bookMeta, "", true);
encryptedBook = BookToFromTextHelper.encryptedBookFromYml(file, bookMeta, "", true, true);
if (encryptedBook != null) {
loadedBook = encryptedBook.bookMeta();
}
} else if (extension.equalsIgnoreCase("txt") || extension.equalsIgnoreCase("yml")) {
}
// Attempt to load the book normally
if (loadedBook == null) {
loadedBook = BookToFromTextHelper.bookFromFile(file, bookMeta);
} else {
BooksWithoutBorders.log(Level.WARNING, "File with unexpected extension " + extension + " encountered!");
return true;
}
if (loadedBook == null) {

View File

@@ -44,7 +44,7 @@ public final class BookToFromTextHelper {
if (file.getName().endsWith(".txt")) {
return bookFromTXT(file, bookMetadata);
} else if (file.getName().endsWith(".yml")) {
return bookFromYml(file, bookMetadata);
return bookFromYml(file, bookMetadata, false);
} else {
throw new IllegalArgumentException(StaticMessage.EXCEPTION_BOOK_UNKNOWN_EXTENSION.toString());
}
@@ -100,7 +100,8 @@ public final class BookToFromTextHelper {
}
// Make sure the plaintext cannot simply be seen in the file
if (BooksWithoutBorders.getConfiguration().useRealEncryption()) {
if (BooksWithoutBorders.getConfiguration().useRealEncryption() &&
encryptedBook.encryptionStyle() == EncryptionStyle.AES) {
bookYml.set("Pages", null);
}
@@ -114,15 +115,17 @@ public final class BookToFromTextHelper {
* @param bookMetadata <p>Metadata which will be altered with the book's contents</p>
* @param userKey <p>The user-supplied decryption key</p>
* @param forceDecrypt <p>Whether to use the saved key for decryption, ignoring the supplied key</p>
* @param loadEncrypted <p>Whether to load the book in its encrypted form, even if it cannot be admin decrypted</p>
* @return <p>Metadata for the loaded book</p>
*/
@Nullable
public static EncryptedBook encryptedBookFromYml(@NotNull File file, @NotNull BookMeta bookMetadata,
@NotNull String userKey, boolean forceDecrypt) {
@NotNull String userKey, boolean forceDecrypt,
boolean loadEncrypted) {
BookMeta meta;
try {
meta = bookFromYml(file, bookMetadata);
meta = bookFromYml(file, bookMetadata, true);
if (meta == null) {
return null;
}
@@ -146,8 +149,12 @@ public final class BookToFromTextHelper {
List<String> data = bookYml.getStringList("Encryption.Data");
EncryptionStyle encryptionStyle = EncryptionStyle.getFromString(bookYml.getString("Encryption.Style",
EncryptionStyle.SUBSTITUTION.toString()));
// If encryption style is null, that means the book was not encrypted in a way this can decrypt
String encryptionStyleName = bookYml.getString("Encryption.Style");
if (encryptionStyleName == null) {
return null;
}
EncryptionStyle encryptionStyle = EncryptionStyle.getFromString(encryptionStyleName);
AESConfiguration aesConfiguration = null;
if (encryptionStyle == EncryptionStyle.AES) {
@@ -174,11 +181,12 @@ public final class BookToFromTextHelper {
userKey, false);
if (decryptedPages != null && !decryptedPages.isEmpty()) {
meta.setPages(decryptedPages);
return encryptedBook;
} else if (loadEncrypted) {
return encryptedBook;
} else {
return null;
}
return encryptedBook;
}
/**
@@ -218,15 +226,29 @@ public final class BookToFromTextHelper {
*
* @param file <p>The path of the file to load</p>
* @param bookMetadata <p>Metadata which will be altered with the book's contents</p>
* @param isEncrypted <p>Whether the book is expected to be encrypted</p>
* @return <p>Metadata for the loaded book</p>
*/
@Nullable
private static BookMeta bookFromYml(@NotNull File file, @NotNull BookMeta bookMetadata) {
private static BookMeta bookFromYml(@NotNull File file, @NotNull BookMeta bookMetadata, boolean isEncrypted) {
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
try {
FileConfiguration bookYml = YamlConfiguration.loadConfiguration(file);
// Don't allow encrypted books to be loaded unless known to be encrypted
String encryptionStyleName = bookYml.getString("Encryption.Style");
if (!isEncrypted && encryptionStyleName != null) {
BooksWithoutBorders.log(Level.WARNING, StaticMessage.EXCEPTION_UNEXPECTED_ENCRYPTED_BOOK.toString());
return null;
}
try {
bookMetadata.setGeneration(BookMeta.Generation.valueOf(bookYml.getString("Generation", "ORIGINAL")));
} catch (IllegalArgumentException exception) {
BooksWithoutBorders.log(Level.FINE, exception.getMessage());
return null;
}
bookMetadata.setTitle(bookYml.getString("Title",
stringFormatter.getUnFormattedColoredMessage(Formatting.NEUTRAL_UNKNOWN_TITLE)));
bookMetadata.setAuthor(authorFromUUID(bookYml.getString("Author",
@@ -234,9 +256,6 @@ public final class BookToFromTextHelper {
bookMetadata.setPages(bookYml.getStringList("Pages"));
bookMetadata.setLore(bookYml.getStringList("Lore"));
bookMetadata.setDisplayName(bookYml.getString("DisplayName"));
} catch (IllegalArgumentException exception) {
return null;
}
return bookMetadata;
}

View File

@@ -275,7 +275,7 @@ public final class EncryptionHelper {
return null;
} else {
try {
EncryptedBook book = BookToFromTextHelper.encryptedBookFromYml(file, bookMetadata, key, forceDecrypt);
EncryptedBook book = BookToFromTextHelper.encryptedBookFromYml(file, bookMetadata, key, forceDecrypt, false);
if (book == null) {
throw new IllegalArgumentException();
} else {