Adds a per-book choice for preventing admin decryption when using real encryption
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
This commit is contained in:
69
README.md
69
README.md
@@ -35,6 +35,9 @@ Books without Borders has got your back!
|
||||
- Easily add a title page or chapter page (for an unsigned book, you can add a blank page as well)
|
||||
with `/addBookTitlePage`.
|
||||
- Remove extra blank pages or unneeded chapter pages with `/deleteBookPage`
|
||||
- If the necessary options are enabled, books can be truly encrypted with the AES cipher, making them impossible to
|
||||
decrypt without knowing the password. Even admin decryption can be made useless. Only enable if you are aware of the
|
||||
potential loss caused by forgotten passwords!
|
||||
|
||||
#### Group encryption
|
||||
|
||||
@@ -101,38 +104,39 @@ An in-game description of available commands is available through the /bwb comma
|
||||
|
||||
#### Single permissions
|
||||
|
||||
| Node | Description |
|
||||
|--------------------------------------------|---------------------------------------------------------------------------------|
|
||||
| bookswithoutborders.addtitlepage | Allows player to add a blank title page to a book |
|
||||
| bookswithoutborders.bypassauthoronlycopy | Allows player to ignore Author_Only_Copy config setting |
|
||||
| bookswithoutborders.bypassauthoronlyunsign | Allows player to ignore Author_Only_Unsign config setting |
|
||||
| bookswithoutborders.bypassauthoronlysave | Allows player to ignore Author_Only_Save config setting |
|
||||
| bookswithoutborders.bypassbookprice | Allows player to ignore Price_to_create_book config setting |
|
||||
| bookswithoutborders.clear | Allows player to clear the contents of the held writable book |
|
||||
| bookswithoutborders.copy | Allows player to copy books |
|
||||
| bookswithoutborders.decrypt | Allows player to decrypt books |
|
||||
| bookswithoutborders.decrypt.agroup | Allows player to decrypt books group-encrypted for group "agroup" |
|
||||
| bookswithoutborders.delete | Allows player to delete books from their personal directory |
|
||||
| bookswithoutborders.deletepage | Allows player to delete a page from a book |
|
||||
| bookswithoutborders.editbookshelf | Allows player to set name/lore for bookshelves, used for peeking |
|
||||
| bookswithoutborders.encrypt | Allows player to encrypt books |
|
||||
| bookswithoutborders.format | Allows a player to format a book |
|
||||
| bookswithoutborders.give | Allows player to give another player one of their privately saved books |
|
||||
| bookswithoutborders.givepublic | Allows a player to give another player a book from the public directory |
|
||||
| bookswithoutborders.groupencrypt | Allows player to use group-based encryption |
|
||||
| bookswithoutborders.load | Allows player to load books from their personal directory |
|
||||
| bookswithoutborders.loadpublic | Allows player to load from the public directory |
|
||||
| bookswithoutborders.peekbookshelf | Allows player to left-click a bookshelf to see the contents of the shelf |
|
||||
| bookswithoutborders.reload | Allows player to reload this plugin |
|
||||
| bookswithoutborders.save | Allows a player to save books to their personal directory |
|
||||
| bookswithoutborders.savepublic | Allows player to save to the public directory |
|
||||
| bookswithoutborders.setauthor | Allows player to set the author of the currently held book |
|
||||
| bookswithoutborders.setbookprice | Allows player to set the cost of creating a book |
|
||||
| bookswithoutborders.setgeneration | Allows player to change the generation of a book (Original, Copy, Copy of Copy) |
|
||||
| bookswithoutborders.settitle | Allows player to set the title of the currently held book |
|
||||
| bookswithoutborders.signs | Allows player to create signs that give/encrypt/decrypt books |
|
||||
| bookswithoutborders.unsign | Allows player to un-sign books |
|
||||
| bookswithoutborders.setlore | Allows player to set the lore of the currently held item |
|
||||
| Node | Description |
|
||||
|--------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
| bookswithoutborders.addtitlepage | Allows player to add a blank title page to a book |
|
||||
| bookswithoutborders.bypassauthoronlycopy | Allows player to ignore Author_Only_Copy config setting |
|
||||
| bookswithoutborders.bypassauthoronlyunsign | Allows player to ignore Author_Only_Unsign config setting |
|
||||
| bookswithoutborders.bypassauthoronlysave | Allows player to ignore Author_Only_Save config setting |
|
||||
| bookswithoutborders.bypassbookprice | Allows player to ignore Price_to_create_book config setting |
|
||||
| bookswithoutborders.clear | Allows player to clear the contents of the held writable book |
|
||||
| bookswithoutborders.copy | Allows player to copy books |
|
||||
| bookswithoutborders.decrypt | Allows player to decrypt books |
|
||||
| bookswithoutborders.decrypt.agroup | Allows player to decrypt books group-encrypted for group "agroup" |
|
||||
| bookswithoutborders.delete | Allows player to delete books from their personal directory |
|
||||
| bookswithoutborders.deletepage | Allows player to delete a page from a book |
|
||||
| bookswithoutborders.editbookshelf | Allows player to set name/lore for bookshelves, used for peeking |
|
||||
| bookswithoutborders.encrypt | Allows player to encrypt books |
|
||||
| bookswithoutborders.format | Allows a player to format a book |
|
||||
| bookswithoutborders.give | Allows player to give another player one of their privately saved books |
|
||||
| bookswithoutborders.givepublic | Allows a player to give another player a book from the public directory |
|
||||
| bookswithoutborders.groupencrypt | Allows player to use group-based encryption |
|
||||
| bookswithoutborders.load | Allows player to load books from their personal directory |
|
||||
| bookswithoutborders.loadpublic | Allows player to load from the public directory |
|
||||
| bookswithoutborders.peekbookshelf | Allows player to left-click a bookshelf to see the contents of the shelf |
|
||||
| bookswithoutborders.reload | Allows player to reload this plugin |
|
||||
| bookswithoutborders.save | Allows a player to save books to their personal directory |
|
||||
| bookswithoutborders.savepublic | Allows player to save to the public directory |
|
||||
| bookswithoutborders.setauthor | Allows player to set the author of the currently held book |
|
||||
| bookswithoutborders.setbookprice | Allows player to set the cost of creating a book |
|
||||
| bookswithoutborders.setgeneration | Allows player to change the generation of a book (Original, Copy, Copy of Copy) |
|
||||
| bookswithoutborders.settitle | Allows player to set the title of the currently held book |
|
||||
| bookswithoutborders.signs | Allows player to create signs that give/encrypt/decrypt books |
|
||||
| bookswithoutborders.unsign | Allows player to un-sign books |
|
||||
| bookswithoutborders.setlore | Allows player to set the lore of the currently held item |
|
||||
| bookswithoutborders.preventadmindecryption | If use real encryption and prevent admin decryption options are enabled, allows player to disable admin decryption for a book |
|
||||
|
||||
### Signs
|
||||
|
||||
@@ -173,3 +177,4 @@ The **_decrypt_** sign must have **\[Decrypt]** on its second line. The third li
|
||||
| Change_Generation_On_Copy | Whether to display "COPY" or "COPY_OF_COPY" instead of "ORIGINAL" when a book is copied. This also uses the vanilla behavior where a copy of a copy or tattered book cannot be copied further. |
|
||||
| Enable_Book_Peeking | Whether to enable hitting a chiseled bookshelf while sneaking to see the shelf's contents. |
|
||||
| Use_Real_Encryption | Enables true AES encryption instead of the very fake legacy encryption. The encryption key is stored in the book file to allow admin decryption, but looking at the encrypted book in the file system, only reveals the encrypted pages. Note that real encryption might alter, corrupt or lose a book's contents, so don't use real encryption with books that have no backup in in-game book form or saved book form. |
|
||||
| Allow_Prevent_Admin_Decryption | Allows players to disable storing the encryption key for an encrypted book. This is only usable for real encryption. This effectively disable admin decryption for the book. Providing the correct password is the only way to decrypt a book without a stored key. THIS IS A DANGEROUS OPTION! |
|
@@ -1,6 +1,8 @@
|
||||
package net.knarcraft.bookswithoutborders.command;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.BwBConfig;
|
||||
import net.knarcraft.bookswithoutborders.config.Permission;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Translatable;
|
||||
import net.knarcraft.bookswithoutborders.encryption.EncryptionStyle;
|
||||
import net.knarcraft.bookswithoutborders.state.ItemSlot;
|
||||
@@ -29,7 +31,7 @@ public class CommandEncrypt implements TabExecutor {
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] arguments) {
|
||||
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
|
||||
if (performPreChecks(sender, arguments, 1,
|
||||
if (performPreChecks(sender, arguments, 1, 2,
|
||||
stringFormatter.getUnFormattedColoredMessage(Translatable.ERROR_ENCRYPT_NO_KEY)) == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -37,11 +39,16 @@ public class CommandEncrypt implements TabExecutor {
|
||||
EncryptionStyle encryptionStyle = arguments.length == 2 ? EncryptionStyle.getFromString(arguments[1]) : EncryptionStyle.AES;
|
||||
|
||||
// AES is the only reliable method for retaining the plaintext
|
||||
if (BooksWithoutBorders.getConfiguration().useRealEncryption() && !encryptionStyle.isRealEncryptionSupported()) {
|
||||
BwBConfig config = BooksWithoutBorders.getConfiguration();
|
||||
boolean realEncryption = config.useRealEncryption();
|
||||
if (realEncryption && !encryptionStyle.isRealEncryptionSupported()) {
|
||||
encryptionStyle = EncryptionStyle.AES;
|
||||
}
|
||||
|
||||
return encryptBook(encryptionStyle, (Player) sender, arguments[0], "");
|
||||
boolean preventAdminDecryption = realEncryption && config.allowPreventAdminDecryption() &&
|
||||
sender.hasPermission(Permission.PREVENT_ADMIN_DECRYPTION.toString());
|
||||
|
||||
return encryptBook(encryptionStyle, (Player) sender, arguments[0], "", preventAdminDecryption);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +62,7 @@ public class CommandEncrypt implements TabExecutor {
|
||||
*/
|
||||
@Nullable
|
||||
protected BookMeta performPreChecks(@NotNull CommandSender sender, @NotNull String[] arguments,
|
||||
int necessaryArguments, @NotNull String missingArgumentsError) {
|
||||
int necessaryArguments, int optionalArguments, @NotNull String missingArgumentsError) {
|
||||
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
|
||||
if (!(sender instanceof Player player)) {
|
||||
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY);
|
||||
@@ -75,7 +82,7 @@ public class CommandEncrypt implements TabExecutor {
|
||||
stringFormatter.displayErrorMessage(player, missingArgumentsError);
|
||||
return null;
|
||||
}
|
||||
if (argumentCount > necessaryArguments + 1) {
|
||||
if (argumentCount > necessaryArguments + optionalArguments) {
|
||||
stringFormatter.displayErrorMessage(player, Translatable.ERROR_TOO_MANY_ARGUMENTS_COMMAND);
|
||||
return null;
|
||||
}
|
||||
@@ -96,16 +103,18 @@ public class CommandEncrypt implements TabExecutor {
|
||||
/**
|
||||
* Encrypts the given book
|
||||
*
|
||||
* @param encryptionStyle <p>The encryption style to use</p>
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param key <p>The encryption key to use</p>
|
||||
* @param group <p>The group to encrypt for</p>
|
||||
* @param encryptionStyle <p>The encryption style to use</p>
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param key <p>The encryption key to use</p>
|
||||
* @param group <p>The group to encrypt for</p>
|
||||
* @param preventAdminDecryption <p>Whether to prevent storage of a key that can be used for admin decryption</p>
|
||||
* @return <p>True if the book was encrypted successfully</p>
|
||||
*/
|
||||
protected boolean encryptBook(@NotNull EncryptionStyle encryptionStyle, @NotNull Player player, @NotNull String key,
|
||||
@NotNull String group) {
|
||||
@NotNull String group, boolean preventAdminDecryption) {
|
||||
ItemSlot heldSlot = InventoryHelper.getHeldSlotBook(player, false, false, true, true);
|
||||
ItemStack encryptedBook = EncryptionHelper.encryptBook(player, heldSlot == ItemSlot.MAIN_HAND, key, encryptionStyle, group);
|
||||
ItemStack encryptedBook = EncryptionHelper.encryptBook(player, heldSlot == ItemSlot.MAIN_HAND, key,
|
||||
encryptionStyle, group, preventAdminDecryption);
|
||||
|
||||
if (encryptedBook != null) {
|
||||
InventoryHelper.setHeldWrittenBook(player, encryptedBook);
|
||||
@@ -119,19 +128,20 @@ public class CommandEncrypt implements TabExecutor {
|
||||
@NotNull
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] arguments) {
|
||||
return doTabCompletion(arguments, false);
|
||||
return doTabCompletion(sender, arguments, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of string for tab completions
|
||||
*
|
||||
* @param args <p>The arguments given</p>
|
||||
* @param sender <p>The command sender executing this command</p>
|
||||
* @param arguments <p>The arguments given</p>
|
||||
* @param groupEncrypt <p>Whether to auto-complete for group encryption</p>
|
||||
* @return <p>The strings to auto-complete</p>
|
||||
*/
|
||||
@NotNull
|
||||
protected List<String> doTabCompletion(@NotNull String[] args, boolean groupEncrypt) {
|
||||
int argumentsCount = args.length;
|
||||
protected List<String> doTabCompletion(@NotNull CommandSender sender, @NotNull String[] arguments, boolean groupEncrypt) {
|
||||
int argumentsCount = arguments.length;
|
||||
boolean useRealEncryption = BooksWithoutBorders.getConfiguration().useRealEncryption();
|
||||
|
||||
List<String> encryptionStyles = new ArrayList<>();
|
||||
@@ -147,13 +157,17 @@ public class CommandEncrypt implements TabExecutor {
|
||||
} else if (argumentsCount == 2) {
|
||||
return List.of("<password>");
|
||||
} else if (argumentsCount == 3) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, args[2]);
|
||||
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, arguments[2]);
|
||||
}
|
||||
} else {
|
||||
BwBConfig config = BooksWithoutBorders.getConfiguration();
|
||||
if (argumentsCount == 1) {
|
||||
return List.of("<password>");
|
||||
} else if (argumentsCount == 2) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, args[1]);
|
||||
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, arguments[1]);
|
||||
} else if (argumentsCount == 3 && (config.useRealEncryption() && config.allowPreventAdminDecryption()) &&
|
||||
sender.hasPermission(Permission.PREVENT_ADMIN_DECRYPTION.toString())) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(List.of("true", "false"), arguments[2]);
|
||||
}
|
||||
}
|
||||
return List.of();
|
||||
|
@@ -27,7 +27,7 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
|
||||
return false;
|
||||
}
|
||||
|
||||
BookMeta bookMetadata = performPreChecks(sender, arguments, 2,
|
||||
BookMeta bookMetadata = performPreChecks(sender, arguments, 2, 1,
|
||||
stringFormatter.getUnFormattedColoredMessage(Translatable.ERROR_GROUP_ENCRYPT_ARGUMENTS_MISSING));
|
||||
|
||||
if (bookMetadata == null) {
|
||||
@@ -42,13 +42,13 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
|
||||
}
|
||||
|
||||
EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.SUBSTITUTION;
|
||||
return encryptBook(encryptionStyle, player, arguments[1], arguments[0]);
|
||||
return encryptBook(encryptionStyle, player, arguments[1], arguments[0], false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String alias, @NotNull String[] arguments) {
|
||||
return doTabCompletion(arguments, true);
|
||||
return doTabCompletion(sender, arguments, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ public class BwBConfig {
|
||||
private boolean changeGenerationOnCopy;
|
||||
private boolean enableBookshelfPeeking;
|
||||
private boolean useRealEncryption;
|
||||
private boolean allowPreventAdminDecryption;
|
||||
|
||||
private final Translator translator;
|
||||
private EconomyManager economyManager;
|
||||
@@ -275,6 +276,15 @@ public class BwBConfig {
|
||||
return this.useRealEncryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether to allow removing the admin decrypt ability
|
||||
*
|
||||
* @return <p>True if admin decrypt removal is allowed</p>
|
||||
*/
|
||||
public boolean allowPreventAdminDecryption() {
|
||||
return this.allowPreventAdminDecryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path used to store encrypted books
|
||||
*
|
||||
@@ -316,6 +326,7 @@ public class BwBConfig {
|
||||
config.set(ConfigOption.AUTHOR_ONLY_UNSIGN.getConfigNode(), this.authorOnlyUnsign);
|
||||
config.set(ConfigOption.AUTHOR_ONLY_SAVE.getConfigNode(), this.authorOnlySave);
|
||||
config.set(ConfigOption.CHANGE_GENERATION_ON_COPY.getConfigNode(), this.changeGenerationOnCopy);
|
||||
config.set(ConfigOption.ALLOW_PREVENT_ADMIN_DECRYPTION.getConfigNode(), this.allowPreventAdminDecryption);
|
||||
BooksWithoutBorders.getInstance().saveConfig();
|
||||
}
|
||||
|
||||
@@ -343,6 +354,7 @@ public class BwBConfig {
|
||||
this.changeGenerationOnCopy = getBoolean(config, ConfigOption.CHANGE_GENERATION_ON_COPY);
|
||||
this.enableBookshelfPeeking = getBoolean(config, ConfigOption.ENABLE_BOOKSHELF_PEEKING);
|
||||
this.useRealEncryption = getBoolean(config, ConfigOption.USE_REAL_ENCRYPTION);
|
||||
this.allowPreventAdminDecryption = getBoolean(config, ConfigOption.ALLOW_PREVENT_ADMIN_DECRYPTION);
|
||||
String language = config.getString("language", "en");
|
||||
this.translator.loadLanguages(BooksWithoutBorders.getInstance().getDataFolder(), "en", language);
|
||||
|
||||
|
@@ -81,6 +81,11 @@ public enum ConfigOption {
|
||||
* Whether to use real AES encryption instead of storing garbled book text, while the full plaintext is stored in a file
|
||||
*/
|
||||
USE_REAL_ENCRYPTION("Options.Use_Real_Encryption", false),
|
||||
|
||||
/**
|
||||
* Whether to allow disabling admin encryption for a real encrypted book
|
||||
*/
|
||||
ALLOW_PREVENT_ADMIN_DECRYPTION("Options.Allow_Prevent_Admin_Decryption", false),
|
||||
;
|
||||
|
||||
private final String configNode;
|
||||
|
@@ -50,7 +50,13 @@ public enum Permission {
|
||||
/**
|
||||
* The permission for using special signs
|
||||
*/
|
||||
SIGNS("signs");
|
||||
SIGNS("signs"),
|
||||
|
||||
/**
|
||||
* The permission for preventing a real encrypted book to be decrypted by an admin
|
||||
*/
|
||||
PREVENT_ADMIN_DECRYPTION("preventAdminDecryption"),
|
||||
;
|
||||
|
||||
private final @NotNull String node;
|
||||
|
||||
|
@@ -11,13 +11,14 @@ import java.util.List;
|
||||
/**
|
||||
* A representation of an encrypted book
|
||||
*
|
||||
* @param bookMeta <p>The book's book meta</p>
|
||||
* @param encryptionStyle <p>The book's encryption style</p>
|
||||
* @param encryptionKey <p>The book's encryption key, or null if admin decrypt is forbidden</p>
|
||||
* @param data <p>The encrypted pages of the book</p>
|
||||
* @param aesConfiguration <p>The AES configuration for the book, or null if not AES encrypted</p>
|
||||
* @param bookMeta <p>The book's book meta</p>
|
||||
* @param encryptionStyle <p>The book's encryption style</p>
|
||||
* @param encryptionKey <p>The book's encryption key, or null if admin decrypt is forbidden</p>
|
||||
* @param data <p>The encrypted pages of the book</p>
|
||||
* @param aesConfiguration <p>The AES configuration for the book, or null if not AES encrypted</p>
|
||||
* @param preventAdminDecrypt <p>Whether this book should not support admin decryption</p>
|
||||
*/
|
||||
public record EncryptedBook(@NotNull BookMeta bookMeta, @NotNull EncryptionStyle encryptionStyle,
|
||||
@NotNull String encryptionKey, @NotNull List<String> data,
|
||||
@Nullable AESConfiguration aesConfiguration) {
|
||||
@Nullable AESConfiguration aesConfiguration, boolean preventAdminDecrypt) {
|
||||
}
|
||||
|
@@ -304,7 +304,7 @@ public class SignEventListener implements Listener {
|
||||
if (heldItemType == Material.WRITTEN_BOOK) {
|
||||
player.closeInventory();
|
||||
eBook = EncryptionHelper.encryptBook(player, mainHand, BookFormatter.stripColor(lines[2]),
|
||||
EncryptionStyle.getFromString(BookFormatter.stripColor(lines[3])));
|
||||
EncryptionStyle.getFromString(BookFormatter.stripColor(lines[3])), false);
|
||||
if (eBook != null) {
|
||||
player.getInventory().setItem(hand, eBook);
|
||||
}
|
||||
|
@@ -76,7 +76,9 @@ public final class BookToFromTextHelper {
|
||||
FileConfiguration bookYml = getBookConfiguration(encryptedBook.bookMeta());
|
||||
|
||||
bookYml.set("Encryption.Style", encryptedBook.encryptionStyle().toString());
|
||||
bookYml.set("Encryption.Key", encryptedBook.encryptionKey());
|
||||
if (!encryptedBook.preventAdminDecrypt()) {
|
||||
bookYml.set("Encryption.Key", encryptedBook.encryptionKey());
|
||||
}
|
||||
if (encryptedBook.encryptionStyle() == EncryptionStyle.AES) {
|
||||
if (encryptedBook.aesConfiguration() == null) {
|
||||
throw new IOException("Attempted to save AES encrypted book without supplying a configuration!");
|
||||
@@ -155,7 +157,8 @@ public final class BookToFromTextHelper {
|
||||
}
|
||||
|
||||
// If the plaintext is stored in the file, don't bother with real decryption
|
||||
EncryptedBook encryptedBook = new EncryptedBook(meta, encryptionStyle, userKey, data, aesConfiguration);
|
||||
EncryptedBook encryptedBook = new EncryptedBook(meta, encryptionStyle, userKey, data, aesConfiguration,
|
||||
realKey.isBlank());
|
||||
if (!meta.getPages().isEmpty()) {
|
||||
return encryptedBook;
|
||||
}
|
||||
|
@@ -127,31 +127,34 @@ public final class EncryptionHelper {
|
||||
/**
|
||||
* Encrypts a book
|
||||
*
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param mainHand <p>Whether the player is holding the book in its main hand</p>
|
||||
* @param key <p>The key/password to use for encryption</p>
|
||||
* @param style <p>The encryption style to use</p>
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param mainHand <p>Whether the player is holding the book in its main hand</p>
|
||||
* @param key <p>The key/password to use for encryption</p>
|
||||
* @param style <p>The encryption style to use</p>
|
||||
* @param preventAdminDecrypt <p>Whether to prevent storage of a key that can be used for admin decryption</p>
|
||||
* @return <p>An encrypted version of the book</p>
|
||||
*/
|
||||
@Nullable
|
||||
public static ItemStack encryptBook(@NotNull Player player, boolean mainHand, @NotNull String key,
|
||||
@NotNull EncryptionStyle style) {
|
||||
return encryptBook(player, mainHand, key, style, "");
|
||||
@NotNull EncryptionStyle style, boolean preventAdminDecrypt) {
|
||||
return encryptBook(player, mainHand, key, style, "", preventAdminDecrypt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a book
|
||||
*
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param mainHand <p>Whether the player is holding the book in its main hand</p>
|
||||
* @param key <p>The key/password to use for encryption</p>
|
||||
* @param style <p>The encryption style to use</p>
|
||||
* @param groupName <p>The name of the group to encrypt for, or "" otherwise</p>
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param mainHand <p>Whether the player is holding the book in its main hand</p>
|
||||
* @param key <p>The key/password to use for encryption</p>
|
||||
* @param style <p>The encryption style to use</p>
|
||||
* @param groupName <p>The name of the group to encrypt for, or "" otherwise</p>
|
||||
* @param preventAdminDecrypt <p>Whether to prevent storage of a key that can be used for admin decryption</p>
|
||||
* @return <p>An encrypted version of the book</p>
|
||||
*/
|
||||
@Nullable
|
||||
public static ItemStack encryptBook(Player player, boolean mainHand, @NotNull String key,
|
||||
@NotNull EncryptionStyle style, @NotNull String groupName) {
|
||||
@NotNull EncryptionStyle style, @NotNull String groupName,
|
||||
boolean preventAdminDecrypt) {
|
||||
BookMeta book = InventoryHelper.getHeldBookMetadata(player, mainHand);
|
||||
if (book == null) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, "Unable to get metadata from the held book!");
|
||||
@@ -167,7 +170,8 @@ public final class EncryptionHelper {
|
||||
AESConfiguration configuration = AESConfiguration.getNewConfiguration(hashedKey);
|
||||
|
||||
//Save the book's un-encrypted contents to a file
|
||||
BookMeta newMetadata = saveBookPlaintext(groupName, player, book, style, hashedKey, configuration);
|
||||
BookMeta newMetadata = saveEncryptedBook(groupName, player,
|
||||
new EncryptedBook(book, style, hashedKey, new ArrayList<>(), configuration, preventAdminDecrypt));
|
||||
if (newMetadata == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -216,26 +220,22 @@ public final class EncryptionHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a book's plain text to a file
|
||||
* Saves an encrypted book to a file
|
||||
*
|
||||
* @param groupName <p>The group who's allowed to decrypt the book, or ""</p>
|
||||
* @param player <p>The player trying to encrypt the book</p>
|
||||
* @param book <p>The book to encrypt</p>
|
||||
* @param encryptionStyle <p>The encryption style used for the book</p>
|
||||
* @param key <p>The key used to encrypt the book</p>
|
||||
* @param aesConfiguration <p>The AES configuration to use, if encrypting using AES</p>
|
||||
* @param groupName <p>The group who's allowed to decrypt the book, or ""</p>
|
||||
* @param player <p>The player trying to encrypt the book</p>
|
||||
* @param encryptedBook <p>The book to encrypt</p>
|
||||
* @return <p>The new metadata for the book, or null if it could not be saved</p>
|
||||
*/
|
||||
@Nullable
|
||||
private static BookMeta saveBookPlaintext(@NotNull String groupName, @NotNull Player player,
|
||||
@NotNull BookMeta book, @NotNull EncryptionStyle encryptionStyle,
|
||||
@NotNull String key, @NotNull AESConfiguration aesConfiguration) {
|
||||
BookMeta newMetadata = book;
|
||||
private static BookMeta saveEncryptedBook(@NotNull String groupName, @NotNull Player player,
|
||||
@NotNull EncryptedBook encryptedBook) {
|
||||
BookMeta newMetadata = encryptedBook.bookMeta();
|
||||
boolean wasSaved;
|
||||
if (groupName.trim().isEmpty()) {
|
||||
wasSaved = saveEncryptedBook(player, book, encryptionStyle, key, aesConfiguration);
|
||||
wasSaved = saveEncryptedBook(player, encryptedBook);
|
||||
} else {
|
||||
newMetadata = saveEncryptedBookForGroup(player, book, groupName);
|
||||
newMetadata = saveEncryptedBookForGroup(player, encryptedBook.bookMeta(), groupName);
|
||||
wasSaved = newMetadata != null;
|
||||
}
|
||||
if (wasSaved) {
|
||||
@@ -327,7 +327,6 @@ public final class EncryptionHelper {
|
||||
File file = new File(path + fileName + ".yml");
|
||||
if (!file.isFile()) {
|
||||
file = new File(path + fileName + ".txt");
|
||||
|
||||
if (!file.isFile()) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, "Incorrect decryption key!");
|
||||
return null;
|
||||
@@ -476,20 +475,15 @@ public final class EncryptionHelper {
|
||||
/**
|
||||
* Saves an encrypted book to be decryptable for the given user
|
||||
*
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param bookMetaData <p>Metadata for the book to encrypt</p>
|
||||
* @param encryptionStyle <p>The style of encryption used</p>
|
||||
* @param key <p>The key to use for encryption</p>
|
||||
* @param aesConfiguration <p>The AES configuration to use if encrypting with AES</p>
|
||||
* @param player <p>The player encrypting the book</p>
|
||||
* @param encryptedBook <p>The book to save</p>
|
||||
* @return <p>The new encrypted metadata for the book, or null if encryption failed</p>
|
||||
*/
|
||||
@NotNull
|
||||
private static Boolean saveEncryptedBook(@NotNull Player player, @NotNull BookMeta bookMetaData,
|
||||
@NotNull EncryptionStyle encryptionStyle, @NotNull String key,
|
||||
@Nullable AESConfiguration aesConfiguration) {
|
||||
private static Boolean saveEncryptedBook(@NotNull Player player, @NotNull EncryptedBook encryptedBook) {
|
||||
String path = BooksWithoutBorders.getConfiguration().getEncryptedBookPath();
|
||||
|
||||
String fileName = BookHelper.getBookFile(bookMetaData, player, true);
|
||||
String fileName = BookHelper.getBookFile(encryptedBook.bookMeta(), player, true);
|
||||
fileName = cleanString(fileName);
|
||||
|
||||
//cancels saving if file is already encrypted
|
||||
@@ -500,8 +494,7 @@ public final class EncryptionHelper {
|
||||
}
|
||||
|
||||
try {
|
||||
BookToFromTextHelper.encryptedBookToYml(path, fileName,
|
||||
new EncryptedBook(bookMetaData, encryptionStyle, key, new ArrayList<>(), aesConfiguration));
|
||||
BookToFromTextHelper.encryptedBookToYml(path, fileName, encryptedBook);
|
||||
} catch (IOException exception) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, "Encryption failed!");
|
||||
return false;
|
||||
|
@@ -39,3 +39,7 @@ Options:
|
||||
# Note that real encryption might alter, corrupt or lose a book's contents, so don't use real encryption with books
|
||||
# that have no backup in in-game book form or saved book form.
|
||||
Use_Real_Encryption: false
|
||||
# Whether to allow players to specifically disable admin decryption for a real encrypted book. This is only available
|
||||
# when real encryption is enabled. It allows a player to prevent the storage of the encryption key in the plugin
|
||||
# folder, meaning that the only way to decrypt the book is to provide the correct key. THIS IS A DANGEROUS OPTION!
|
||||
Allow_Prevent_Admin_Decryption: false
|
@@ -102,9 +102,11 @@ commands:
|
||||
Encrypts the book the player is holding. "key" is required and can be any phrase or number excluding spaces.
|
||||
"style" is not required. Possible values are "dna", "substitution", "aes", "onetimepad" and "magic".
|
||||
If real encryption is enabled, possible methods are restricted.
|
||||
If real encryption and prevent admin decryption are enabled, the third argument prevents the key from being
|
||||
stored in the server files, preventing admin decryption. If the password is lost, decryption is impossible.
|
||||
aliases:
|
||||
- bwbencrypt
|
||||
usage: /<command> <key> [encryption style]
|
||||
usage: /<command> <key> [encryption style] [prevent admin decrypt]
|
||||
permission: bookswithoutborders.encrypt
|
||||
setbookgeneration:
|
||||
description: Sets the generation of your held book
|
||||
@@ -265,6 +267,7 @@ permissions:
|
||||
bookswithoutborders.reload: true
|
||||
bookswithoutborders.setgeneration: true
|
||||
bookswithoutborders.editbookshelf: true
|
||||
bookswithoutborders.preventadmindecryption: true
|
||||
bookswithoutborders.use:
|
||||
description: Allows player to use commands to save/load/delete in their personal directory, and peeking at bookshelves if enabled
|
||||
children:
|
||||
@@ -342,3 +345,5 @@ permissions:
|
||||
description: Allows player to add a blank title page to a book
|
||||
bookswithoutborders.deletepage:
|
||||
description: Allows player to delete a page from a book
|
||||
bookswithoutborders.preventadmindecryption:
|
||||
description: If use real encryption and prevent admin decryption options are enabled, allows player to disable admin decryption for a book
|
Reference in New Issue
Block a user