Fixed some issues, and made things readible from File.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'com.gradleup.shadow' version '9.0.0-beta7'
|
||||
}
|
||||
|
||||
group = 'me.zacharias'
|
||||
@@ -10,8 +11,16 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.12.1'
|
||||
implementation("org.jetbrains:annotations:23.1.0")
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
jar{
|
||||
manifest {
|
||||
attributes 'Main-class': 'me.zacharias.bank.Main'
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,25 @@ package me.zacharias.bank;
|
||||
|
||||
import me.zacharias.bank.transaction.Transaction;
|
||||
import me.zacharias.bank.transaction.TransactionType;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class Account {
|
||||
public class Account {
|
||||
ArrayList<Transaction> transactions;
|
||||
String name;
|
||||
double balance;
|
||||
UUID id;
|
||||
@MagicConstant(valuesFromClass = Interests.class)
|
||||
double interestRate;
|
||||
|
||||
public Account(String name, int balance) {
|
||||
public Account(String name, double balance, @MagicConstant(valuesFromClass = Interests.class) double interestRate) {
|
||||
this.name = name;
|
||||
this.balance = balance;
|
||||
transactions = new ArrayList<>();
|
||||
id = UUID.randomUUID();
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
|
||||
public void WithdrawTransaction(double amount, String description, UUID destination) {
|
||||
@@ -85,9 +89,13 @@ public abstract class Account {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
abstract double getInterestRate();
|
||||
|
||||
public double getInterest() {
|
||||
return balance * (1+getInterestRate());
|
||||
return balance * (1+interestRate);
|
||||
}
|
||||
|
||||
public static class Interests
|
||||
{
|
||||
public static final double BANK_ACCOUNT_INTEREST_RATE = 0.001;
|
||||
public static final double SAVINGS_ACCOUNT_INTEREST_RATE = 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
7
src/main/java/me/zacharias/bank/AccountType.java
Normal file
7
src/main/java/me/zacharias/bank/AccountType.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package me.zacharias.bank;
|
||||
|
||||
public enum AccountType {
|
||||
BANK_ACCOUNT,
|
||||
SAVINGS_ACCOUNT,
|
||||
UNKNOWN,
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package me.zacharias.bank;
|
||||
|
||||
public class BankAccount extends Account {
|
||||
public BankAccount(String name, int balance) {
|
||||
super(name, balance);
|
||||
}
|
||||
import static me.zacharias.bank.Account.Interests.BANK_ACCOUNT_INTEREST_RATE;
|
||||
|
||||
@Override
|
||||
double getInterestRate() {
|
||||
return 0.001;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public class BankAccount extends Account {
|
||||
public BankAccount(String name, double balance) {
|
||||
super(name, balance, BANK_ACCOUNT_INTEREST_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,84 @@
|
||||
package me.zacharias.bank;
|
||||
|
||||
public class Main {
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import static me.zacharias.bank.Utils.*;
|
||||
|
||||
public class Main {
|
||||
User user;
|
||||
|
||||
static Gson gson;
|
||||
|
||||
static {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
//gsonBuilder.registerTypeAdapter(Account.class, new AccountAdapter());
|
||||
|
||||
gson = gsonBuilder.create();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String user = SHA256("zacharias");
|
||||
File userFile = new File("./users/" + user + ".json");
|
||||
|
||||
if(!userFile.exists()) {
|
||||
|
||||
User u = new User("zacharias");
|
||||
u.createAccount("Konto", 0.0);
|
||||
Account a = u.getAccount("Konto");
|
||||
a.DepositTransaction(104, "Spawnar pängar", UUID.randomUUID());
|
||||
|
||||
String json = gson.toJson(u);
|
||||
try {
|
||||
WriteFile(userFile, Encrypt(json, "pass"));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
new Main();
|
||||
}
|
||||
|
||||
public Main() {
|
||||
|
||||
Console console = System.console();
|
||||
|
||||
if(console == null) {
|
||||
System.out.println("No console.");
|
||||
//return;
|
||||
}
|
||||
|
||||
String name = "zacharias";//console.readLine("Enter your name: ");
|
||||
|
||||
String userHash = SHA256(name);
|
||||
|
||||
File userFile = new File("./users/" + userHash + ".json");
|
||||
|
||||
if(!userFile.exists()) {
|
||||
System.out.println("User does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
String password = "pass";//new String(console.readPassword("Enter your password: "));
|
||||
|
||||
String userData;
|
||||
|
||||
try {
|
||||
userData = Decrypt(ReadFile(userFile), password);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
System.out.println(userData);
|
||||
|
||||
user = gson.fromJson(userData, User.class);
|
||||
|
||||
Account a = user.getAccount("Konto");
|
||||
System.out.println(a.getClass().getSimpleName());
|
||||
System.out.println(a.getBalance());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,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
|
||||
*/
|
||||
public class SavingsAccount extends Account{
|
||||
|
||||
public SavingsAccount(String name, int balance) {
|
||||
super(name, balance);
|
||||
}
|
||||
|
||||
@Override
|
||||
double getInterestRate() {
|
||||
return 0.05;
|
||||
public SavingsAccount(String name, double balance) {
|
||||
super(name, balance, SAVINGS_ACCOUNT_INTEREST_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,42 @@ import java.util.UUID;
|
||||
public class User {
|
||||
UUID id;
|
||||
String name;
|
||||
String password;
|
||||
ArrayList<Account> accounts;
|
||||
|
||||
public User(String name, String password) {
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
id = UUID.randomUUID();
|
||||
accounts = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void createAccount(String name, int balance) {
|
||||
public void createAccount(String name, double balance) {
|
||||
Account account = new BankAccount(name, balance);
|
||||
accounts.add(account);
|
||||
}
|
||||
|
||||
public void createSavingsAccount(String name, int balance) {
|
||||
public void createSavingsAccount(String name, double balance) {
|
||||
Account account = new SavingsAccount(name, balance);
|
||||
accounts.add(account);
|
||||
}
|
||||
|
||||
public Account getAccount(String name) {
|
||||
for (Account account : accounts) {
|
||||
if (account.name.equals(name)) {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Account getAccount(UUID id) {
|
||||
for (Account account : accounts) {
|
||||
if (account.id.equals(id)) {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteAccount(Account account) {
|
||||
Account base = null;
|
||||
for(Account a : accounts) {
|
||||
|
||||
133
src/main/java/me/zacharias/bank/Utils.java
Normal file
133
src/main/java/me/zacharias/bank/Utils.java
Normal file
@@ -0,0 +1,133 @@
|
||||
package me.zacharias.bank;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
public class Utils {
|
||||
public static String SHA256(String input) {
|
||||
MessageDigest sha256 = null;
|
||||
try {
|
||||
sha256 = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
byte[] hash = sha256.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) hexString.append('0');
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
private static final int KEY_SIZE = 256;
|
||||
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 Exception {
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
random.nextBytes(salt);
|
||||
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
random.nextBytes(iv);
|
||||
|
||||
SecretKey key = deriveKey(username, salt);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec);
|
||||
byte[] encryptedData = cipher.doFinal(data.getBytes());
|
||||
|
||||
byte[] combined = new byte[salt.length + iv.length + encryptedData.length];
|
||||
System.arraycopy(salt, 0, combined, 0, salt.length);
|
||||
System.arraycopy(iv, 0, combined, salt.length, iv.length);
|
||||
System.arraycopy(encryptedData, 0, combined, salt.length + iv.length, encryptedData.length);
|
||||
|
||||
return Base64.getEncoder().encodeToString(combined);
|
||||
}
|
||||
|
||||
public static String Decrypt(String data, String username) throws Exception {
|
||||
byte[] combined = Base64.getDecoder().decode(data);
|
||||
|
||||
// Extract salt, IV, and encrypted data
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
byte[] cipherText = new byte[combined.length - SALT_LENGTH - IV_LENGTH];
|
||||
|
||||
System.arraycopy(combined, 0, salt, 0, salt.length);
|
||||
System.arraycopy(combined, salt.length, iv, 0, iv.length);
|
||||
System.arraycopy(combined, salt.length + iv.length, cipherText, 0, cipherText.length);
|
||||
|
||||
SecretKey key = deriveKey(username, salt);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, gcmSpec);
|
||||
byte[] decrptedData = cipher.doFinal(cipherText);
|
||||
|
||||
return new String(decrptedData);
|
||||
}
|
||||
|
||||
private static SecretKey deriveKey(String password, byte[] salt) throws Exception {
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_SIZE);
|
||||
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
|
||||
}
|
||||
|
||||
public static String ReadFile(File file)
|
||||
{
|
||||
if(!file.exists())
|
||||
{
|
||||
throw new RuntimeException(new FileNotFoundException(file.getPath()+" not found"));
|
||||
}
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new FileReader(file));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while((line = br.readLine()) != null)
|
||||
{
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteFile(File file, String data) {
|
||||
if(file.exists())
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
file.createNewFile();
|
||||
|
||||
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
|
||||
bw.write(data);
|
||||
bw.close();
|
||||
}catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user