From 12429d22aa9ffa250ecb27f5583a368ac7c8bde2 Mon Sep 17 00:00:00 2001 From: Zacharias Date: Fri, 25 Apr 2025 12:21:44 +0200 Subject: [PATCH] Added some documentation to the code. fixed a slight bug in the encofing of user data where evry user had the same password of "pass". --- src/main/java/me/zacharias/bank/Account.java | 77 ++++++++++++++- .../java/me/zacharias/bank/AccountType.java | 12 +++ .../java/me/zacharias/bank/BankAccount.java | 6 +- src/main/java/me/zacharias/bank/Launcher.java | 11 ++- src/main/java/me/zacharias/bank/Main.java | 3 + .../me/zacharias/bank/SavingsAccount.java | 7 +- src/main/java/me/zacharias/bank/User.java | 66 ++++++++++++- src/main/java/me/zacharias/bank/Utils.java | 99 +++++++++++++++++-- src/main/java/me/zacharias/bank/app/Main.java | 2 +- .../bank/transaction/Transaction.java | 68 ++++++++++++- .../bank/transaction/TransactionType.java | 25 ++++- 11 files changed, 351 insertions(+), 25 deletions(-) diff --git a/src/main/java/me/zacharias/bank/Account.java b/src/main/java/me/zacharias/bank/Account.java index a26e430..6b9626c 100644 --- a/src/main/java/me/zacharias/bank/Account.java +++ b/src/main/java/me/zacharias/bank/Account.java @@ -48,7 +48,14 @@ public class Account { this.interestRate = interestRate; transactions.add(new Transaction(0, "Account opened", id, id, TransactionType.OPEN)); } - + + /** + * Withdraws the given amount from the account. + * @param amount The amount to be withdrawn + * @param description The description of the transaction + * @param destination The destination of the transaction + * @return The transaction object + */ public Transaction WithdrawTransaction(double amount, String description, UUID destination) { if(amount < 0) { throw new IllegalArgumentException("Amount cannot be negative"); @@ -62,6 +69,13 @@ public class Account { return transaction; } + /** + * Deposits the given amount into the account. + * @param amount The amount to be deposited + * @param description The description of the transaction + * @param originator The originator of the transaction + * @return The transaction object + */ public Transaction DepositTransaction(double amount, String description, UUID originator) { if(amount < 0) { throw new IllegalArgumentException("Amount cannot be negative"); @@ -72,6 +86,14 @@ public class Account { return transaction; } + /** + * Transfers the given amount from the account to the given destination. + * @param amount The amount to be transferred + * @param description The description of the transaction + * @param originator The originator of the transaction + * @param destination The destination of the transaction + * @return The transaction object + */ public Transaction TransferTransaction(double amount, String description, UUID originator, UUID destination) { if(amount < 0 && balance < Math.abs(amount)) { throw new IllegalArgumentException("Insufficient balance"); @@ -82,6 +104,11 @@ public class Account { return transaction; } + /** + * Handles the given transaction. + * @param transaction The transaction to be handled + * @return The transaction object + */ public Transaction handleTransaction(Transaction transaction) { if(transaction.getType() == TransactionType.WITHDRAW) { if(transaction.getAmount() < 0) { @@ -103,6 +130,9 @@ public class Account { return transaction; } + /** + * Loads the transactions from the TransactionQue.json file for this account. + */ public void load() { ArrayList transactions = Utils.GetTransactions(id); @@ -111,40 +141,79 @@ public class Account { handleTransaction(transaction); } } - + + /** + * Gets the name of the account. + * @return The name of the account + */ public String getName() { return name; } - + + /** + * Gets the balance of the account. + * @return The balance of the account + */ public double getBalance() { return balance; } + /** + * Gets the ID of the account. + * @return The ID of the account + */ public UUID getId() { return id; } - + + /** + * Gets the transactions of the account. + * @return The transactions of the account + */ public ArrayList getTransactions() { return transactions; } + /** + * Gets the interest of the account. + * @return The interest of the account + */ public double getInterest() { return balance * (1+interestRate); } + /** + * Gets the interest rate of the account. + * @return The interest rate of the account + */ @Override public String toString() { return toString(false); } + /** + * Gets the account as a string. + * @param negativ Whether to show the balance as + * @return The account as a string + */ public String toString(boolean negativ) { return name + " - " + (negativ ? -balance : balance) + " kr"; } + /** + * Contains the interest rates of the accounts. + */ public static class Interests { + /** + * Interest rate of the bank account. + */ public static final double BANK_ACCOUNT_INTEREST_RATE = 0.001; + + /** + * Interest rate of the savings account. + */ public static final double SAVINGS_ACCOUNT_INTEREST_RATE = 0.05; } } diff --git a/src/main/java/me/zacharias/bank/AccountType.java b/src/main/java/me/zacharias/bank/AccountType.java index c8d12b3..94840a1 100644 --- a/src/main/java/me/zacharias/bank/AccountType.java +++ b/src/main/java/me/zacharias/bank/AccountType.java @@ -1,7 +1,19 @@ package me.zacharias.bank; +/** + * Represents the type of an account. + */ public enum AccountType { + /** + * Bank account type. + */ BANK_ACCOUNT, + /** + * Savings account type. + */ SAVINGS_ACCOUNT, + /** + * Unknown account type. + */ UNKNOWN, } diff --git a/src/main/java/me/zacharias/bank/BankAccount.java b/src/main/java/me/zacharias/bank/BankAccount.java index f1a1361..e009fb4 100644 --- a/src/main/java/me/zacharias/bank/BankAccount.java +++ b/src/main/java/me/zacharias/bank/BankAccount.java @@ -3,9 +3,13 @@ package me.zacharias.bank; import static me.zacharias.bank.Account.Interests.BANK_ACCOUNT_INTEREST_RATE; /** - * This class only works as a way to have prefilled information, but can be replaced by just calling the {@link Account#Account(String, double, double)} instead + * This class only works as a way to have prefilled information, but can be replaced by just calling the {@link Account#Account(String, double)} instead */ public class BankAccount extends Account { + /** + * Creates a new BankAccount with the given name. + * @param name The name of the account + */ public BankAccount(String name) { super(name, BANK_ACCOUNT_INTEREST_RATE); } diff --git a/src/main/java/me/zacharias/bank/Launcher.java b/src/main/java/me/zacharias/bank/Launcher.java index b7708ff..0fa4596 100644 --- a/src/main/java/me/zacharias/bank/Launcher.java +++ b/src/main/java/me/zacharias/bank/Launcher.java @@ -7,7 +7,16 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.UUID; +/** + * Launcher class for the bank application. + * Used to provide an interface for creating new users. + */ public class Launcher { + /** + * Main method for the launcher. + * Used to provide an interface for creating new users. + * @param args The command line arguments + */ public static void main(String[] args) { ArrayList argsList = new ArrayList<>(); @@ -50,7 +59,7 @@ public class Launcher { Account a = user.createAccount("Konto"); a.DepositTransaction(100, "Welcome to the bank", UUID.fromString("00000000-0000-0000-0000-000000000000")); - user.write(); + user.write(password); users.add(user); }catch (Exception e) { diff --git a/src/main/java/me/zacharias/bank/Main.java b/src/main/java/me/zacharias/bank/Main.java index f7f6d24..7a09a53 100644 --- a/src/main/java/me/zacharias/bank/Main.java +++ b/src/main/java/me/zacharias/bank/Main.java @@ -9,6 +9,9 @@ import java.util.UUID; import static me.zacharias.bank.Utils.*; +/** + * This is more or less just a test class. + */ public class Main { User user; diff --git a/src/main/java/me/zacharias/bank/SavingsAccount.java b/src/main/java/me/zacharias/bank/SavingsAccount.java index 284d278..26dd2a3 100644 --- a/src/main/java/me/zacharias/bank/SavingsAccount.java +++ b/src/main/java/me/zacharias/bank/SavingsAccount.java @@ -3,10 +3,13 @@ package me.zacharias.bank; import static me.zacharias.bank.Account.Interests.SAVINGS_ACCOUNT_INTEREST_RATE; /** - * This class only works as a way to have prefilled information, but can be replaced by just calling the {@link Account#Account(String, double, double)} instead + * This class only works as a way to have prefilled information, but can be replaced by just calling the {@link Account#Account(String, double)} instead */ public class SavingsAccount extends Account{ - + /** + * Creates a new SavingsAccount with the given name. + * @param name The name of the account + */ public SavingsAccount(String name) { super(name, SAVINGS_ACCOUNT_INTEREST_RATE); } diff --git a/src/main/java/me/zacharias/bank/User.java b/src/main/java/me/zacharias/bank/User.java index a0f5a46..f03e30f 100644 --- a/src/main/java/me/zacharias/bank/User.java +++ b/src/main/java/me/zacharias/bank/User.java @@ -10,29 +10,63 @@ import java.util.UUID; import static me.zacharias.bank.Utils.*; +/** + * User class for the bank application. + * Used to store the user data. + */ public class User { + /** + * The user's id. + */ UUID id; + + /** + * The user's name. + */ String name; + + /** + * The user's accounts. + */ ArrayList accounts; + /** + * Creates a new User with the given name. + * @param name The name of the user + */ public User(String name) { this.name = name; id = UUID.randomUUID(); accounts = new ArrayList<>(); } + /** + * Creates a new BankAccount with the given name. + * @param name The name of the account + * @return The created account + */ public Account createAccount(String name) { Account account = new BankAccount(name); accounts.add(account); return account; } + /** + * Creates a new SavingsAccount with the given name. + * @param name The name of the account + * @return The created account + */ public Account createSavingsAccount(String name) { Account account = new SavingsAccount(name); accounts.add(account); return account; } - + + /** + * Gets the account with the given name. + * @param name The name of the account + * @return The account with the given name + */ public Account getAccount(String name) { for (Account account : accounts) { if (account.name.equals(name)) { @@ -41,7 +75,12 @@ public class User { } return null; } - + + /** + * Gets the account with the given id. + * @param id The id of the account + * @return The account with the given id + */ public Account getAccount(@NotNull UUID id) { for (Account account : accounts) { if (account.id.equals(id)) { @@ -51,6 +90,10 @@ public class User { return null; } + /** + * Deletes the given account. + * @param account The account to be deleted + */ public void deleteAccount(@NotNull Account account) { Account base = null; for(Account a : accounts) { @@ -65,25 +108,40 @@ public class User { accounts.remove(account); } + /** + * Gets the user's name. + * @return The user's name + */ public String getName() { return name; } + /** + * Gets the user's accounts. + * @return The user's accounts + */ public ArrayList getAccounts() { return accounts; } - public void write() { + /** + * Writes the user data to the user file. + * @param password The password used to encrypt the user data + */ + public void write(String password) { String user = SHA256(name); File userFile = new File("./users/" + user + ".json"); String json = gson.toJson(this); try { - WriteFile(userFile, Encrypt(json, "pass")); + WriteFile(userFile, Encrypt(json, password)); } catch (Exception e) { throw new RuntimeException(e); } } + /** + * Updates the accounts according to the TransactionQue.json file. + */ public void update() { for(Account account : accounts) { account.load(); diff --git a/src/main/java/me/zacharias/bank/Utils.java b/src/main/java/me/zacharias/bank/Utils.java index de8817f..ac5526d 100644 --- a/src/main/java/me/zacharias/bank/Utils.java +++ b/src/main/java/me/zacharias/bank/Utils.java @@ -21,8 +21,14 @@ import java.util.ArrayList; import java.util.Base64; import java.util.UUID; +/** + * Utils class for various utility functions. + */ public class Utils { + /** + * Simple Gson instance for serialization and deserialization the User classes. + */ public static final Gson gson; static { @@ -38,6 +44,11 @@ public class Utils { } } + /** + * SHA256 hasing os string mostly used for having an abstract way of storing usernames + * @param input String to be hashed + * @return hashed string using the SHA256 algorithm + */ public static String SHA256(String input) { MessageDigest sha256 = null; try { @@ -61,8 +72,22 @@ public class Utils { private static final int ITERATIONS = 65536; private static final int SALT_LENGTH = 16; private static final int IV_LENGTH = 12; - - public static String Encrypt(String data, String username) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { + + /** + * Encrypts the given data using AES/GCM/NoPadding with a random salt and IV. + * Used to encrypt the user data. before storing it in the user file. + * @param data The data in string format to be encrypted + * @param password The password used to derive the key for encryption + * @return The encrypted data + * @throws NoSuchPaddingException + * @throws NoSuchAlgorithmException + * @throws InvalidAlgorithmParameterException + * @throws InvalidKeyException + * @throws IllegalBlockSizeException + * @throws BadPaddingException + * @throws InvalidKeySpecException + */ + public static String Encrypt(String data, String password) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { SecureRandom random = new SecureRandom(); byte[] salt = new byte[SALT_LENGTH]; @@ -71,7 +96,7 @@ public class Utils { byte[] iv = new byte[IV_LENGTH]; random.nextBytes(iv); - SecretKey key = deriveKey(username, salt); + SecretKey key = deriveKey(password, salt); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv); @@ -85,7 +110,21 @@ public class Utils { return Base64.getEncoder().encodeToString(combined); } - + + /** + * Decrypts the given data using AES/GCM/NoPadding with a random salt and IV. + * Used to decrypt the user data. after retrieving it from the user file. + * @param data The data in string format to be decrypted + * @param username The password used to derive the key for decryption + * @return The decrypted data + * @throws NoSuchPaddingException + * @throws NoSuchAlgorithmException + * @throws InvalidAlgorithmParameterException + * @throws InvalidKeyException + * @throws IllegalBlockSizeException + * @throws BadPaddingException + * @throws InvalidKeySpecException + */ public static String Decrypt(String data, String username) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException { byte[] combined = Base64.getDecoder().decode(data); @@ -107,13 +146,28 @@ public class Utils { return new String(decrptedData); } - + + /** + * Derives the key from the given password and salt. + * Used to encrypt and decrypt the user data. + * @param password The password used to derive the key + * @param salt The salt used to derive the key + * @return The derived key + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + */ private static SecretKey deriveKey(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_SIZE); return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); } - + + /** + * Reads the given file and returns its content as a string. + * Used to read the user data from the user file. + * @param file The file to be read + * @return The content of the file as a string + */ public static String ReadFile(File file) { if(!file.exists()) @@ -136,7 +190,13 @@ public class Utils { throw new RuntimeException(e); } } - + + /** + * Writes the given data to the given file. + * Used to write the user data to the user file. + * @param file The file to write to + * @param data The data to be written + */ public static void WriteFile(File file, String data) { if(file.exists()) { @@ -159,6 +219,11 @@ public class Utils { } } + /** + * Adds the given transaction to the transactionQue.json file. + * Used to add transactions to the transaction queue for later processing by the receiving account. + * @param transaction The transaction to be added + */ public static void AddTrnsationQue(Transaction transaction) { try { File transactionQueFile = new File("./data/transactionQue.json"); @@ -192,6 +257,12 @@ public class Utils { } } + /** + * Gets all transactions from the transactionQue.json file. + * Used to get transactions from the transaction queue for later processing by the receiving account. + * @param account The account to get the transactions for + * @return The transactions from the transaction queue for the given account + */ public static ArrayList GetTransactions(UUID account) { try{ File transactionQueFile = new File("./data/transactionQue.json"); @@ -241,6 +312,13 @@ public class Utils { } } + /** + * Gets the JSONObject from the transactionQue.json file. + * Used to get the JSONObject from the transaction queue for later processing by the receiving account. + * @param transactionQueFile The file to get the JSONObject from + * @return The JSONObject from the transaction queue + * @throws IOException If an I/O error occurs + */ private static @NotNull JSONObject getJsonObject(File transactionQueFile) throws IOException { if(!transactionQueFile.exists()) { @@ -274,6 +352,13 @@ public class Utils { return jsonObject; } + /** + * Validates the transactions in the TransactionQue.json file. + * Used to validate the transaction queue for later processing by the receiving account. + * @param transactions the transactions array from the TransactionQue.json file + * @param validation the provided hash value from the TransactionQue.json file + * @return weather or not the key is valid for the transactions array + */ private static boolean validate(JSONArray transactions, String validation) { byte[] decodedBytes = Base64.getDecoder().decode(validation); StringBuilder result = new StringBuilder(); diff --git a/src/main/java/me/zacharias/bank/app/Main.java b/src/main/java/me/zacharias/bank/app/Main.java index aa90028..2a9f905 100644 --- a/src/main/java/me/zacharias/bank/app/Main.java +++ b/src/main/java/me/zacharias/bank/app/Main.java @@ -47,7 +47,7 @@ public class Main extends JPanel { public void logout() { frame.remove(mainManu); - mainManu.user.write(); + mainManu.user.write(new String(login.passwordField.getPassword())); mainManu = null; accountView = null; transactionView = null; diff --git a/src/main/java/me/zacharias/bank/transaction/Transaction.java b/src/main/java/me/zacharias/bank/transaction/Transaction.java index 5f8a16b..213c0c9 100644 --- a/src/main/java/me/zacharias/bank/transaction/Transaction.java +++ b/src/main/java/me/zacharias/bank/transaction/Transaction.java @@ -6,13 +6,44 @@ import java.time.format.DateTimeFormatter; import java.util.UUID; public class Transaction { + /** + * Amount of the transaction. + */ private double amount; + + /** + * Description of the transaction. + */ private String description; + + /** + * Originator of the transaction. + */ private UUID originator; + + /** + * Destination of the transaction. + */ private UUID destination; + + /** + * Type of the transaction. + */ private TransactionType type; + + /** + * Date of the transaction. + */ private String date; + /** + * Creates a new transaction. + * @param amount Amount of the transaction. + * @param description Description + * @param destination Destination of the transaction. + * @param originator Originator of the transaction. + * @param type Type of the transaction. + */ public Transaction(double amount, String description, UUID destination, UUID originator, TransactionType type) { this.amount = amount; this.description = description; @@ -22,30 +53,59 @@ public class Transaction { date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")); } + /** + * Gets the amount of the transaction. + * @return The amount of the transaction + */ public double getAmount() { return amount; } - + + /** + * Gets the description of the transaction. + * @return The description of the transaction + */ public String getDescription() { return description; } - + + /** + * Gets the originator of the transaction. + * @return The originator of the transaction + */ public UUID getOriginator() { return originator; } - + + /** + * Gets the destination of the transaction. + * @return The destination of the transaction + */ public UUID getDestination() { return destination; } - + + /** + * Gets the type of the transaction. + * @return The type of the transaction + */ public TransactionType getType() { return type; } + /** + * Gets the date of the transaction. + * @return The date of the transaction + */ public String getDate() { return date; } + /** + * Copies the transaction. + * @param transactionType Type of the transaction. + * @return A copy of the transaction. + */ public Transaction copy(TransactionType transactionType) { return new Transaction(amount, description, destination, originator, transactionType); } diff --git a/src/main/java/me/zacharias/bank/transaction/TransactionType.java b/src/main/java/me/zacharias/bank/transaction/TransactionType.java index 0496a1b..648848c 100644 --- a/src/main/java/me/zacharias/bank/transaction/TransactionType.java +++ b/src/main/java/me/zacharias/bank/transaction/TransactionType.java @@ -1,5 +1,28 @@ package me.zacharias.bank.transaction; public enum TransactionType { - WITHDRAW, DEPOSIT, OPEN, TRANSFER, CLOSE + /** + * Transaction type for withdrawing money from the account. + */ + WITHDRAW, + + /** + * Transaction type for depositing money into the account. + */ + DEPOSIT, + + /** + * Transaction type for opening the account. + */ + OPEN, + + /** + * Transaction type for transferring money from one account to another. + */ + TRANSFER, + + /** + * Transaction type for closing the account. + */ + CLOSE }