diff --git a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java index 5809768..7a214d8 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java @@ -14,6 +14,8 @@ import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import net.knarcraft.bookswithoutborders.utility.EncryptionHelper; +import net.knarcraft.bookswithoutborders.utility.FileHelper; import net.milkbowl.vault.economy.Economy; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -286,7 +288,7 @@ public class BooksWithoutBorders extends JavaPlugin { sender.sendMessage(ChatColor.YELLOW + "Use: /bwb [Command]"); sender.sendMessage(ChatColor.YELLOW + "[] denote parameters"); - if (BooksHavePrice()) { + if (booksHavePrice()) { if (bookPriceType != Material.AIR) sender.sendMessage(ChatColor.RED + "[" + (int) bookPriceQuantity + " " + bookPriceType.toString() + "(s) are required to create a book]"); else @@ -401,8 +403,7 @@ public class BooksWithoutBorders extends JavaPlugin { } //Player only commands - if (sender instanceof Player) { - Player player = (Player) sender; + if (sender instanceof Player player) { if (args[0].equalsIgnoreCase("savePublic")) { if (!sender.hasPermission("bookswithoutborders.savepublic")) { @@ -432,11 +433,10 @@ public class BooksWithoutBorders extends JavaPlugin { if (((Player) sender).getItemInHand().getType() == Material.WRITTEN_BOOK || ((Player) sender).getItemInHand().getType() == Material.WRITABLE_BOOK) { if (args.length == 2) { saveBook((Player) sender, args[1], false); - return true; } else { saveBook((Player) sender, "false", false); - return true; } + return true; } else { sender.sendMessage(ChatColor.RED + "You must be holding a written book or book and quill to save it!"); return false; @@ -682,7 +682,7 @@ public class BooksWithoutBorders extends JavaPlugin { return false; } - if (BooksHavePrice() && + if (booksHavePrice() && !sender.hasPermission("bookswithoutborders.bypassbookprice") && cannotPayForBookPrinting((Player) sender, Integer.parseInt(args[1]))) { return false; @@ -731,9 +731,9 @@ public class BooksWithoutBorders extends JavaPlugin { ItemStack eBook; if (args.length == 3) { - eBook = bookEncryption((Player) sender, args[1], args[2], ""); + eBook = encryptBook((Player) sender, true, args[1], args[2], ""); } else { - eBook = bookEncryption((Player) sender, args[1], "", ""); + eBook = encryptBook((Player) sender, true, args[1], "", ""); } if (eBook != null) { @@ -777,9 +777,9 @@ public class BooksWithoutBorders extends JavaPlugin { ItemStack eBook; if (args.length == 4) { - eBook = bookEncryption((Player) sender, args[2], args[3], args[1]); + eBook = encryptBook((Player) sender, true, args[2], args[3], args[1]); } else { - eBook = bookEncryption((Player) sender, args[2], "", args[1]); + eBook = encryptBook((Player) sender, true, args[2], "", args[1]); } if (eBook != null) { @@ -828,11 +828,9 @@ public class BooksWithoutBorders extends JavaPlugin { } } - StringBuilder key = new StringBuilder();//converts user supplied key into integer form - for (int x = 0; x < args[1].length(); x++) - key.append(Character.getNumericValue(Character.codePointAt(args[1], x))); + String key = EncryptionHelper.getNumberKeyFromStringKey(args[1]); - ItemStack book = eLoad(((Player) sender), key.toString(), true); + ItemStack book = eLoad(((Player) sender), key, true); if (book != null) { ((Player) sender).setItemInHand(book); sender.sendMessage(ChatColor.GREEN + "Book decrypted!"); @@ -1434,7 +1432,7 @@ public class BooksWithoutBorders extends JavaPlugin { book.setItemMeta(bDat); book.setAmount(numCopies); - if (BooksHavePrice() && !sender.hasPermission("bookswithoutborders.bypassbookprice") && + if (booksHavePrice() && !sender.hasPermission("bookswithoutborders.bypassbookprice") && (dir.equalsIgnoreCase("public") || dir.equalsIgnoreCase("player") || dir.equalsIgnoreCase("")) && cannotPayForBookPrinting((Player) sender, numCopies)) { @@ -1648,13 +1646,15 @@ public class BooksWithoutBorders extends JavaPlugin { return rawPages; } - protected ItemStack bookEncryption(Player player, String key, String style, String groupName) { - StringBuilder ikey = new StringBuilder();//converts user supplied key into integer form - for (int x = 0; x < key.length(); x++) { - ikey.append(Character.getNumericValue(Character.codePointAt(key, x))); - } + protected ItemStack encryptBook(Player player, boolean mainHand, String key, String style) { + return encryptBook(player, mainHand, key, style, ""); + } - BookMeta book = (BookMeta) player.getItemInHand().getItemMeta(); + protected ItemStack encryptBook(Player player, boolean mainHand, String key, String style, String groupName) { + //converts user supplied key into integer form + String integerKey = EncryptionHelper.getNumberKeyFromStringKey(key); + + BookMeta book = getHeldBookMetadata(player, mainHand); if (!book.hasPages()) { player.sendMessage(ChatColor.RED + "Book is empty!"); @@ -1662,121 +1662,129 @@ public class BooksWithoutBorders extends JavaPlugin { } BookMeta nuMeta = null; - boolean wasSaved = (groupName.equalsIgnoreCase("")) ? eSave(player, book, ikey.toString()) : (nuMeta = groupESave(player, book, ikey.toString(), groupName)) != null; + boolean wasSaved = (groupName.equalsIgnoreCase("")) ? eSave(player, book, integerKey) : (nuMeta = groupESave(player, book, integerKey, groupName)) != null; if (wasSaved) { - ItemStack ecbook; - List ecPages = new ArrayList<>(); + ItemStack encryptedBook; + List encryptedPages = new ArrayList<>(); List nuPages; if (style.equalsIgnoreCase("dna")) { - GenenCrypt gc = new GenenCrypt(ikey.substring(0, (ikey.length())));//Length used to be divided by /4 + GenenCrypt gc = new GenenCrypt(integerKey.substring(0, (integerKey.length())));//Length used to be divided by /4 for (int x = 0; x < book.getPages().size(); x++) { - ecPages.add(gc.encrypt(book.getPage(x + 1))); + encryptedPages.add(gc.encrypt(book.getPage(x + 1))); } } else if (style.equalsIgnoreCase("magic")) { for (int i = 0; i < book.getPages().size(); i++) { String page = book.getPage(i + 1); page = "ァk" + page.replace("ァ", ""); - ecPages.add(page); + encryptedPages.add(page); } } else { SubstitutionCipher sc = new SubstitutionCipher(); for (int x = 0; x < book.getPages().size(); x++) { - ecPages.add(sc.encrypt(book.getPage(x + 1), ikey.toString())); + encryptedPages.add(sc.encrypt(book.getPage(x + 1), integerKey)); } } - ecPages = pageFormat(ecPages); - nuPages = cleanList(ecPages); + encryptedPages = pageFormat(encryptedPages); + nuPages = cleanList(encryptedPages); player.sendMessage(ChatColor.GREEN + "Book encrypted!"); - ecbook = new ItemStack(Material.WRITTEN_BOOK); + encryptedBook = new ItemStack(Material.WRITTEN_BOOK); book.setPages(nuPages); - ecbook.setItemMeta(book); - ecbook.setAmount(player.getItemInHand().getAmount()); + encryptedBook.setItemMeta(book); + encryptedBook.setAmount(player.getItemInHand().getAmount()); if (nuMeta != null) - ecbook.setItemMeta(nuMeta); + encryptedBook.setItemMeta(nuMeta); - return ecbook; + return encryptedBook; } return null; } - protected void deleteBook(CommandSender sender, String fname, Boolean ispub) { - //checks if player is using list number to load - for (int x = 0; x < fname.length(); x++) { - if (!Character.isDigit(fname.charAt(x))) { - break; - } - if (x == fname.length() - 1 && Character.isDigit(fname.charAt(x)) && loadList.containsKey(sender.getName())) { - if (Integer.parseInt(fname) <= loadList.get(sender.getName()).size()) { - fname = loadList.get(sender.getName()).get(Integer.parseInt(fname) - 1); - } - } - } - - File file; - //TODO Convert namecheck into a method maybe - NameCheck: - { - //Extension is already present - if (fname.lastIndexOf(".") != -1) { - if (fname.substring(fname.lastIndexOf(".")).equals(".yml") || fname.substring(fname.lastIndexOf(".")).equals(".txt")) { - file = (ispub) ? new File(bookFolder + fname) : - new File(bookFolder + cleanString(sender.getName()) + SLASH + fname); - - if (!file.isFile()) { - sender.sendMessage(ChatColor.RED + "Incorrect file name!"); - return; - } - break NameCheck; - } - } - - //No extension present - file = (ispub) ? new File(bookFolder + fname + ".yml") : - new File(bookFolder + cleanString(sender.getName()) + SLASH + fname + ".yml"); - - if (!file.isFile()) { - file = (ispub) ? new File(bookFolder + fname + ".txt") : - new File(bookFolder + cleanString(sender.getName()) + SLASH + fname + ".txt"); - - if (!file.isFile()) { - sender.sendMessage(ChatColor.RED + "Incorrect file name!"); - return; - } - } - } - + /** + * Deletes the given book + * + * @param sender

The sender of the command to delete the book

+ * @param fileName

The file name of the book

+ * @param isPublic

Whether the book to delete is public or not

+ */ + protected void deleteBook(CommandSender sender, String fileName, Boolean isPublic) { + //If the file name is an index of the load list, load the book try { - file.delete(); - } catch (Exception e) { - sender.sendMessage(ChatColor.RED + "Deletion failed!"); + int loadListIndex = Integer.parseInt(fileName); + String senderName = sender.getName(); + if (loadList.containsKey(senderName) && loadListIndex <= loadList.get(senderName).size()) { + fileName = loadList.get(senderName).get(loadListIndex - 1); + } + } catch (NumberFormatException ignored) { + } + + //Get the file to be deleted + File file; + if (isPublic) { + file = FileHelper.getBookFile(bookFolder + fileName); + } else { + file = FileHelper.getBookFile(bookFolder + cleanString(sender.getName()) + SLASH + fileName); + } + + //Send message if no such file could be found + if (file == null) { + sender.sendMessage(ChatColor.RED + "Incorrect file name!"); return; } - sender.sendMessage(ChatColor.GREEN + "\"" + fname + "\" deleted successfully"); + //Try to delete the file + try { + if (file.delete()) { + sender.sendMessage(ChatColor.GREEN + "\"" + fileName + "\" deleted successfully"); + } else { + sender.sendMessage(ChatColor.RED + "Deletion failed without an exception!"); + } + } catch (Exception e) { + sender.sendMessage(ChatColor.RED + "Deletion failed!"); + } } /** * Unsigns the player's currently held book - * @param player

The player holding the book

+ * + * @param player

The player holding the book

* @param mainHand

Whether the player is holding the book in its main hand or its off hand

*/ protected void unSignHeldBook(Player player, boolean mainHand) { //Get the old book - BookMeta oldBook; - if (mainHand) { - oldBook = (BookMeta) player.getInventory().getItemInMainHand().getItemMeta(); - } else { - oldBook = (BookMeta) player.getInventory().getItemInOffHand().getItemMeta(); - } + BookMeta oldBook = getHeldBookMetadata(player, mainHand); //UnSign the book ItemStack newBook = new ItemStack(Material.WRITABLE_BOOK); newBook.setItemMeta(oldBook); + replaceHeldBook(player, newBook, mainHand); + } + + /** + * Gets metadata about the player's held book + * @param player

The player holding the book

+ * @param mainHand

Whether to get information about a book in the player's main hand or off hand

+ * @return

Information about the held book

+ */ + private BookMeta getHeldBookMetadata(Player player, boolean mainHand) { + if (mainHand) { + return (BookMeta) player.getInventory().getItemInMainHand().getItemMeta(); + } else { + return (BookMeta) player.getInventory().getItemInOffHand().getItemMeta(); + } + } + + /** + * Replaces the player's held item + * @param player

The player to replace the item for

+ * @param newBook

The new book the player should hold

+ * @param mainHand

Whether to replace the item in the player's main hand or off hand

+ */ + private void replaceHeldBook(Player player, ItemStack newBook, boolean mainHand) { if (mainHand) { player.getInventory().setItemInMainHand(newBook); } else { @@ -1784,13 +1792,19 @@ public class BooksWithoutBorders extends JavaPlugin { } } - protected boolean BooksHavePrice() { + /** + * Checks whether books have a price for printing them + * + * @return

True if players need to pay for printing books

+ */ + protected boolean booksHavePrice() { return (bookPriceType != null && bookPriceQuantity > 0); } /** * Makes the player pay for printing a given number of books - * @param player

The player printing the books

+ * + * @param player

The player printing the books

* @param numCopies

The number of copies the player is trying to print

* @return

True if the player cannot pay for the printing of the books

*/ @@ -1816,7 +1830,8 @@ public class BooksWithoutBorders extends JavaPlugin { /** * Takes payment for printing a number of books by withdrawing the correct item - * @param player

The player which needs to pay

+ * + * @param player

The player which needs to pay

* @param itemCost

The number of items to pay

*/ private void payForBookPrintingItem(Player player, int itemCost) { @@ -1839,8 +1854,9 @@ public class BooksWithoutBorders extends JavaPlugin { /** * Uses economy to take payment for printing a number of books - * @param player

The player which needs to pay

- * @param cost

The cost of the book printing

+ * + * @param player

The player which needs to pay

+ * @param cost

The cost of the book printing

* @param numCopies

The number of books the player is printing

* @return

True if the player had the money and it has been withdrawn

*/ @@ -1859,8 +1875,9 @@ public class BooksWithoutBorders extends JavaPlugin { /** * Checks whether the given player is the author of a given book + * * @param player

The player to check

- * @param book

The book to check

+ * @param book

The book to check

* @return

True if the player is the book's author

*/ protected boolean isAuthor(Player player, BookMeta book) { diff --git a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBordersListener.java b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBordersListener.java index d022d5d..1dc2dc2 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBordersListener.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBordersListener.java @@ -4,6 +4,8 @@ import java.io.File; import java.util.List; import java.util.Objects; +import net.knarcraft.bookswithoutborders.utility.EncryptionHelper; +import net.knarcraft.bookswithoutborders.utility.FileHelper; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Tag; @@ -226,7 +228,7 @@ public class BooksWithoutBordersListener implements Listener { //Tests if a full file name has been supplied and points to an actual file String signFile = bookFolder + lines[2] + lines[3]; - if (bookFileExists(signFile)) { + if (FileHelper.bookFileExists(signFile)) { markGiveSignValidity(event, true); } else { if (isBookListIndex(lines[2])) { @@ -258,17 +260,6 @@ public class BooksWithoutBordersListener implements Listener { return false; } - /** - * Checks if a file path points to an actual book - * @param bookFile

The path to a book

- * @return

True if the file exists and points to a book file

- */ - private boolean bookFileExists(String bookFile) { - return ((new File(bookFile).isFile() && (bookFile.toLowerCase().endsWith(".txt") || - bookFile.toLowerCase().endsWith(".yml"))) || new File(bookFile + ".txt").isFile() || - new File(bookFile + ".yml").isFile()) && !bookFile.contains("../") && !bookFile.contains("..\\"); - } - /** * Marks a give sign as valid or invalid * @param event

The event causing the creation of the give sign

@@ -390,9 +381,10 @@ public class BooksWithoutBordersListener implements Listener { private void encryptHeldBookUsingSign(Sign sign, Material heldItemType, Player player, EquipmentSlot hand) { ItemStack eBook; String[] lines = sign.getLines(); + boolean mainHand = hand == EquipmentSlot.HAND; if (heldItemType == Material.WRITTEN_BOOK) { player.closeInventory(); - eBook = BooksWithoutBorders.bwb.bookEncryption(player, lines[2].substring(2), lines[3].substring(2), ""); + eBook = BooksWithoutBorders.bwb.encryptBook(player, mainHand, lines[2].substring(2), lines[3].substring(2)); if (eBook != null) { player.getInventory().setItem(hand, eBook); } @@ -445,13 +437,10 @@ public class BooksWithoutBordersListener implements Listener { player.closeInventory(); //Converts user supplied key into integer form - StringBuilder key = new StringBuilder(); String lineText = ChatColor.stripColor(sign.getLine(2)); - for (int x = 0; x < lineText.length(); x++) { - key.append(Character.getNumericValue(Character.codePointAt(lineText, x))); - } + String key = EncryptionHelper.getNumberKeyFromStringKey(lineText); - ItemStack book = BooksWithoutBorders.bwb.eLoad(player, key.toString(), false); + ItemStack book = BooksWithoutBorders.bwb.eLoad(player, key, false); if (book != null) { player.getInventory().setItem(hand, book); player.sendMessage(ChatColor.GREEN + "Book decrypted!"); diff --git a/src/main/java/net/knarcraft/bookswithoutborders/GenenCrypt.java b/src/main/java/net/knarcraft/bookswithoutborders/GenenCrypt.java index bd22a85..0a14a6f 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/GenenCrypt.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/GenenCrypt.java @@ -4,167 +4,178 @@ import java.util.Random; import java.util.ArrayList; import java.util.HashMap; +/** + * Case-insensitive gene-based encryption + * + *

Not sure where this was gotten from, but it does exist at + * Stack Exchange.

+ */ public class GenenCrypt { - private final Random ranGen; - private final String[] bases; - private final ArrayList originalCodonList; - private final ArrayList shuffledCodonList; - private final String[] charList; - private final HashMap codonTable; - private final HashMap decryptTable; - private final String key; - - public GenenCrypt(String key){ - - // define the initial, unshuffled codon list of 4 base codons - originalCodonList = new ArrayList<>(); - bases = new String[]{"A", "T", "G", "C"}; - for(int i = 0; i < 4; i++){ - for(int j = 0; j < 4; j++){ - for(int k = 0; k < 4; k++){ - for(int l = 0; l < 4; l++){ - originalCodonList.add("" + bases[i] + bases[j] + bases[k] + bases[l]); - } - } - } - } - - // make a random number generator with a seed based on the key - this.key = key; - long longKey = 0; - for(int i = 0; i < key.length(); i++){ - longKey += (int)key.charAt(i); - } - ranGen = new java.util.Random(longKey); - - // use the random number generator and the originalCodonList to make a shuffled list - shuffledCodonList = new ArrayList<>(); - while(originalCodonList.size() > 0){ - int index = ranGen.nextInt(originalCodonList.size()); - shuffledCodonList.add(originalCodonList.get(index)); - originalCodonList.remove(index); - } - - // define the characters that can be encoded, 64 in total - // 26 capital letters - // 10 digits - // space, newline, and tab - // the symbols . , ? " ! @ # $ % ^ & * ( ) - + = / _ \ : ; < > - charList = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", "\t", "\n", ".", ",", "?", "\"", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "+", "=", "/", "_", "\\", ":", ";", "<", ">", "|"}; - - // define the codon table to encode text - codonTable = new HashMap<>(); - for(int i = 0; i < charList.length; i++){ - String[] tempArray = new String[]{shuffledCodonList.get(4 * i), shuffledCodonList.get(4 * i + 1), shuffledCodonList.get(4 * i + 2), shuffledCodonList.get(4 * i + 3)}; - //System.out.println(i); - codonTable.put(charList[i], tempArray); - } - - // define the decryption table - decryptTable = new HashMap<>(); - for(int i = 0; i < codonTable.size(); i++){ - String s = charList[i]; - String[] sa = codonTable.get(s); - decryptTable.put(sa[0], s); - decryptTable.put(sa[1], s); - decryptTable.put(sa[2], s); - decryptTable.put(sa[3], s); - } - - - } - - public void printShuffledList(){ - for (String s : shuffledCodonList) { - System.out.println(s); - } - } - public void printOriginalList(){ - for (String s : originalCodonList) { - System.out.println(s); - } - } - public void printCodonTable(){ - // print the codon table - for(int i = 0; i < codonTable.size(); i++){ - String s = charList[i]; - String[] sa = codonTable.get(s); - switch (s) { - case "\t": - System.out.println(i + "\t" + "\\t" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); - break; - case "\n": - System.out.println(i + "\t" + "\\n" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); - break; - case " ": - System.out.println(i + "\t" + "\" \"" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); - break; - default: - System.out.println(i + "\t" + s + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); - break; - } - } - } - - public String encrypt(String input){ - StringBuilder output = new StringBuilder(); - for(int i = 0; i < input.length(); i++){ - // insert junk bases - int offset = key.charAt(i % key.length()); - StringBuilder junk = new StringBuilder(); - for(int j = 0; j < offset; j++){ - junk.append(bases[ranGen.nextInt(4)]); - } - output.append(junk); - int choose = ranGen.nextInt(4); - String s = ("" + input.charAt(i)).toUpperCase(); - if(codonTable.containsKey(s)){ - String[] sa = codonTable.get(s); - output.append(sa[choose]); - } - } - // add some junk bases to the end of the cipher text - int offset = key.charAt(input.length() % key.length()); - StringBuilder junk = new StringBuilder(); - for(int j = 0; j < offset; j++){ - junk.append(bases[ranGen.nextInt(4)]); - } - output.append(junk); - return output.toString(); - } - - public String decrypt(String in){ - String input = "" + in; - StringBuilder output = new StringBuilder(); - int keyCount = 0; - int junk = key.charAt(keyCount % key.length()); - while(input.length() > junk){ - // cuts out the junk bases - input = input.substring(junk); - // get the codon, decrypt the codon, remove it from the input string - String codon = input.substring(0, 4); - output.append(decryptTable.get(codon)); - input = input.substring(4); - // increment the key counter and update junk - keyCount++; - junk = key.charAt(keyCount % key.length()); - } - return output.toString(); - } - - /*public static void main(String[] args){ - GenenCrypt gc = new GenenCrypt("Another Key"); - gc.printCodonTable(); - System.out.println(); - System.out.println(); - System.out.println(); - System.out.println("Encrypting the line \"Hello World!\""); - String encrypted = gc.encrypt("Hello World!"); - System.out.println(encrypted); - System.out.println(); - System.out.println("Decrypting the ciphertext"); - System.out.println(gc.decrypt(encrypted)); - - }*/ + private final Random ranGen; + private final String[] bases; + private final ArrayList originalCodonList; + private final ArrayList shuffledCodonList; + private final String[] charList; + private final HashMap codonTable; + private final HashMap decryptTable; + private final String key; + + /** + * Instantiates a new GenenCrypt + * @param key

The key used to generate the codon table

+ */ + public GenenCrypt(String key) { + + // define the initial, unshuffled codon list of 4 base codons + originalCodonList = new ArrayList<>(); + bases = new String[]{"A", "T", "G", "C"}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 4; k++) { + for (int l = 0; l < 4; l++) { + originalCodonList.add("" + bases[i] + bases[j] + bases[k] + bases[l]); + } + } + } + } + + // make a random number generator with a seed based on the key + this.key = key; + long longKey = 0; + for (int i = 0; i < key.length(); i++) { + longKey += (int) key.charAt(i); + } + ranGen = new java.util.Random(longKey); + + // use the random number generator and the originalCodonList to make a shuffled list + shuffledCodonList = new ArrayList<>(); + while (originalCodonList.size() > 0) { + int index = ranGen.nextInt(originalCodonList.size()); + shuffledCodonList.add(originalCodonList.get(index)); + originalCodonList.remove(index); + } + + // define the characters that can be encoded, 64 in total + // 26 capital letters + // 10 digits + // space, newline, and tab + // the symbols . , ? " ! @ # $ % ^ & * ( ) - + = / _ \ : ; < > + charList = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", + "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", + "\t", "\n", ".", ",", "?", "\"", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "+", "=", "/", + "_", "\\", ":", ";", "<", ">", "|"}; + + // define the codon table to encode text + codonTable = new HashMap<>(); + for (int i = 0; i < charList.length; i++) { + String[] tempArray = new String[]{shuffledCodonList.get(4 * i), shuffledCodonList.get(4 * i + 1), + shuffledCodonList.get(4 * i + 2), shuffledCodonList.get(4 * i + 3)}; + //System.out.println(i); + codonTable.put(charList[i], tempArray); + } + + // define the decryption table + decryptTable = new HashMap<>(); + for (int i = 0; i < codonTable.size(); i++) { + String s = charList[i]; + String[] sa = codonTable.get(s); + decryptTable.put(sa[0], s); + decryptTable.put(sa[1], s); + decryptTable.put(sa[2], s); + decryptTable.put(sa[3], s); + } + + + } + + /** + * Prints the shuffled codon list used for generating the codon table + */ + public void printShuffledList() { + for (String s : shuffledCodonList) { + System.out.println(s); + } + } + + /** + * Prints the original codon list before it was shuffled + */ + public void printOriginalList() { + for (String s : originalCodonList) { + System.out.println(s); + } + } + + /** + * Prints the codon table used for encryption and decryption + */ + public void printCodonTable() { + // print the codon table + for (int i = 0; i < codonTable.size(); i++) { + String s = charList[i]; + String[] sa = codonTable.get(s); + switch (s) { + case "\t" -> System.out.println(i + "\t" + "\\t" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); + case "\n" -> System.out.println(i + "\t" + "\\n" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); + case " " -> System.out.println(i + "\t" + "\" \"" + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); + default -> System.out.println(i + "\t" + s + "\t" + sa[0] + ", " + sa[1] + ", " + sa[2] + ", " + sa[3]); + } + } + } + + /** + * Encrypts some input + * @param input

The input to encrypt

+ * @return

The encrypted input

+ */ + public String encrypt(String input) { + StringBuilder output = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + // insert junk bases + int offset = key.charAt(i % key.length()); + StringBuilder junk = new StringBuilder(); + for (int j = 0; j < offset; j++) { + junk.append(bases[ranGen.nextInt(4)]); + } + output.append(junk); + int choose = ranGen.nextInt(4); + String s = ("" + input.charAt(i)).toUpperCase(); + if (codonTable.containsKey(s)) { + String[] sa = codonTable.get(s); + output.append(sa[choose]); + } + } + // add some junk bases to the end of the cipher text + int offset = key.charAt(input.length() % key.length()); + StringBuilder junk = new StringBuilder(); + for (int j = 0; j < offset; j++) { + junk.append(bases[ranGen.nextInt(4)]); + } + output.append(junk); + return output.toString(); + } + + /** + * Decrypts some input + * @param input

The input to decrypt

+ * @return

The decrypted input

+ */ + public String decrypt(String input) { + StringBuilder output = new StringBuilder(); + int keyCount = 0; + int junk = key.charAt(0); + while (input.length() > junk) { + // cuts out the junk bases + input = input.substring(junk); + // get the codon, decrypt the codon, remove it from the input string + String codon = input.substring(0, 4); + output.append(decryptTable.get(codon)); + input = input.substring(4); + // increment the key counter and update junk + keyCount++; + junk = key.charAt(keyCount % key.length()); + } + return output.toString(); + } } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java new file mode 100644 index 0000000..e97a11d --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java @@ -0,0 +1,18 @@ +package net.knarcraft.bookswithoutborders.utility; + +public class EncryptionHelper { + + /** + * Transforms a string key/password into its numerical values + * @param key

The key to transform

+ * @return

The numbers representing the key's characters

+ */ + public static String getNumberKeyFromStringKey(String key) { + StringBuilder integerKey = new StringBuilder(); + for (int x = 0; x < key.length(); x++) { + integerKey.append(Character.getNumericValue(Character.codePointAt(key, x))); + } + return integerKey.toString(); + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/FileHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/FileHelper.java new file mode 100644 index 0000000..e75bea7 --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/FileHelper.java @@ -0,0 +1,41 @@ +package net.knarcraft.bookswithoutborders.utility; + +import java.io.File; + +public class FileHelper { + + /** + * Checks if a file path points to an actual book + * @param bookFile

The path to a book

+ * @return

True if the file exists and points to a book file

+ */ + public static boolean bookFileExists(String bookFile) { + return ((new File(bookFile).isFile() && (bookFile.endsWith(".txt") || + bookFile.endsWith(".yml"))) || new File(bookFile + ".txt").isFile() || + new File(bookFile + ".yml").isFile()) && !bookFile.contains("../") && !bookFile.contains("..\\"); + } + + public static File getBookFile(String bookPath) { + if (!bookFileExists(bookPath)) { + return null; + } + + File bookFile = new File(bookPath); + if (bookFile.exists()) { + return bookFile; + } + + File bookFileYml = new File(bookPath + ".yml"); + if (bookFileYml.exists()) { + return bookFileYml; + } + + File bookFileTxt = new File(bookPath + ".txt"); + if (bookFileTxt.exists()) { + return bookFileTxt; + } + + return null; + } + +} diff --git a/src/test/java/net/knarcraft/bookswithoutborders/GenenCryptTest.java b/src/test/java/net/knarcraft/bookswithoutborders/GenenCryptTest.java new file mode 100644 index 0000000..b7254e9 --- /dev/null +++ b/src/test/java/net/knarcraft/bookswithoutborders/GenenCryptTest.java @@ -0,0 +1,17 @@ +package net.knarcraft.bookswithoutborders; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class GenenCryptTest { + + @Test + public void encryptDecryptTest() { + GenenCrypt gc = new GenenCrypt("Another Key"); + gc.printCodonTable(); + String encrypted = gc.encrypt("Hello World!"); + assertEquals("HELLO WORLD!", gc.decrypt(encrypted)); + } + +} diff --git a/src/test/java/net/knarcraft/bookswithoutborders/util/EncryptionHelperTest.java b/src/test/java/net/knarcraft/bookswithoutborders/util/EncryptionHelperTest.java new file mode 100644 index 0000000..ef425ff --- /dev/null +++ b/src/test/java/net/knarcraft/bookswithoutborders/util/EncryptionHelperTest.java @@ -0,0 +1,16 @@ +package net.knarcraft.bookswithoutborders.util; + +import net.knarcraft.bookswithoutborders.utility.EncryptionHelper; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class EncryptionHelperTest { + + @Test + public void getNumberKeyFromStringKey() { + String numberKey = EncryptionHelper.getNumberKeyFromStringKey("hello"); + assertEquals("1714212124", numberKey); + } + +}