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".
This commit is contained in:
2025-04-25 12:21:44 +02:00
parent 86f67b07c9
commit 12429d22aa
11 changed files with 351 additions and 25 deletions

View File

@@ -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<Transaction> 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<Transaction> 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;
}
}

View File

@@ -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,
}

View File

@@ -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);
}

View File

@@ -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<String> 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) {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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<Account> 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<Account> 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();

View File

@@ -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<Transaction> 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();

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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
}