commit 691021ca702dc08cabf87b4acadfb748e0c0457c Author: bytedream Date: Thu Apr 28 19:41:28 2022 +0200 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..0018ad9 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ⚠️ UNFINISHED PROJECT ⚠️ + +> A try to create a java based end-to-end encrypted file sharing server with java based clients. But like nearly all of my java projects this didn't go so well. I think that it's not runnable. diff --git a/lib/animatefx-1.2.1.jar b/lib/animatefx-1.2.1.jar new file mode 100644 index 0000000..3ab1895 Binary files /dev/null and b/lib/animatefx-1.2.1.jar differ diff --git a/lib/controlsfx-8.40.17.jar b/lib/controlsfx-8.40.17.jar new file mode 100644 index 0000000..b2a7e7d Binary files /dev/null and b/lib/controlsfx-8.40.17.jar differ diff --git a/lib/hsqldb/hsqldb.jar b/lib/hsqldb/hsqldb.jar new file mode 100644 index 0000000..7870975 Binary files /dev/null and b/lib/hsqldb/hsqldb.jar differ diff --git a/lib/hsqldb/servlet-2_3-fcs-classfiles.zip b/lib/hsqldb/servlet-2_3-fcs-classfiles.zip new file mode 100644 index 0000000..c450772 Binary files /dev/null and b/lib/hsqldb/servlet-2_3-fcs-classfiles.zip differ diff --git a/lib/hsqldb/sqltool.jar b/lib/hsqldb/sqltool.jar new file mode 100644 index 0000000..b37f84e Binary files /dev/null and b/lib/hsqldb/sqltool.jar differ diff --git a/lib/log4j-1.2.17.jar b/lib/log4j-1.2.17.jar new file mode 100644 index 0000000..1d425cf Binary files /dev/null and b/lib/log4j-1.2.17.jar differ diff --git a/src/org/blueshard/olymp/Main.java b/src/org/blueshard/olymp/Main.java new file mode 100644 index 0000000..2049e3c --- /dev/null +++ b/src/org/blueshard/olymp/Main.java @@ -0,0 +1,58 @@ +package org.blueshard.olymp; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.exception.FatalIOException; +import org.blueshard.olymp.logging.EmptyLogger; +import org.blueshard.olymp.logging.ServerLogger; +import org.blueshard.olymp.register_code.RegisterCode; +import org.blueshard.olymp.server.MainServer; +import org.blueshard.olymp.sql.SQL; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.SQLException; + +public class Main { + + private static Connection connection = new SQL().getConnection(); + public Logger root = new EmptyLogger().getLogger(); + + public static void main(String[] args) throws IOException, SQLException { + if (args.length == 1) { + String command = args[0].strip().toLowerCase(); + if (command.equals("sql")) { + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + Connection connection = getConnection(); + String SQLQuery; + while (true) { + System.out.print("SQL Query: "); + SQLQuery = input.readLine().strip().toUpperCase(); + + if (SQLQuery.equals("EXIT")) { + break; + } else { + connection.createStatement().executeQuery(SQLQuery); + } + } + } else if (command.equals("add registercode")) { + try { + RegisterCode.generateNewRegisterCode(); + } catch (FatalIOException e) { + e.printStackTrace(); + } + } + } else { + MainServer server = new MainServer(8269, new ServerLogger().main()); + server.start(); + + connection.close(); + } + } + + public static Connection getConnection() { + return connection; + } + +} diff --git a/src/org/blueshard/olymp/cli/Main.java b/src/org/blueshard/olymp/cli/Main.java new file mode 100644 index 0000000..e9e232b --- /dev/null +++ b/src/org/blueshard/olymp/cli/Main.java @@ -0,0 +1,20 @@ +package org.blueshard.olymp.cli; + +import org.blueshard.olymp.exception.FatalIOException; +import org.blueshard.olymp.register_code.RegisterCode; + +import java.io.IOException; +import java.sql.SQLException; + +public class Main { + + public static void main(String[] args) throws IOException, FatalIOException, SQLException { + switch (args[0].strip()) { + case "start": + org.blueshard.olymp.Main.main(new String[0]); + case "add register code": + RegisterCode.generateNewRegisterCode(); + } + } + +} diff --git a/src/org/blueshard/olymp/cli/SQLCli.java b/src/org/blueshard/olymp/cli/SQLCli.java new file mode 100644 index 0000000..3d3a083 --- /dev/null +++ b/src/org/blueshard/olymp/cli/SQLCli.java @@ -0,0 +1,15 @@ +package org.blueshard.olymp.cli; + +import javax.net.SocketFactory; +import java.io.IOException; +import java.net.Socket; + +public class SQLCli { + + public static void main(String[] args) throws IOException { + Socket server = SocketFactory.getDefault().createSocket("localhost", 8269); + + + } + +} diff --git a/src/org/blueshard/olymp/data/Data.java b/src/org/blueshard/olymp/data/Data.java new file mode 100644 index 0000000..f179324 --- /dev/null +++ b/src/org/blueshard/olymp/data/Data.java @@ -0,0 +1,166 @@ +package org.blueshard.olymp.data; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class Data { + + private String dataAsString; + private Map data = new HashMap<>(); + + public Data(String data) { + this.dataAsString = data; + + String key = ""; + String dataString = dataAsString; + + String separator = getSeparator(); + try { + if (separator.length() == 1) { + dataString = dataString.substring(dataString.indexOf(",")).strip(); + } else { + dataString = dataString.substring(dataString.indexOf(",") + 1).strip(); + } + } catch (StringIndexOutOfBoundsException e) { + dataString = ""; + } + for (String string: dataString.split(separator)) { + string = string.strip(); + if (string.equals(":") || string.equals(",") || string.equals("{") || string.equals("}")) { + continue; + } else if (key.isEmpty()) { + key = string; + } else { + this.data.put(key, string); + key = ""; + } + } + } + + public int getCode() { + int lenBeforeCode = 1 + getSeparator().length() + 1; + return Integer.parseInt(dataAsString.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + } + + public Map getData() { + return data; + } + + public String getDataAsString() { + return dataAsString; + } + + public String getFromData(String key) { + return data.get(key); + } + + private String getSeparator() { + return dataAsString.substring(1).split(":")[0]; + } + + public static class Builder { + + private Map data = new HashMap<>(); + private int code; + + public Builder(int code) { + this.code = code; + } + + public String createData() { + String separator = createSeparator(); + + StringBuilder dataAsString = new StringBuilder("{" + separator + ":" + code); + data.forEach((key, value) -> dataAsString.append(",") + .append(separator) + .append(key) + .append(separator) + .append(":") + .append(separator) + .append(value) + .append(separator)); + dataAsString.append("}"); + + return dataAsString.toString(); + } + + public String createSeparator() { + char choice; + + StringBuilder stringBuilder = new StringBuilder(); + String indicator = "'"; + char[] choices = {'\'', '"', '^'}; + + data.forEach((key, value) -> stringBuilder.append(key).append(value)); + + String string = stringBuilder.toString(); + + while (true) { + if (string.contains(indicator)) { + switch (indicator) { + case "'": + indicator = "\""; + break; + case "\"": + indicator = "^"; + break; + default: + { + choice = choices[new Random().nextInt(choices.length) - 1]; + if (indicator.contains("|")) { + String[] splitted_indicator = indicator.split("\\|"); + indicator = splitted_indicator[0] + choice + '|' + choice + splitted_indicator[1]; + } else { + indicator = indicator + choice + '|' + choice + indicator; + } + } + } + } else { + return indicator; + } + } + } + + public void addData(String key, String value) { + this.data.put(key, value); + } + + public void addAllData(Map allData) { + this.data.putAll(allData); + } + + public int getCode() { + return code; + } + + public Data getData() { + return new Data(getDataAsString()); + } + + public Map getDataMap() { + return data; + } + + public String getDataAsString() { + return createData(); + } + } + + public static boolean isDataString(String string) { + try { + string = string.strip(); + if (string.startsWith("{") && string.endsWith("}") && string.contains(":")) { + String separator = string.substring(1).split(":")[0]; + int lenBeforeCode = 1 + separator.length() + 1; + Integer.parseInt(string.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } + +} diff --git a/src/org/blueshard/olymp/data/DataCodes.java b/src/org/blueshard/olymp/data/DataCodes.java new file mode 100644 index 0000000..1b89817 --- /dev/null +++ b/src/org/blueshard/olymp/data/DataCodes.java @@ -0,0 +1,156 @@ +package org.blueshard.olymp.data; + +public class DataCodes { + + public static final int DATACODESLENGHT = 5; + + public static class Client { + + public static final int UNEXPECTEDERROR = 56400; + public static final int UNEXPECTEDEXIT = 95078; + + public static final int CLOSE = 69826; + + public static final int FIRSTCONNECT = 19938; + + public static final int PUBLICKEY = 19294; + + public static final int UPDATEYES = 80515; + public static final int UPDATENO = 38510; + + public static final int LOGIN = 39208; + public static final int REGISTERCODE = 18981; + public static final int REGISTER = 84219; + + public static final int GETFILESDATA = 28926; + public static final int GETFILE = 95868; + public static final int SENDFILE = 53639; + + } + + public static class Server { + + public static final int UNEXPECTEDERROR = 29875; + public static final int UNEXPECTEDEXIT = 85048; + + public static final int NOTLOGGEDIN = 77015; + + public static final int CLOSE = 42812; + + public static final int READY = 86670; + public static final int FIRSTCONNECT = 76896; + + public static final int PUBLICKEY = 19294; + + public static final int OPTIONALUPDATE = 12925; + public static final int REQUIREDUPDATE = 97103; + + public static final int LOGINFAIL = 11868; + public static final int LOGINSUCCESS = 54151; + public static final int REGISTERCODE_EXIST = 31166; + public static final int REGISTERCODE_NOT_EXIST = 47648; + public static final int REGISTERFAIL = 52300; + public static final int REGISTERFAIL_USER_EXIST= 77444; + public static final int REGISTERSUCCESS = 34367; + + public static final int RECEIVEFILEFAIL = 45747; + public static final int RECEIVEFILESUCCESS = 75368; + public static final int SENDFILESDATA = 78946; + public static final int SENDFILEFAIL = 90173; + public static final int SENDFILESSUCCESS = 37272; + + } + + public static class Params { + + public static class CheckSum { + + public static final String MD5 = "md5"; + + } + + public static class ClientAgent { + + public static final String CLIENTAGENT = "clientAgent"; + + public static final String VALIDAGENT = "validAgent"; + + public static final String THEOSUI = "theosUI"; + + } + + public static class File { + + public static final String STARTDIRECOTRY = "startDirectory"; + public static final String FILEPATH = "filepath"; + + } + + public static class Key { + + public static final String PUBLICKEY = "key"; + + } + + public static class LogLevel { + + public static final String LOGLEVEL = "logLevel"; + + public static final String ALL = "0"; + public static final String WARNING = "1"; + public static final String NOTHING = "2"; + + } + + public static class LogReg { + + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String SALT = "salt"; + public static final String EMAIL = "email"; + + } + + public static class RegisterCode { + + public static final String REGISTERCODE = "registerCode"; + + } + + public static class Update { + + public static final String UPDATE = "update"; + + public static final String NEWVERSION = "newVersion"; + public static final String CHANGES = "changes"; + + } + + public static class UserLevel { + + public static final String USERLEVEL = "userLevel"; + + public static final String PUBLIC = "0"; + public static final String PROTECTED = "1"; + public static final String PRIVATE = "2"; + + } + + public static class State { + + public static final String STATE = "state"; + + public static final String ACTIVE = "active"; + public static final String DISABLED = "disabled"; + + } + + public static class Version { + + public static final String VERSION = "version"; + + } + + } + +} diff --git a/src/org/blueshard/olymp/e2ee/AESCipher.java b/src/org/blueshard/olymp/e2ee/AESCipher.java new file mode 100644 index 0000000..a8cefa0 --- /dev/null +++ b/src/org/blueshard/olymp/e2ee/AESCipher.java @@ -0,0 +1,48 @@ +package org.blueshard.olymp.e2ee; + +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.utils.ExceptionUtils; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class AESCipher { + + private static final int keySize = 256; + + public static byte[] generateKey() throws UnexpectedException { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(keySize); + SecretKey secretKey = keyGenerator.generateKey(); + return secretKey.getEncoded(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] input, byte[] key) throws UnexpectedException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new UnexpectedException(e); + } + } + + public static byte[] decrypt(byte[] input, byte[] key) throws UnexpectedException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchPaddingException | NoSuchAlgorithmException e) { + throw new UnexpectedException(e); + } + } + +} diff --git a/src/org/blueshard/olymp/e2ee/E2EEConverter.java b/src/org/blueshard/olymp/e2ee/E2EEConverter.java new file mode 100644 index 0000000..4d2e213 --- /dev/null +++ b/src/org/blueshard/olymp/e2ee/E2EEConverter.java @@ -0,0 +1,36 @@ +package org.blueshard.olymp.e2ee; + +import org.blueshard.olymp.exception.UnexpectedException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class E2EEConverter { + + private final static String separator = "@"; + + public static String decrypt(String input, byte[] privateKey) throws UnexpectedException, BadPaddingException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException { + String[] inputAsArray = input.split(separator); + String key = inputAsArray[0]; + String realInput = inputAsArray[1]; + + byte[] AESKey = RSACipher.decrypt(Base64.getDecoder().decode(key), privateKey); + + return new String(AESCipher.decrypt(Base64.getDecoder().decode(realInput), AESKey)); + } + + public static String encrypt(String input, byte[] publicKey) throws UnexpectedException, BadPaddingException, InvalidKeyException, IllegalBlockSizeException, InvalidKeySpecException { + byte[] AESKey = AESCipher.generateKey(); + + String encryptedKey = Base64.getEncoder().encodeToString(RSACipher.encrypt(AESKey, publicKey)); + String encryptedInput = Base64.getEncoder().encodeToString(AESCipher.encrypt(input.getBytes(StandardCharsets.UTF_8), AESKey)); + + return encryptedKey + separator + encryptedInput; + } + +} diff --git a/src/org/blueshard/olymp/e2ee/RSACipher.java b/src/org/blueshard/olymp/e2ee/RSACipher.java new file mode 100644 index 0000000..1e37b0a --- /dev/null +++ b/src/org/blueshard/olymp/e2ee/RSACipher.java @@ -0,0 +1,57 @@ +package org.blueshard.olymp.e2ee; + +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.utils.ExceptionUtils; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.*; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RSACipher { + + private static final int keySize = 2048; + + public static KeyPair generateKeyPair() throws UnexpectedException { + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(keySize); + return keyPairGenerator.generateKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] key, byte[] publicKey) throws UnexpectedException, InvalidKeyException, InvalidKeySpecException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); + RSAPublicKey publicRSAKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicRSAKey); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] decrypt(byte[] key, byte[] privateKey) throws UnexpectedException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privatePKCS8Key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey)); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privatePKCS8Key); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + +} diff --git a/src/org/blueshard/olymp/exception/ErrorCodes.java b/src/org/blueshard/olymp/exception/ErrorCodes.java new file mode 100644 index 0000000..0dc9690 --- /dev/null +++ b/src/org/blueshard/olymp/exception/ErrorCodes.java @@ -0,0 +1,24 @@ +package org.blueshard.olymp.exception; + +import java.util.HashSet; +import java.util.Set; + +public class ErrorCodes { + + public final static int couldnt_create_userfiles_folder = 293; + public final static int couldnt_delete_userfiles_folder = 219; + + public final static int couldnt_delete_custom_user_directory = 383; + public final static int couldnt_delete_custom_user_file = 942; + + public static final int couldnt_read_versions_conf = 317; + + public final static int couldnt_create_user_information = 249; + public final static int couldnt_get_user_information = 890; + public final static int couldnt_delete_user_information = 345; + + public final static int couldnt_create_register_code = 457; + public final static int couldnt_get_register_code = 350; + public final static int couldnt_delete_register_code = 569; + +} diff --git a/src/org/blueshard/olymp/exception/FatalIOException.java b/src/org/blueshard/olymp/exception/FatalIOException.java new file mode 100644 index 0000000..2256ab0 --- /dev/null +++ b/src/org/blueshard/olymp/exception/FatalIOException.java @@ -0,0 +1,30 @@ +package org.blueshard.olymp.exception; + +public class FatalIOException extends Exception { + + private final int errno; + private final Throwable throwable; + + public FatalIOException(int errno, String message) { + super("Errno: " + errno + " - " + message); + + this.errno = errno; + this.throwable = null; + } + + public FatalIOException(int errno, String message, Throwable t) { + super("Errno: " + errno + " - " + message); + + this.errno = errno; + this.throwable = t; + } + + public int getErrno() { + return errno; + } + + public Throwable getCauseThrowable() { + return throwable; + } + +} diff --git a/src/org/blueshard/olymp/exception/IllegalCodeException.java b/src/org/blueshard/olymp/exception/IllegalCodeException.java new file mode 100644 index 0000000..c5affaf --- /dev/null +++ b/src/org/blueshard/olymp/exception/IllegalCodeException.java @@ -0,0 +1,15 @@ +package org.blueshard.olymp.exception; + +public class IllegalCodeException extends Exception { + + private final int givenCode; + private final int requiredCode; + + public IllegalCodeException(int givenCode, int requiredCode){ + super("Wrong data code is given '" + givenCode + "', expected '" + requiredCode + "'"); + + this.givenCode = givenCode; + this.requiredCode = requiredCode; + } + +} diff --git a/src/org/blueshard/olymp/exception/IllegalPasswordException.java b/src/org/blueshard/olymp/exception/IllegalPasswordException.java new file mode 100644 index 0000000..bcea633 --- /dev/null +++ b/src/org/blueshard/olymp/exception/IllegalPasswordException.java @@ -0,0 +1,9 @@ +package org.blueshard.olymp.exception; + +public class IllegalPasswordException extends Exception { + + public IllegalPasswordException(String errorMessage){ + super(errorMessage); + } + +} diff --git a/src/org/blueshard/olymp/exception/RegisterCodeNotExistException.java b/src/org/blueshard/olymp/exception/RegisterCodeNotExistException.java new file mode 100644 index 0000000..fb2b21f --- /dev/null +++ b/src/org/blueshard/olymp/exception/RegisterCodeNotExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.olymp.exception; + +public class RegisterCodeNotExistException extends Exception { + + public RegisterCodeNotExistException(String registerCode) { + super("The register code '" + registerCode + "' do not exist"); + } + +} diff --git a/src/org/blueshard/olymp/exception/UnexpectedException.java b/src/org/blueshard/olymp/exception/UnexpectedException.java new file mode 100644 index 0000000..ea75364 --- /dev/null +++ b/src/org/blueshard/olymp/exception/UnexpectedException.java @@ -0,0 +1,23 @@ +package org.blueshard.olymp.exception; + +public class UnexpectedException extends Exception { + + public UnexpectedException() { + super("An unexpected error occurred"); + } + + public UnexpectedException(Throwable t) { + super("An unexpected error occurred (" + t.getMessage() + ")"); + this.setStackTrace(t.getStackTrace()); + } + + public UnexpectedException(String message) { + super(message); + } + + public UnexpectedException(String message, Throwable t) { + super(message); + this.setStackTrace(t.getStackTrace()); + } + +} diff --git a/src/org/blueshard/olymp/exception/UserAlreadyExistException.java b/src/org/blueshard/olymp/exception/UserAlreadyExistException.java new file mode 100644 index 0000000..ab1bbbf --- /dev/null +++ b/src/org/blueshard/olymp/exception/UserAlreadyExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.olymp.exception; + +public class UserAlreadyExistException extends UserException { + + public UserAlreadyExistException(String username, String message) { + super(username, message); + } + +} diff --git a/src/org/blueshard/olymp/exception/UserException.java b/src/org/blueshard/olymp/exception/UserException.java new file mode 100644 index 0000000..e7439ba --- /dev/null +++ b/src/org/blueshard/olymp/exception/UserException.java @@ -0,0 +1,13 @@ +package org.blueshard.olymp.exception; + +public class UserException extends Exception { + + final String UUID; + + public UserException(String UUID, String message) { + super(message); + + this.UUID = UUID; + } + +} diff --git a/src/org/blueshard/olymp/exception/UserNotExistException.java b/src/org/blueshard/olymp/exception/UserNotExistException.java new file mode 100644 index 0000000..5dd9814 --- /dev/null +++ b/src/org/blueshard/olymp/exception/UserNotExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.olymp.exception; + +public class UserNotExistException extends UserException { + + public UserNotExistException(String username, String message){ + super(username, message); + } + +} diff --git a/src/org/blueshard/olymp/exception/UserNotLoggedInException.java b/src/org/blueshard/olymp/exception/UserNotLoggedInException.java new file mode 100644 index 0000000..83ca72b --- /dev/null +++ b/src/org/blueshard/olymp/exception/UserNotLoggedInException.java @@ -0,0 +1,8 @@ +package org.blueshard.olymp.exception; + +public class UserNotLoggedInException extends UserException { + + public UserNotLoggedInException(String username, String message) { + super(username, message); + } +} diff --git a/src/org/blueshard/olymp/files/ConfReader.java b/src/org/blueshard/olymp/files/ConfReader.java new file mode 100644 index 0000000..5f200e3 --- /dev/null +++ b/src/org/blueshard/olymp/files/ConfReader.java @@ -0,0 +1,209 @@ +package org.blueshard.olymp.files; + +import java.io.*; +import java.util.Map; +import java.util.TreeMap; + +public class ConfReader { + + public static class SingleConfReader { + + private File confFile; + private TreeMap entries = new TreeMap<>(); + + public SingleConfReader(File confFile) throws IOException { + initialize(confFile); + } + + public SingleConfReader(String confFile) throws IOException { + initialize(new File(confFile)); + } + + private void initialize(File confFile) throws IOException { + this.confFile = confFile; + + BufferedReader bufferedReader = new BufferedReader(new FileReader(confFile)); + String line; + + while ((line = bufferedReader.readLine()) != null) { + line = line.strip(); + + if (line.isBlank() || line.isEmpty()) { + entries.put("#", null); + } else if (line.contains("#")) { + entries.put("#", line.substring(1)); + } else { + String[] keyValue = line.split("=", 1); + + entries.put(keyValue[0].strip(), keyValue[1].strip()); + } + } + + bufferedReader.close(); + } + + public boolean containsKey(String sectionName, String key) { + return entries.containsKey(key); + } + + public boolean containsValue(String sectionName, String value) { + return entries.containsKey(value); + } + + public TreeMap getAll() { + return entries; + } + + public TreeMap getAll(boolean onlyText) { + if (onlyText) { + TreeMap returnEntries = entries; + returnEntries.entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#")); + return returnEntries; + } else { + return entries; + } + } + + public String getKey(String value) { + for (Map.Entry entry: entries.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String key) { + return entries.get(key); + } + + public void remove(String key) { + entries.remove(key); + } + + public void replace(String key, String newValue) { + entries.replace(key, newValue); + } + + } + + public static class MultipleConfReader { + + private File confFile; + private TreeMap> entries = new TreeMap<>(); + + public MultipleConfReader(File confFile) throws IOException { + initialize(confFile); + } + + public MultipleConfReader(String confFile) throws IOException { + initialize(new File(confFile)); + } + + private void initialize(File confFile) throws IOException { + this.confFile = confFile; + + BufferedReader bufferedReader = new BufferedReader(new FileReader(confFile)); + String currentSection = null; + TreeMap currentEntries = new TreeMap<>(); + String line; + + while ((line = bufferedReader.readLine()) != null) { + line = line.strip(); + + if (line.isBlank() || line.isEmpty()) { + currentEntries.put("#", null); + } else if (line.contains("#")) { + currentEntries.put("#", line.substring(1)); + } else if (line.startsWith("[") && line.endsWith("]")) { + if (currentSection != null) { + entries.put(currentSection, currentEntries); + } + currentSection = line.substring(1, line.length() - 1); + } else { + String[] keyValue = line.split("=", 1); + if (keyValue.length == 1) { + currentEntries.put(keyValue[0].strip(), ""); + } else { + currentEntries.put(keyValue[0].strip(), keyValue[1].strip()); + } + } + } + + bufferedReader.close(); + } + + public boolean containsKey(String sectionName, String key) { + return entries.get(sectionName).containsKey(key); + } + + public boolean containsValue(String sectionName, String value) { + return entries.get(sectionName).containsKey(value); + } + + public boolean containsSection(String sectionName) { + return entries.containsKey(sectionName); + } + + public TreeMap> getAll() { + return entries; + } + + public TreeMap> getAll(boolean onlyText) { + if (onlyText) { + TreeMap> returnEntries = entries; + for (Map.Entry> entry : entries.entrySet()) { + entry.getValue().entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#")); + } + return returnEntries; + } else { + return entries; + } + } + + public TreeMap getAll(String sectionName) { + TreeMap returnEntries = entries.get(sectionName); + returnEntries.entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#")); + return returnEntries; + } + + public TreeMap getAll(String sectionName, boolean onlyText) { + if (onlyText) { + TreeMap returnEntries = entries.get(sectionName); + returnEntries.entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#")); + return returnEntries; + } else { + return entries.get(sectionName); + } + } + + public String getKey(String sectionName, String value) { + for (Map.Entry entry: entries.get(sectionName).entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String sectionName, String key) { + return entries.get(sectionName).get(key); + } + + public void remove(String sectionName, String key) { + entries.remove(sectionName).remove(key); + } + + public void removeSection(String sectionName) { + entries.remove(sectionName); + } + + public void replace(String sectionName, String key, String newValue) { + entries.get(sectionName).replace(key, newValue); + } + + } + +} diff --git a/src/org/blueshard/olymp/files/ConfWriter.java b/src/org/blueshard/olymp/files/ConfWriter.java new file mode 100644 index 0000000..4e96b83 --- /dev/null +++ b/src/org/blueshard/olymp/files/ConfWriter.java @@ -0,0 +1,267 @@ +package org.blueshard.olymp.files; + +import java.io.*; +import java.util.*; + +public class ConfWriter { + + + public static class SingleConfWriter { + + private TreeMap entries = new TreeMap<>(); + + public void write(String filename) throws IOException { + write(new File(filename)); + } + + public void write(File file) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + String key; + String value; + + for (Map.Entry entry: entries.entrySet()) { + key = entry.getKey(); + value = entry.getValue(); + + if (key.equals("#")) { + if (value == null) { + bufferedWriter.newLine(); + } else { + bufferedWriter.write(key + value); + } + } else { + bufferedWriter.write(key + " = " + value); + } + bufferedWriter.newLine(); + } + + bufferedWriter.flush(); + bufferedWriter.close(); + } + + public void add(String key, String value) { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + entries.put(key, value); + } + } + + public void addAll(TreeMap newEntries) { + TreeMap tempEntries = new TreeMap<>(); + + newEntries.forEach((key, value) -> { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + tempEntries.put(key, value); + } + }); + + entries.putAll(tempEntries); + } + + public void addBlankLine() { + TreeMap newEntries = entries; + + newEntries.put("#", null); + + entries = newEntries; + } + + public void addComment(String comment) { + TreeMap newEntries = entries; + + newEntries.put("#", comment); + + entries = newEntries; + } + + public TreeMap getAll() { + return entries; + } + + public void getAndAdd(String string) throws IOException { + getAndAdd(new File(string)); + } + + public void getAndAdd(File file) throws IOException { + entries.putAll(new ConfReader.SingleConfReader(file).getAll()); + } + + public String getKey(String value) { + for (Map.Entry entry: entries.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String key) { + return entries.get(key); + } + + public void remove(String key) { + entries.remove(key); + } + + public void replace(String key, String newValue) { + entries.replace(key, newValue); + } + + } + + public static class MultipleConfWriter { + + private TreeMap> entries = new TreeMap<>(); + + public void createNewSection(String sectionName) { + entries.put(sectionName, new TreeMap<>()); + } + + public void write(String filename) throws IOException { + write(new File(filename)); + } + + public void write(File file) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + String sectionKey; + String sectionValue; + + for (Map.Entry> entry: entries.entrySet()) { + String sectionName = entry.getKey(); + + bufferedWriter.write("[" + sectionName + "]"); + bufferedWriter.newLine(); + bufferedWriter.newLine(); + + for (Map.Entry sectionEntry: entries.get(sectionName).entrySet()) { + sectionKey = sectionEntry.getKey(); + sectionValue = sectionEntry.getValue(); + + if (sectionKey.equals("#")) { + if (sectionValue == null) { + bufferedWriter.newLine(); + } else { + bufferedWriter.write(sectionKey + sectionValue); + } + } else { + bufferedWriter.write(sectionKey + " = " + sectionValue); + } + bufferedWriter.newLine(); + } + } + + bufferedWriter.flush(); + bufferedWriter.close(); + } + + public void add(String sectionName, String key, String value) { + if (sectionName == null || key == null || !entries.containsKey(sectionName)) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + TreeMap newEntries = entries.get(sectionName); + newEntries.put(key, value); + entries.replace(sectionName, new TreeMap<>(newEntries)); + } + } + + public void addAll(String sectionName, TreeMap newEntries) { + TreeMap tempEntries = new TreeMap<>(); + + if (sectionName == null || !newEntries.containsKey(sectionName)) { + return; + } else { + newEntries.forEach((key, value) -> { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + tempEntries.put(key, value); + } + }); + } + + TreeMap newSectionEntries = entries.get(sectionName); + newSectionEntries.putAll(tempEntries); + entries.replace(sectionName, new TreeMap<>(newSectionEntries)); + } + + public void addBlankLine(String sectionName) { + TreeMap newEntries = entries.get(sectionName); + + newEntries.put("#", null); + + entries.put(sectionName, newEntries); + } + + public void addComment(String sectionName, String comment) { + TreeMap newEntries = entries.get(sectionName); + + newEntries.put("#", comment); + + entries.put(sectionName, newEntries); + } + + public void addSingleConfWriter(String sectionName, ConfWriter.SingleConfWriter singleConfWriter) { + entries.put(sectionName, singleConfWriter.entries); + } + + public TreeMap> getAll() { + return entries; + } + + public void getAndAdd(String string) throws IOException { + getAndAdd(new File(string)); + } + + public void getAndAdd(File file) throws IOException { + entries.putAll(new ConfReader.MultipleConfReader(file).getAll()); + } + + public String getKey(String sectionName, String value) { + for (Map.Entry entry: entries.get(sectionName).entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String sectionName, String key) { + return entries.get(sectionName).get(key); + } + + public void remove(String sectionName, String key) { + entries.remove(sectionName).remove(key); + } + + public void removeSection(String sectionName) { + entries.remove(sectionName); + } + + public void replace(String sectionName, String key, String newValue) { + entries.get(sectionName).replace(key, newValue); + } + + } + +} diff --git a/src/org/blueshard/olymp/files/ServerFiles.java b/src/org/blueshard/olymp/files/ServerFiles.java new file mode 100644 index 0000000..25a2ba3 --- /dev/null +++ b/src/org/blueshard/olymp/files/ServerFiles.java @@ -0,0 +1,39 @@ +package org.blueshard.olymp.files; + +public class ServerFiles { + + public static class etc { + + public static final String dir = "/srv/etc/"; + public static final String register_codes = dir + "register_codes"; + public static final String versions = dir + "versions.conf"; + + public static class update { + + public static final String dir = "/srv/etc/update/"; + public static final String TheosUI_jar = dir + "update.jar"; + + } + + } + + public static class logs { + + public static final String dir = "/srv/logs/"; + public static final String main_log = dir + "main.log"; + + } + + public static class user_files { + + public static final String dir = "/srv/user_files/"; + + public final String user_files_dir; + + public user_files(String UUID) { + user_files_dir = dir + UUID + "/"; + } + + } + +} diff --git a/src/org/blueshard/olymp/fileserver/FileReceiver.java b/src/org/blueshard/olymp/fileserver/FileReceiver.java new file mode 100644 index 0000000..9573d87 --- /dev/null +++ b/src/org/blueshard/olymp/fileserver/FileReceiver.java @@ -0,0 +1,76 @@ +package org.blueshard.olymp.fileserver; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.e2ee.E2EEConverter; +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.server.ClientFactory; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import java.io.*; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class FileReceiver { + + ClientFactory.Client client; + File destFile; + byte[] privateKey; + Logger logger; + + public FileReceiver(ClientFactory.Client client, File destFile, byte[] privateKey, Logger logger) { + this.client = client; + this.destFile = destFile; + this.privateKey = privateKey; + this.logger = logger; + } + + public String main() throws IOException, UnexpectedException, IllegalBlockSizeException, InvalidKeyException, InvalidKeySpecException, BadPaddingException, NoSuchPaddingException { + try { + SSLServerSocket FTPSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(20); + logger.info("Start File Receiver for client " + client.getId()); + logger.info("Receiver infos: " + FTPSocket.toString()); + + SSLSocket sslSocket = (SSLSocket) FTPSocket.accept(); + logger.info("Client connected"); + + InputStream inputStream = sslSocket.getInputStream(); + FileOutputStream fileOutputStream = new FileOutputStream(destFile); + StringBuilder hexString = new StringBuilder(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + fileOutputStream.write(Base64.getDecoder().decode(E2EEConverter.decrypt(Base64.getEncoder().encodeToString(buffer), privateKey)), 0, length); + md5.update(buffer, 0, length); + } + logger.info("Received file from client and saved it"); + + byte[] digest = md5.digest(); + + for (byte b : digest) { + if ((0xff & b) < 0x10) { + hexString.append("0").append(Integer.toHexString((0xFF & b))); + } else { + hexString.append(Integer.toHexString(0xFF & b)); + } + } + sslSocket.close(); + logger.info("Closed File Receiver"); + logger.info("File MD5 check sum is " + hexString.toString()); + + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(e); + } + } + +} diff --git a/src/org/blueshard/olymp/fileserver/FileSender.java b/src/org/blueshard/olymp/fileserver/FileSender.java new file mode 100644 index 0000000..053812b --- /dev/null +++ b/src/org/blueshard/olymp/fileserver/FileSender.java @@ -0,0 +1,74 @@ +package org.blueshard.olymp.fileserver; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.e2ee.E2EEConverter; +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.server.ClientFactory; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import java.io.*; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class FileSender { + + ClientFactory.Client client; + File sourceFile; + byte[] publicKey; + Logger logger; + + public FileSender(ClientFactory.Client client, File sourceFile, byte[] publicKey, Logger logger) { + this.client = client; + this.sourceFile = sourceFile; + this.publicKey = publicKey; + this.logger = logger; + } + + public String main() throws IOException, UnexpectedException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException, InvalidKeyException { + try { + SSLServerSocket FTPSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(20); + logger.info("Started file sender"); + logger.info("Sender infos: " + FTPSocket.toString()); + + SSLSocket sslSocket = (SSLSocket) FTPSocket.accept(); + logger.info("Client connected"); + + FileInputStream fileInputStream = new FileInputStream(sourceFile); + OutputStream outputStream = sslSocket.getOutputStream(); + StringBuilder hexString = new StringBuilder(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[1024]; + int length; + + while ((length = fileInputStream.read(buffer)) > 0) { + outputStream.write(Base64.getDecoder().decode(E2EEConverter.encrypt(Base64.getEncoder().encodeToString(buffer), publicKey)), 0, length); + md5.update(buffer, 0, length); + } + logger.info("Send file to client and saved it"); + + byte[] digest = md5.digest(); + + for (byte b : digest) { + if ((0xff & b) < 0x10) { + hexString.append("0").append(Integer.toHexString((0xFF & b))); + } else { + hexString.append(Integer.toHexString(0xFF & b)); + } + } + sslSocket.close(); + logger.info("Closed File Sender"); + + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(e); + } + } + +} diff --git a/src/org/blueshard/olymp/logging/ClientLogger.java b/src/org/blueshard/olymp/logging/ClientLogger.java new file mode 100644 index 0000000..5695474 --- /dev/null +++ b/src/org/blueshard/olymp/logging/ClientLogger.java @@ -0,0 +1,102 @@ +package org.blueshard.olymp.logging; + +import org.apache.log4j.*; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.spi.ThrowableInformation; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.server.ClientFactory; +import org.blueshard.olymp.utils.ConsoleColors; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Locale; + +public class ClientLogger { + + private final Logger logger; + + public ClientLogger(ClientFactory.Client client, Level logLevel) throws IOException { + logger = Logger.getLogger(String.valueOf(client.getId())); + logger.setLevel(logLevel); + + ConsoleAppender consoleAppender = new ConsoleAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + DateFormat date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.GERMANY); + Level level = loggingEvent.getLevel(); + StringBuilder extraData = new StringBuilder(); + String color; + String id = String.valueOf(client.getId()); + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + switch (loggingEvent.getLevel().toInt()) { + case Level.WARN_INT: + color = ConsoleColors.RED_BRIGHT; + break; + case Level.ERROR_INT: + color = ConsoleColors.RED_BOLD + ConsoleColors.RED_UNDERLINED; + break; + case Level.FATAL_INT: + color = ConsoleColors.BLACK; + break; + default: + color = ""; + break; + } + + if (throwableInformation != null) { + extraData.append(ConsoleColors.RED); + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return color + "[" + date.format(loggingEvent.getTimeStamp()) + " - ID: " + id + "] " + level + ": " + loggingEvent.getMessage() + "\n" + extraData.toString() + ConsoleColors.RESET; + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }); + RollingFileAppender rollingFileAppender = new RollingFileAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + DateFormat date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.GERMANY); + Level level = loggingEvent.getLevel(); + StringBuilder extraData = new StringBuilder(); + String id = String.valueOf(client.getId()); + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + if (throwableInformation != null) { + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return "[" + date.format(loggingEvent.getTimeStamp()) + " - ID: " + id + "] " + level + ": " + loggingEvent.getMessage() + "\n" + extraData.toString(); + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }, ServerFiles.logs.main_log, true); + rollingFileAppender.setMaxBackupIndex(10); + rollingFileAppender.setMaxFileSize("10MB"); + + logger.addAppender(consoleAppender); + logger.addAppender(rollingFileAppender); + } + + public Logger getLogger() { + return logger; + } + +} diff --git a/src/org/blueshard/olymp/logging/EmptyLogger.java b/src/org/blueshard/olymp/logging/EmptyLogger.java new file mode 100644 index 0000000..200f7c6 --- /dev/null +++ b/src/org/blueshard/olymp/logging/EmptyLogger.java @@ -0,0 +1,14 @@ +package org.blueshard.olymp.logging; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +public class EmptyLogger { + + public Logger getLogger() { + Logger logger = Logger.getLogger(EmptyLogger.class.getName()); + logger.setLevel(Level.OFF); + return logger; + } + +} diff --git a/src/org/blueshard/olymp/logging/LogDeleter.java b/src/org/blueshard/olymp/logging/LogDeleter.java new file mode 100644 index 0000000..e701ac4 --- /dev/null +++ b/src/org/blueshard/olymp/logging/LogDeleter.java @@ -0,0 +1,15 @@ +package org.blueshard.olymp.logging; + +import org.blueshard.olymp.user.User; + +public class LogDeleter { + + private final User user; + private final String logLifeTime; + + public LogDeleter(User user, String logLifeTime) { + this.user = user; + this.logLifeTime = logLifeTime; + } + +} diff --git a/src/org/blueshard/olymp/logging/ServerLogger.java b/src/org/blueshard/olymp/logging/ServerLogger.java new file mode 100644 index 0000000..bce3d2b --- /dev/null +++ b/src/org/blueshard/olymp/logging/ServerLogger.java @@ -0,0 +1,92 @@ +package org.blueshard.olymp.logging; + +import org.apache.log4j.*; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.spi.ThrowableInformation; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.utils.ConsoleColors; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Arrays; + +public class ServerLogger { + + private final Logger logger = LogManager.getLogger(ServerLogger.class); + + public Logger main() throws IOException { + logger.setLevel(Level.ALL); + + RollingFileAppender rollingFileAppender = new RollingFileAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + SimpleDateFormat date = new SimpleDateFormat("HH:mm:ss"); + StringBuilder extraData = new StringBuilder(); + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + if (throwableInformation != null) { + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return "[" + date.format(loggingEvent.getTimeStamp()) + " - Server] " + loggingEvent.getLevel() + ": " + loggingEvent.getMessage() + "\n" + extraData.toString(); + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }, ServerFiles.logs.main_log, true); + rollingFileAppender.setMaxBackupIndex(10); + rollingFileAppender.setMaxFileSize("10MB"); + ConsoleAppender consoleAppender = new ConsoleAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + SimpleDateFormat date = new SimpleDateFormat("HH:mm:ss"); + StringBuilder extraData = new StringBuilder(); + String color; + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + switch (loggingEvent.getLevel().toInt()) { + case Level.WARN_INT: + color = ConsoleColors.RED_BRIGHT; + break; + case Level.ERROR_INT: + color = ConsoleColors.RED_BOLD + ConsoleColors.RED_UNDERLINED; + break; + case Level.FATAL_INT: + color = ConsoleColors.BLACK; + break; + default: + color = ""; + break; + } + + if (throwableInformation != null) { + extraData.append(ConsoleColors.RED); + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return color + "[" + date.format(loggingEvent.getTimeStamp()) + " - Server] " + loggingEvent.getLevel() + ": " + loggingEvent.getMessage() + "\n" + extraData.toString() + ConsoleColors.RESET; + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }); + + logger.addAppender(rollingFileAppender); + logger.addAppender(consoleAppender); + + return logger; + } + +} diff --git a/src/org/blueshard/olymp/register_code/RegisterCode.java b/src/org/blueshard/olymp/register_code/RegisterCode.java new file mode 100644 index 0000000..a35f117 --- /dev/null +++ b/src/org/blueshard/olymp/register_code/RegisterCode.java @@ -0,0 +1,95 @@ +package org.blueshard.olymp.register_code; + +import org.blueshard.olymp.Main; +import org.blueshard.olymp.exception.ErrorCodes; +import org.blueshard.olymp.exception.FatalIOException; +import org.blueshard.olymp.sql.SQL; + +import java.sql.*; +import java.util.HashSet; +import java.util.concurrent.ThreadLocalRandom; + +public class RegisterCode { + + public static String generateNewRegisterCode() throws FatalIOException { + String[] letters = 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", + "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"}; + + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < 18; i++) { + stringBuilder.append(letters[ThreadLocalRandom.current().nextInt(0, letters.length)]); + } + + try { + Connection connection = Main.getConnection(); + + PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO REGISTER_CODES VALUES(?)"); + preparedStatement.setString(1, stringBuilder.toString()); + + preparedStatement.executeUpdate(); + + SQL.checkpoint(); + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_create_register_code, "Couldn't add new register code", e); + } + + return stringBuilder.toString(); + } + + public static HashSet getAllRegisterCodes() throws FatalIOException { + HashSet registerCodes = new HashSet<>(); + + try { + Statement statement = Main.getConnection().createStatement(); + + ResultSet resultSet = statement.executeQuery("SELECT CODE FROM REGISTER_CODE"); + + int columnCount; + + while (resultSet.next()) { + registerCodes.add(resultSet.getString(1)); + } + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_get_register_code, "Failed to read register codes", e); + } + + return registerCodes; + } + + public static boolean isRegisterCode(String registerCode) throws FatalIOException { + try { + Statement statement = Main.getConnection().createStatement(); + + ResultSet resultSet = statement.executeQuery("SELECT CODE FROM REGISTER_CODE"); + + while (resultSet.next()) { + if (resultSet.getString(1).equals(registerCode)) { + resultSet.close(); + return true; + } + } + resultSet.close(); + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_get_register_code, "Failed to read register codes", e); + } + + return false; + } + + public static void removeRegisterCode(String registerCode) throws FatalIOException { + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("DELETE FROM REGISTER_CODES WHERE CODE = ?"); + + preparedStatement.setString(1, registerCode); + preparedStatement.executeUpdate(); + + SQL.checkpoint(); + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_delete_register_code, "Failed to delete register code " + registerCode, e); + } + + } + +} diff --git a/src/org/blueshard/olymp/security/Password.java b/src/org/blueshard/olymp/security/Password.java new file mode 100644 index 0000000..693140f --- /dev/null +++ b/src/org/blueshard/olymp/security/Password.java @@ -0,0 +1,67 @@ +package org.blueshard.olymp.security; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; + +public class Password { + + public static PasswordInfos createPassword(String password, byte[] salt) throws InvalidKeySpecException { + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(salt); + + KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); + SecretKeyFactory factory = null; + try { + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException ignore) { + } + + byte[] hashedPassword; + try { + hashedPassword = factory.generateSecret(keySpec).getEncoded(); + } catch (InvalidKeySpecException ignore) { + } + + hashedPassword = factory.generateSecret(keySpec).getEncoded(); + + return new PasswordInfos(hashedPassword, salt); + } + + public static class PasswordInfos { + + private final byte[] password; + private final byte[] salt; + + public PasswordInfos(byte[] password, byte[] salt) { + this.password = password; + this.salt = salt; + } + + public byte[] getPasswordAsBytes() { + return password; + } + + public String getPasswordAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(password); + } + + public byte[] getSaltAsBytes() { + return salt; + } + + public String getSaltAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(salt); + } + + } + +} diff --git a/src/org/blueshard/olymp/server/Action.java b/src/org/blueshard/olymp/server/Action.java new file mode 100644 index 0000000..fabb364 --- /dev/null +++ b/src/org/blueshard/olymp/server/Action.java @@ -0,0 +1,133 @@ +package org.blueshard.olymp.server; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.Main; +import org.blueshard.olymp.data.DataCodes; +import org.blueshard.olymp.data.Data; +import org.blueshard.olymp.e2ee.RSACipher; +import org.blueshard.olymp.exception.*; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.register_code.RegisterCode; +import org.blueshard.olymp.sql.SQL; +import org.blueshard.olymp.sql.SQLPosition; +import org.blueshard.olymp.user.User; +import org.blueshard.olymp.version.TheosUIVersion; + +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; + +public class Action { + + private Data data; + private final ClientSender clientSender; + + public Action(Data data, ClientSender clientSender) { + this.data = data; + this.clientSender = clientSender; + } + + public void refreshData(Data data) { + this.data = data; + } + + public void close() { + clientSender.close(); + } + + public void firstConnectionResult(boolean validAgent, boolean update) { + clientSender.firstConnectResult(validAgent, update); + } + + public void isRegisterCode() throws FatalIOException { + if (RegisterCode.isRegisterCode(data.getFromData(DataCodes.Params.RegisterCode.REGISTERCODE))) { + clientSender.registerCodeExist(); + } else { + clientSender.registerCodeNotExist(); + } + } + + public static PrivateKey publicKey(OutputStream outputStream, Logger logger) throws UnexpectedException { + KeyPair keyPair = RSACipher.generateKeyPair(); + + ClientSender.publicKey(keyPair.getPublic(), new DataOutputStream(outputStream), logger); + + return keyPair.getPrivate(); + } + + public static void ready(OutputStream outputStream, Logger logger) { + ClientSender.ready(new DataOutputStream(outputStream), logger); + } + + public User login() throws UserNotExistException, IllegalCodeException, IllegalPasswordException, FatalIOException { + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("SELECT UUID FROM USERS WHERE USERNAME = ?"); + + preparedStatement.setString(1, data.getFromData(DataCodes.Params.LogReg.USERNAME)); + + ResultSet resultSet = preparedStatement.executeQuery(); + + if (resultSet.next()) { + User user = new User(resultSet.getString(1)); + + if (data.getCode() != DataCodes.Client.LOGIN) { + throw new IllegalCodeException(data.getCode(), DataCodes.Client.LOGIN); + } else if (!data.getFromData(DataCodes.Params.LogReg.PASSWORD).equals(user.getPasswordInfos().getPasswordAsString())) { + throw new IllegalPasswordException("Wrong password is given"); + } + + clientSender.loginSuccess(); + + resultSet.close(); + + return user; + } else { + resultSet.close(); + throw new UserNotExistException(data.getFromData(DataCodes.Params.LogReg.USERNAME), "The user doesn't exist"); + } + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_get_user_information, "Couldn't get UUID for user with name " + data.getFromData(DataCodes.Params.LogReg.USERNAME), e); + } + } + + public User register() throws FatalIOException, UserAlreadyExistException, RegisterCodeNotExistException { + User user = User.createNewUser(data.getFromData(DataCodes.Params.RegisterCode.REGISTERCODE), + data.getFromData(DataCodes.Params.LogReg.USERNAME), data.getFromData(DataCodes.Params.LogReg.PASSWORD), + data.getFromData(DataCodes.Params.LogReg.SALT), data.getFromData(DataCodes.Params.LogReg.EMAIL)); + + clientSender.registerSuccess(); + + return user; + } + + public void receiveFile(User user, byte[] privateKey) { + clientSender.receiveFile(new ServerFiles.user_files(user.getUUID()) + data.getFromData(DataCodes.Params.File.FILEPATH), privateKey); + } + + public void requestArtificeUIOptionalUpdate(TheosUIVersion version) { + clientSender.requestArtificeUIOptionalUpdate(version, version.getChanges()); + } + + public void requestArtificeUIRequiredUpdate(TheosUIVersion version) { + clientSender.requestArtificeUIRequiredUpdate(version, version.getChanges()); + } + + public void sendFile(String file, byte[] publicKey) { + clientSender.sendFile(new File(file), publicKey); + } + + public void sendUpdateFile(byte[] publicKey) { + clientSender.sendFile(new File(ServerFiles.etc.update.TheosUI_jar), publicKey); + } + + public void sendUserFilesData(String UUID, String startDirectory) { + clientSender.filesData(UUID, new File(new ServerFiles.user_files(UUID).user_files_dir + startDirectory)); + } + +} diff --git a/src/org/blueshard/olymp/server/ClientFactory.java b/src/org/blueshard/olymp/server/ClientFactory.java new file mode 100644 index 0000000..cc475f7 --- /dev/null +++ b/src/org/blueshard/olymp/server/ClientFactory.java @@ -0,0 +1,86 @@ +package org.blueshard.olymp.server; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.util.Arrays; +import java.util.TreeMap; +import java.util.concurrent.ThreadLocalRandom; + +public class ClientFactory { + + private TreeMap ids = new TreeMap<>(); + + public Client createNewClient(Socket socket, String clientAgent) { + int id; + do { + id = ThreadLocalRandom.current().nextInt(1, 999); + } while (ids.containsKey(id)); + + return new Client(id, socket, clientAgent); + } + + public class Client { + + private final int id; + private final Socket socket; + private String clientAgent; + + public Client(int id, Socket socket, String clientAgent) { + ClientFactory.this.ids.clear(); + this.id = id; + this.socket = socket; + this.clientAgent = clientAgent; + } + + public void close() throws IOException { + try { + socket.close(); + ids.remove(id); + } catch (IOException e) { + e.printStackTrace(); + throw new IOException("Couldn't close connection"); + } + } + + public int getId() { + return id; + } + + public String getClientAgent() { + return clientAgent; + } + + public InetAddress getInetAddress() { + return socket.getInetAddress(); + } + + public InputStream getInputStream() throws IOException { + return socket.getInputStream(); + } + + public String getIPAddress() { + return getInetAddress().getHostAddress(); + } + + public OutputStream getOutputStream() throws IOException { + return socket.getOutputStream(); + } + + public int getPort() { + return socket.getPort(); + } + + public void setClientAgent(String clientAgent) throws IllegalAccessException { + if (this.clientAgent != null) { + throw new IllegalAccessException("Client agent is already set"); + } else { + this.clientAgent = clientAgent; + } + } + + } + +} diff --git a/src/org/blueshard/olymp/server/ClientReceiver.java b/src/org/blueshard/olymp/server/ClientReceiver.java new file mode 100644 index 0000000..b268f90 --- /dev/null +++ b/src/org/blueshard/olymp/server/ClientReceiver.java @@ -0,0 +1,86 @@ +package org.blueshard.olymp.server; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.data.DataCodes; +import org.blueshard.olymp.data.Data; +import org.blueshard.olymp.e2ee.E2EEConverter; +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.user.User; + +import java.io.*; +import java.security.GeneralSecurityException; + +public class ClientReceiver { + + private final User user; + private final ClientFactory.Client client; + private final byte[] clientPublicKey; + private final byte[] privateKey; + private final Logger logger; + + private final DataInputStream clientInput; + private final ClientSender clientSender; + + ClientReceiver(User user, ClientFactory.Client client, ClientSender clientSender, byte[] clientPublicKey, byte[] privateKey, Logger logger) throws IOException { + this.user = user; + this.client = client; + this.clientPublicKey = clientPublicKey; + this.privateKey = privateKey; + this.logger = logger; + + try { + this.clientInput = new DataInputStream(this.client.getInputStream()); + this.clientSender = clientSender; + } catch (IOException e) { + throw new IOException(ResultCodes.UNEXPECTEDEXIT + ";" + e.getMessage()); + } + } + + public int main() { + Data inputData; + Action action = new Action(null, clientSender); + + while (true) { + try { + inputData = new Data(E2EEConverter.decrypt(clientInput.readUTF(), privateKey)); + } catch (IOException | GeneralSecurityException e) { + return ResultCodes.UNEXPECTEDEXIT; + } catch (UnexpectedException e) { + clientSender.unexpectedError(); + return ResultCodes.UNEXPECTEDEXIT; + } + action.refreshData(inputData); + switch (inputData.getCode()) { + case DataCodes.Client.UNEXPECTEDEXIT: + return ResultCodes.UNEXPECTEDEXIT; + + case DataCodes.Client.CLOSE: + return ResultCodes.EXIT; + + case DataCodes.Client.GETFILESDATA: + String startDirectory = inputData.getFromData(DataCodes.Params.File.STARTDIRECOTRY); + if (startDirectory == null) { + startDirectory = "/"; + } + action.sendUserFilesData(user.getUUID(), startDirectory); + break; + + case DataCodes.Client.GETFILE: + action.sendFile(user.getUserfileDirectory() + inputData.getFromData(DataCodes.Params.File.FILEPATH), privateKey); + break; + + case DataCodes.Client.SENDFILE: + action.receiveFile(user, clientPublicKey); + break; + } + } + } + + public static class ResultCodes { + + public static final int EXIT = 25; + public static final int UNEXPECTEDEXIT = 84; + + } + +} diff --git a/src/org/blueshard/olymp/server/ClientSender.java b/src/org/blueshard/olymp/server/ClientSender.java new file mode 100644 index 0000000..f82f02b --- /dev/null +++ b/src/org/blueshard/olymp/server/ClientSender.java @@ -0,0 +1,350 @@ +package org.blueshard.olymp.server; + +import org.apache.log4j.Logger; +import org.blueshard.olymp.data.Data; +import org.blueshard.olymp.data.DataCodes; +import org.blueshard.olymp.e2ee.E2EEConverter; +import org.blueshard.olymp.exception.UnexpectedException; +import org.blueshard.olymp.fileserver.FileReceiver; +import org.blueshard.olymp.fileserver.FileSender; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.utils.SizeUnit; +import org.blueshard.olymp.version.TheosUIVersion; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; +import java.util.concurrent.Executors; + +public class ClientSender { + + private final ClientFactory.Client client; + private final byte[] clientPublicKey; + private final Logger logger; + + private final DataOutputStream dataOutputStream; + + public ClientSender(ClientFactory.Client client, byte[] clientPublicKey, Logger logger) throws IOException, IllegalBlockSizeException, UnexpectedException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + this.client = client; + this.clientPublicKey = clientPublicKey; + this.logger = logger; + + this.dataOutputStream = new DataOutputStream(this.client.getOutputStream()); + + if (clientPublicKey.length != 0) { + E2EEConverter.encrypt("Test", clientPublicKey); // just test if the client key works + } + } + + public void send(Data data) throws IOException { + if (clientPublicKey.length == 0) { + dataOutputStream.writeUTF(data.getDataAsString() + "\n"); + } else { + try { + dataOutputStream.writeUTF(E2EEConverter.encrypt(data.getDataAsString() + "\n", clientPublicKey)); + } catch (UnexpectedException e) { + logger.error("An unexpected error occurred", e); + unexpectedError(); + } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidKeySpecException ignore) { + } + } + dataOutputStream.flush(); + } + + public void send(Data.Builder data) throws IOException { + send(data.getData()); + } + + private String loggerInfo(String data) { + return "Send " + data + " data"; + } + + private String loggerWarning(String data) { + return "Failed to send " + data + " data"; + } + + public void close() { + try { + send(new Data.Builder(DataCodes.Server.CLOSE)); + logger.info(loggerInfo("close")); + } catch (IOException e) { + logger.warn(loggerWarning("close"), e); + } + } + + public void unexpectedError() { + try { + send(new Data.Builder(DataCodes.Server.UNEXPECTEDERROR)); + logger.info(loggerInfo("unexpected error")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected error")); + } + } + + public void unexpectedExit() { + try { + send(new Data.Builder(DataCodes.Server.UNEXPECTEDEXIT)); + logger.info(loggerInfo("unexpected exit")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected exit")); + } + } + + public static void publicKey(PublicKey publicKey, DataOutputStream dataOutputStream, Logger logger) { + try { + Data.Builder data = new Data.Builder(DataCodes.Server.PUBLICKEY); + data.addData(DataCodes.Params.Key.PUBLICKEY, Base64.getEncoder().encodeToString(publicKey.getEncoded())); + + dataOutputStream.writeUTF(data.getDataAsString() + "\n"); + dataOutputStream.flush(); + + logger.info("Send public key data"); + } catch (IOException e) { + logger.warn("Failed to send public key data"); + } + } + + public static void ready(DataOutputStream dataOutputStream, Logger logger) { + try { + dataOutputStream.writeUTF(new Data.Builder(DataCodes.Server.READY).getDataAsString() + "\n"); + dataOutputStream.flush(); + + logger.info("Send ready data"); + } catch (IOException e) { + logger.warn("Failed to send ready data", e); + } + } + + public void userNotLoggedIn() { + try { + send(new Data.Builder(DataCodes.Server.NOTLOGGEDIN)); + logger.info(loggerInfo("user not logged in")); + } catch (IOException e) { + logger.warn(loggerWarning("user not logged in")); + } + } + + //----- update -----// + + public void firstConnectResult(boolean validAgent, boolean update) { + Data.Builder data = new Data.Builder(DataCodes.Server.FIRSTCONNECT); + data.addData(DataCodes.Params.ClientAgent.VALIDAGENT, String.valueOf(validAgent)); + data.addData(DataCodes.Params.Update.UPDATE, String.valueOf(update)); + + try { + send(data); + logger.info(loggerInfo("first connect result")); + } catch (IOException e) { + logger.warn(loggerWarning("first connect result"), e); + } + } + + public void requestArtificeUIOptionalUpdate(TheosUIVersion version, String changes) { + Data.Builder data = new Data.Builder(DataCodes.Server.OPTIONALUPDATE); + data.addData(DataCodes.Params.Update.NEWVERSION, version.toString()); + data.addData(DataCodes.Params.Update.CHANGES, changes); + + try { + send(data); + logger.info(loggerInfo("request ArtificeUI optional update")); + } catch (IOException e) { + logger.warn(loggerWarning("request ArtificeUI optional update")); + } + } + + public void requestArtificeUIRequiredUpdate(TheosUIVersion version, String changes) { + Data.Builder data = new Data.Builder(DataCodes.Server.REQUIREDUPDATE); + data.addData(DataCodes.Params.Update.NEWVERSION, version.toString()); + data.addData(DataCodes.Params.Update.CHANGES, changes); + + try { + send(data); + logger.info(loggerInfo("request ArtificeUI required update")); + } catch (IOException e) { + logger.warn(loggerWarning("request ArtificeUI required update")); + } + } + + //----- login / register -----// + + public void loginFailed() { + try { + send(new Data.Builder(DataCodes.Server.LOGINFAIL)); + logger.info(loggerInfo("login fail")); + } catch (IOException e) { + logger.warn(loggerWarning("login fail")); + } + } + + public void loginSuccess() { + try { + send(new Data.Builder(DataCodes.Server.LOGINSUCCESS)); + logger.info(loggerInfo("login success")); + } catch (IOException e) { + logger.warn(loggerWarning("login success")); + } + } + + public void registerCodeExist() { + try { + send(new Data.Builder(DataCodes.Server.REGISTERCODE_EXIST)); + logger.info(loggerInfo("register code exist")); + } catch (IOException e) { + logger.warn(loggerWarning("register code exist")); + } + } + + public void registerCodeNotExist() { + try { + send(new Data.Builder(DataCodes.Server.REGISTERCODE_NOT_EXIST)); + logger.info(loggerInfo("register code not exist")); + } catch (IOException e) { + logger.warn(loggerWarning("register code not exist")); + } + } + + public void registerFailed() { + try { + send(new Data.Builder(DataCodes.Server.REGISTERFAIL)); + logger.info(loggerInfo("register fail")); + } catch (IOException e) { + logger.warn(loggerWarning("register fail")); + } + } + + public void registerFailed_UserExist() { + try { + send(new Data.Builder(DataCodes.Server.REGISTERFAIL_USER_EXIST)); + logger.info(loggerInfo("register fail, user exist")); + } catch (IOException e) { + logger.warn(loggerWarning("register fail, user exist")); + } + } + + public void registerSuccess() { + try { + send(new Data.Builder(DataCodes.Server.REGISTERSUCCESS)); + System.out.println(new Data.Builder(DataCodes.Server.REGISTERSUCCESS).getDataAsString()); + logger.info(loggerInfo("register success")); + } catch (IOException e) { + logger.warn(loggerWarning("register success")); + } + } + + + //----- filesData ----// + + public void filesData(String UUID, File startDirectory) { + Data.Builder data = new Data.Builder(DataCodes.Server.SENDFILESDATA); + + String file; + File[] files = startDirectory.listFiles(); + int userDirectoryLength = new ServerFiles.user_files(UUID).user_files_dir.length(); + + for (int i = 0; i < files.length; i++) { + file = startDirectory.getAbsolutePath() + "/" + files[i].getName(); + + if (files[i].isDirectory()) { + data.addData("d" + i, file.substring(userDirectoryLength)); + } else { + data.addData("f" + SizeUnit.BYTES(files[i].length()).toMegabyte() + "MB", file.substring(userDirectoryLength)); + } + } + + try { + send(data); + logger.info("Send files data"); + } catch (IOException e) { + logger.warn("Failed to send user files data"); + } + } + + public void receiveFile(String file, byte[] privateKey) { + FileReceiver fileReceiver = new FileReceiver(client, new File(file), privateKey, logger); + + Executors.newSingleThreadExecutor().execute(() -> { + try { + try { + String md5CheckSum = fileReceiver.main(); + } catch (UnexpectedException e) { + logger.warn("An unexpected io exception occurred", e); + } catch (IllegalBlockSizeException | InvalidKeyException | InvalidKeySpecException | BadPaddingException | NoSuchPaddingException e) { + logger.warn("An unexpected exception occurred"); + } + logger.info("Received file " + file); + receiveFileSuccess(); + } catch (IOException e) { + logger.warn("Failed to receive file " + file); + e.printStackTrace(); + } + }); + } + + public void receiveFileFailed() { + try { + send(new Data.Builder(DataCodes.Server.RECEIVEFILEFAIL)); + logger.info(loggerInfo("receive file fail")); + } catch (IOException e) { + logger.warn(loggerWarning("receive file fail")); + } + } + + public void receiveFileSuccess() { + try { + send(new Data.Builder(DataCodes.Server.RECEIVEFILESUCCESS)); + logger.info(loggerInfo("receive file success")); + } catch (IOException e) { + logger.warn(loggerWarning("receive file success")); + } + } + + public void sendFile(File file, byte[] publicKey) { + FileSender fileSender = new FileSender(client, file, publicKey, logger); + + Executors.newSingleThreadExecutor().execute(() -> { + try { + String md5CheckSum = null; + try { + md5CheckSum = fileSender.main(); + } catch (UnexpectedException e) { + logger.warn("An unexpected io exception occurred", e); + } catch (BadPaddingException | IllegalBlockSizeException | InvalidKeySpecException | InvalidKeyException e) { + logger.warn("An unexpected exception occurred"); + } + logger.info("Send file " + file); + sendFileSuccess(md5CheckSum); + } catch (IOException e) { + logger.warn("Failed to send file " + file.getAbsolutePath()); + e.printStackTrace(); + sendFileFailed(); + } + }); + } + + public void sendFileFailed() { + try { + send(new Data.Builder(DataCodes.Server.SENDFILEFAIL)); + logger.info(loggerInfo("send file data")); + } catch (IOException e) { + logger.warn(loggerWarning("send file fail")); + } + } + + public void sendFileSuccess(String checkSum) { + try { + Data.Builder data = new Data.Builder(DataCodes.Server.SENDFILESSUCCESS); + data.addData(DataCodes.Params.CheckSum.MD5, checkSum); + send(data); + logger.info(loggerInfo("send file success")); + } catch (IOException e) { + logger.warn(loggerWarning("send file success")); + } + } +} diff --git a/src/org/blueshard/olymp/server/MainServer.java b/src/org/blueshard/olymp/server/MainServer.java new file mode 100644 index 0000000..55c83f4 --- /dev/null +++ b/src/org/blueshard/olymp/server/MainServer.java @@ -0,0 +1,345 @@ +package org.blueshard.olymp.server; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.blueshard.olymp.Main; +import org.blueshard.olymp.data.Data; +import org.blueshard.olymp.data.DataCodes; +import org.blueshard.olymp.e2ee.E2EEConverter; +import org.blueshard.olymp.exception.*; +import org.blueshard.olymp.logging.ClientLogger; +import org.blueshard.olymp.register_code.RegisterCode; +import org.blueshard.olymp.user.User; +import org.blueshard.olymp.utils.ExceptionUtils; +import org.blueshard.olymp.version.TheosUIVersion; + +import javax.net.ServerSocketFactory; +import java.io.*; +import java.lang.reflect.Field; +import java.net.ServerSocket; +import java.net.SocketException; +import java.security.GeneralSecurityException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashSet; +import java.util.concurrent.Executors; + +public class MainServer { + + private final int port; + private final Logger logger; + + private ServerSocket serverSocket = null; + private ClientFactory clientFactory = new ClientFactory(); + + public MainServer(int port, Logger logger) { + this.port = port; + this.logger = logger; + } + + public void start() { + try { + serverSocket = ServerSocketFactory.getDefault().createServerSocket(port); + } catch (IOException e) { + logger.fatal("Couldn't create server"); + e.printStackTrace(); + return; + } + logger.info("Start server"); + + logger.info("Server infos: " + serverSocket.toString()); + + while (true){ + ClientFactory.Client client; + try { + client = clientFactory.createNewClient(serverSocket.accept(), null); + } catch (IOException e) { + logger.error("Couldn't connect to new client"); + e.printStackTrace(); + return; + } + + logger.info("New Client connected - ID: " + client.getId()); + try { + Executors.newSingleThreadExecutor().execute(() -> { + try { + boolean notLoggedIn = true; + Data inputData; + Logger clientLogger = null; + User user = null; + + byte[] clientPublicKey; + + if (client.getInetAddress().getHostAddress().equals("127.0.0.1")) { + logger.info("Localhost connected"); + DataInputStream dataInputStream = new DataInputStream(client.getInputStream()); + DataOutputStream dataOutputStream = new DataOutputStream(client.getOutputStream()); + String connectionType = dataInputStream.readUTF().strip().toLowerCase(); + switch (connectionType) { + case "sql": + logger.info("Localhost acts in SQL mode"); + Connection connection = Main.getConnection(); + StringBuilder resultData = new StringBuilder(); + ResultSetMetaData resultSetMetaData; + String input; + + while (true) { + try { + input = dataInputStream.readUTF().replaceAll("\\s{2,}", " ").strip(); + if (input.toLowerCase().equals("exit")) { + logger.info("Localhost exit sql mode"); + break; + } else if (input.toLowerCase().startsWith("add register code")) { + String times = input.toLowerCase().substring("add register code".length() - 1); + if (times.isBlank()) { + String registerCode = RegisterCode.generateNewRegisterCode(); + logger.info("Localhost generated a new register code ('" + registerCode + "')"); + dataOutputStream.writeUTF(registerCode); + } else { + StringBuilder stringBuilder = new StringBuilder(); + int intTimes; + try { + intTimes = Integer.parseInt(times); + } catch (NumberFormatException e) { + logger.warn("'" + times + "' is not a valid number", e); + dataOutputStream.writeUTF(ExceptionUtils.extractExceptionMessage(e)); + continue; + } + for (int i = 1; i < intTimes + 1; i++) { + stringBuilder.append(RegisterCode.generateNewRegisterCode()).append("\n"); + } + logger.info("Localhost generated a new register codes ('" + stringBuilder.toString() + "')"); + dataOutputStream.writeUTF(stringBuilder.toString()); + } + } else if (input.toLowerCase().startsWith("all register codes")) { + HashSet allRegisterCodes = RegisterCode.getAllRegisterCodes(); + logger.info("Localhost got all register codes"); + dataOutputStream.writeUTF(Arrays.toString(allRegisterCodes.toArray(new String[allRegisterCodes.size()]))); + } else if (input.toLowerCase().startsWith("is register code")) { + String registerCode = input.toLowerCase().substring("is register code".length() - 1); + boolean isRegisterCode = RegisterCode.isRegisterCode(registerCode); + logger.info("Localhost checked register code '" + registerCode + "' for it's validity (" + isRegisterCode + ")"); + dataOutputStream.writeUTF(String.valueOf(isRegisterCode)); + } else if (input.toLowerCase().startsWith("remove register code")) { + String registerCode = input.toLowerCase().substring("remove register code".length() - 1); + RegisterCode.removeRegisterCode(registerCode); + logger.info("Localhost removed register code '" + registerCode + "'"); + } else { + logger.info("Localhost send following SQL query: '" + input + "'"); + try { + ResultSet resultSet = connection.createStatement().executeQuery(input); + logger.info("SQL query from localhost executed successfully"); + while (resultSet.next()) { + resultSetMetaData = resultSet.getMetaData(); + for (int i = 1; i < resultSetMetaData.getColumnCount() + 1; i++) { + resultData.append(resultSetMetaData.getColumnName(i)).append(resultSet.getString(i)).append("\n"); + } + } + dataOutputStream.writeUTF(resultData.toString()); + logger.info("Sent SQL query result set"); + } catch (SQLException e) { + logger.warn("SQL query from localhost caused an error", e); + dataOutputStream.writeUTF(e.getSQLState()); + } + resultData.delete(0, resultData.length()); + } + } catch (FatalIOException e) { + logger.fatal("Fatal IO Exception occurred (" + ExceptionUtils.errorNumberToString(e.getErrno()) + ")", e); + dataOutputStream.writeUTF("Fatal IO Exception occurred (" + ExceptionUtils.errorNumberToString(e.getErrno()) + ")\n" + ExceptionUtils.extractExceptionMessage(e)); + } + } + break; + } + client.close(); + logger.info("Localhost disconnected"); + return; + } + + while (true) { + String clientData = new DataInputStream(client.getInputStream()).readUTF(); + + if (Data.isDataString(clientData)) { + if (new Data(clientData).getCode() == DataCodes.Client.PUBLICKEY) { + clientPublicKey = Base64.getDecoder().decode(new Data(clientData).getFromData(DataCodes.Params.Key.PUBLICKEY)); + logger.info("Received client public key"); + break; + } else { + logger.info("Client send invalid data"); + } + } else { + logger.info("Client send invalid data"); + } + } + + byte[] privateKey = Action.publicKey(client.getOutputStream(), logger).getEncoded(); + + ClientSender clientSender; + try { + clientSender = new ClientSender(client, clientPublicKey, logger); + } catch (GeneralSecurityException ignore) { + return; + } + Action action = new Action(null, clientSender); + + String agent = null; + String update = null; + TheosUIVersion version = null; + + try { + Data data = new Data(E2EEConverter.decrypt(new DataInputStream(client.getInputStream()).readUTF(), privateKey)); + String clientAgent = data.getFromData(DataCodes.Params.ClientAgent.CLIENTAGENT); + + if (clientAgent.equals(DataCodes.Params.ClientAgent.THEOSUI)) { + client.setClientAgent(clientAgent); + agent = DataCodes.Params.ClientAgent.THEOSUI; + version = new TheosUIVersion(data.getFromData(DataCodes.Params.Version.VERSION)); + + if (version.hasRequiredUpdate()) { + logger.info("Client has a deprecated TheosUI version"); + update = "r"; + } else if (version.hasOptionalUpdate()) { + logger.info("Client has a deprecated TheosUI version"); + update = "o"; + } + } else { + logger.error("Client use an invalid client agent, connection get closed"); + } + } catch (GeneralSecurityException | IllegalAccessException ignore) { + } + + action.firstConnectionResult(agent != null, update != null); + + if (agent == null) { + clientSender.close(); + client.close(); + return; + } + + if (update != null && agent.equals(DataCodes.Params.ClientAgent.THEOSUI)) { + if (update.equals("r")) { + action.requestArtificeUIRequiredUpdate(version); + } else if (update.equals("o")) { + action.requestArtificeUIOptionalUpdate(version); + } + } + + while (notLoggedIn) { + try { + inputData = new Data(E2EEConverter.decrypt(new DataInputStream(client.getInputStream()).readUTF(), privateKey)); + } catch (IOException | GeneralSecurityException e) { + clientSender.unexpectedError(); + return; + } + action.refreshData(inputData); + + switch (inputData.getCode()) { + case DataCodes.Client.CLOSE: + case DataCodes.Client.UNEXPECTEDEXIT: + return; + + case DataCodes.Client.REGISTERCODE: + action.isRegisterCode(); + break; + + case DataCodes.Client.LOGIN: + try { + user = action.login(); + if (String.valueOf(user.getLogLevel()).equals(DataCodes.Params.LogLevel.ALL)) { + clientLogger = new ClientLogger(client, Level.ALL).getLogger(); + } else if (String.valueOf(user.getLogLevel()).equals(DataCodes.Params.LogLevel.WARNING)) { + clientLogger = new ClientLogger(client, Level.WARN).getLogger(); + } else { + clientLogger = new ClientLogger(client, Level.OFF).getLogger(); + } + logger.info("New Client details - IP: " + client.getIPAddress() + "\n" + + "Port: " + client.getPort()); + + logger.info("Logged in successfully"); + notLoggedIn = false; + } catch (IOException | UserNotExistException | IllegalPasswordException e) { + clientSender.loginFailed(); + logger.warn("Login failed", e); + } catch (IllegalCodeException e) { + clientSender.unexpectedError(); + logger.warn("An unexpected error occurred", e); + } + break; + + case DataCodes.Client.REGISTER: + try { + user = action.register(); + clientLogger = new ClientLogger(client, Level.OFF).getLogger(); + logger.info("Registered in successfully"); + notLoggedIn = false; + } catch (IOException e) { + clientSender.registerFailed(); + logger.warn("Register failed", e); + } catch (UserAlreadyExistException e) { + clientSender.registerFailed_UserExist(); + logger.warn("Couldn't register, user already exist", e); + } catch (RegisterCodeNotExistException e) { + clientSender.registerCodeNotExist(); + logger.warn("Couldn't register, given register code do not exist"); + } + break; + default: + clientSender.userNotLoggedIn(); + logger.warn("User isn't logged in"); + break; + } + } + int resultCode = new ClientReceiver(user, client, clientSender, clientPublicKey, privateKey, clientLogger).main(); + if (resultCode == ClientReceiver.ResultCodes.EXIT) { + client.close(); + logger.info("Closed connection to client"); + } else if (resultCode == ClientReceiver.ResultCodes.UNEXPECTEDEXIT) { + client.close(); + logger.warn("Unexpected closed the connection to client"); + } + + } catch (SocketException e) { + logger.error("Socket Exception for client " + client.getId() + " occurred", e); + } catch (IOException e) { + logger.error("IO Exception for client " + client.getId() +" occurred", e); + } catch (FatalIOException e) { + String name; + int errno; + ErrorCodes errorCodes = new ErrorCodes(); + Field[] fields = ErrorCodes.class.getFields(); + + for (Field field : fields) { + try { + name = field.getName(); + errno = (int) field.get(errorCodes); + if (errno == e.getErrno()) { + logger.fatal("Fatal IOException occurred while login or register - Errno: " + e.getErrno() + " (" + name + ")", e); + return; + } + } catch (IllegalAccessException illegalAccessException) { + illegalAccessException.printStackTrace(); + } + } + logger.error("Fatal IOException occurred while login or register - Errno: " + e.getErrno(), e); + } catch (UnexpectedException e) { + e.printStackTrace(); + } + }); + } catch (Exception e) { + StringWriter stringWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(stringWriter)); + logger.error("An unexpected error occurred: " + stringWriter, e); + } + } + + } + + public void close() throws IOException { + serverSocket.close(); + logger.info("Closed server"); + } + +} diff --git a/src/org/blueshard/olymp/sql/SQL.java b/src/org/blueshard/olymp/sql/SQL.java new file mode 100644 index 0000000..0980e01 --- /dev/null +++ b/src/org/blueshard/olymp/sql/SQL.java @@ -0,0 +1,39 @@ +package org.blueshard.olymp.sql; + +import org.blueshard.olymp.Main; + +import java.sql.*; + +public class SQL { + + private Connection connection = null; + + public SQL () { + try { + Class.forName("org.hsqldb.jdbcDriver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return; + } + + try { + connection = DriverManager.getConnection("jdbc:hsqldb:file:/srv/hsqldb/olympdb/olympdb", "OLYMP", "&C=@zFR7kLQvGy%e"); + } catch (SQLException e) { + e.printStackTrace(); + return; + } + } + + public void close() throws SQLException { + connection.close(); + } + + public Connection getConnection() { + return connection; + } + + public static void checkpoint() throws SQLException { + Main.getConnection().createStatement().execute("CHECKPOINT"); + } + +} diff --git a/src/org/blueshard/olymp/sql/SQLPosition.java b/src/org/blueshard/olymp/sql/SQLPosition.java new file mode 100644 index 0000000..52116c6 --- /dev/null +++ b/src/org/blueshard/olymp/sql/SQLPosition.java @@ -0,0 +1,22 @@ +package org.blueshard.olymp.sql; + +public class SQLPosition { + + public static class USERS { + + public static final int UUID = 1; + public static final int USERNAME = 2; + public static final int PASSWORD = 3; + public static final int SALT = 4; + public static final int MAIL = 5; + public static final int ACTIVE = 6; + public static final int USERLEVEL = 7; + public static final int LOGLEVEL = 8; + public static final int MAX_FILES = 9; + public static final int FILES = 10; + public static final int MAX_FILES_SIZE = 11; + public static final int FILES_SIZE = 12; + + } + +} diff --git a/src/org/blueshard/olymp/user/User.java b/src/org/blueshard/olymp/user/User.java new file mode 100644 index 0000000..0542f65 --- /dev/null +++ b/src/org/blueshard/olymp/user/User.java @@ -0,0 +1,146 @@ +package org.blueshard.olymp.user; + +import org.blueshard.olymp.Main; +import org.blueshard.olymp.exception.*; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.register_code.RegisterCode; +import org.blueshard.olymp.security.Password; +import org.blueshard.olymp.sql.SQL; +import org.blueshard.olymp.sql.SQLPosition; +import org.blueshard.olymp.utils.*; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.sql.*; +import java.util.*; + +public class User extends UserInfos { + + private Password.PasswordInfos passwordInfos; + + public User(String UUID) throws UserNotExistException, FatalIOException { + super(UUID); + + if (!isUser(UUID)){ + throw new UserNotExistException(UUID, "The user " + UUID + " doesn't exists"); + } + + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("SELECT PASSWORD, SALT FROM USERS WHERE (UUID = ?)"); + + preparedStatement.setString(1, UUID); + + ResultSet resultSet = preparedStatement.executeQuery(); + + if (resultSet.next()) { + passwordInfos = new Password.PasswordInfos(Base64.getDecoder().decode(resultSet.getString(1)), Base64.getDecoder().decode(resultSet.getString(2))); + } + } catch (SQLException e) { + e.printStackTrace(); + throw new FatalIOException(ErrorCodes.couldnt_get_user_information, "Couldn't get user information for user " + UUID, e); + } + } + + public boolean equalsPassword(String clearPassword) throws InvalidKeySpecException { + return Password.createPassword(clearPassword, passwordInfos.getSaltAsBytes()).getPasswordAsString().equals(passwordInfos.getPasswordAsString()); + } + + public static User createNewUser(String registerCode, String username, String password, String salt, String mailAddress) throws FatalIOException, UserAlreadyExistException, RegisterCodeNotExistException { + if (isUser(username)) { + throw new UserAlreadyExistException(username, "The user " + username + " already exists"); + } + + if (!RegisterCode.isRegisterCode(registerCode)) { + throw new RegisterCodeNotExistException(registerCode); + } + + String uuid = UUID.randomUUID().toString(); + + File userDirectory = new File(new ServerFiles.user_files(uuid).user_files_dir); + if (!userDirectory.mkdir()) { + throw new FatalIOException(ErrorCodes.couldnt_create_userfiles_folder, "Couldn't create " + new ServerFiles.user_files(uuid).user_files_dir); + } + + //--------------------------------------------------------------------------------------// + + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("INSERT INTO USERS (UUID, USERNAME, PASSWORD, SALT, EMAIL) VALUES (?, ?, ?, ?, ?)"); + + preparedStatement.setString(1, uuid); + preparedStatement.setString(2, username); + preparedStatement.setString(3, password); + preparedStatement.setString(4, salt); + preparedStatement.setString(5, mailAddress); + + preparedStatement.executeUpdate(); + + SQL.checkpoint(); + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_create_user_information, "Failed to add new user", e); + } + + RegisterCode.removeRegisterCode(registerCode); + + try { + return new User(username); + } catch (UserNotExistException e) { + //shouldn't get thrown + return null; + } + + } + + public static void deleteUser(String UUID) throws FatalIOException, IOException { + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("DELETE FROM USERS WHERE UUID = ?"); + + preparedStatement.setString(1, UUID); + + preparedStatement.executeUpdate(); + + SQL.checkpoint(); + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_delete_user_information, "Couldn't delete user information for user " + UUID, e); + } + + File file; + ArrayList customUserFiles = FileUtils.getAllFilesInDirectory(new ServerFiles.user_files(UUID).user_files_dir); + ListIterator customUserFileListIterator = customUserFiles.listIterator(customUserFiles.size()); + + while(customUserFileListIterator.hasPrevious()) { + file = customUserFileListIterator.previous(); + + if (!file.delete()) { + if (file.isDirectory()) { + throw new FatalIOException(ErrorCodes.couldnt_delete_custom_user_directory, "Couldn't delete custom user folder " + file.getAbsolutePath()); + } else { + throw new FatalIOException(ErrorCodes.couldnt_delete_custom_user_file, "Couldn't delete custom user file " + file.getAbsolutePath()); + } + } + } + + } + + public static boolean isUser(String UUID) throws FatalIOException { + try { + Statement statement = Main.getConnection().createStatement(); + + ResultSet resultSet = statement.executeQuery("SELECT UUID FROM USERS"); + + while (resultSet.next()) { + if (resultSet.getString(1).equals(UUID)) { + return true; + } + } + resultSet.close(); + + return false; + } catch (SQLException e) { + throw new FatalIOException(ErrorCodes.couldnt_get_user_information, "Couldn't get all usernames", e); + } + } + +} diff --git a/src/org/blueshard/olymp/user/UserInfos.java b/src/org/blueshard/olymp/user/UserInfos.java new file mode 100644 index 0000000..2ad32b2 --- /dev/null +++ b/src/org/blueshard/olymp/user/UserInfos.java @@ -0,0 +1,112 @@ +package org.blueshard.olymp.user; + +import org.blueshard.olymp.Main; +import org.blueshard.olymp.exception.ErrorCodes; +import org.blueshard.olymp.exception.FatalIOException; +import org.blueshard.olymp.files.ConfReader; +import org.blueshard.olymp.files.ConfWriter; +import org.blueshard.olymp.files.ServerFiles; +import org.blueshard.olymp.security.Password; +import org.blueshard.olymp.sql.SQL; +import org.blueshard.olymp.sql.SQLPosition; + +import java.io.*; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Base64; +import java.util.TreeMap; + +public class UserInfos { + + private final String UUID; + private String username; + private Password.PasswordInfos passwordInfos; + private String mail; + private boolean active; + private int userLevel; + private int logLevel; + private long maxFiles; + private long files; + private double maxFilesSize; + private double filesSize; + + public UserInfos(String UUID) throws FatalIOException { + try { + PreparedStatement preparedStatement = Main.getConnection().prepareStatement("SELECT * FROM USERS WHERE (UUID = ?)"); + + preparedStatement.setString(1, UUID); + + ResultSet resultSet = preparedStatement.executeQuery(); + + if (resultSet.next()) { + this.UUID = UUID; + this.username = resultSet.getString(SQLPosition.USERS.USERNAME); + this.passwordInfos = new Password.PasswordInfos(Base64.getDecoder().decode(resultSet.getString(SQLPosition.USERS.PASSWORD)), + Base64.getDecoder().decode(resultSet.getString(SQLPosition.USERS.SALT))); + this.mail = resultSet.getString(SQLPosition.USERS.MAIL); + this.active = resultSet.getBoolean(SQLPosition.USERS.ACTIVE); + this.userLevel = resultSet.getInt(SQLPosition.USERS.USERLEVEL); + this.logLevel = resultSet.getInt(SQLPosition.USERS.LOGLEVEL); + this.maxFiles = resultSet.getLong(SQLPosition.USERS.MAX_FILES); + this.files = resultSet.getLong(SQLPosition.USERS.FILES); + this.maxFilesSize = resultSet.getDouble(SQLPosition.USERS.MAX_FILES_SIZE); + this.filesSize = resultSet.getDouble(SQLPosition.USERS.FILES_SIZE); + } else { + throw new FatalIOException(ErrorCodes.couldnt_get_user_information, "Couldn't get user information for user " + UUID); + } + } catch (SQLException e) { + e.printStackTrace(); + throw new FatalIOException(ErrorCodes.couldnt_get_user_information, "Couldn't get user information for user " + UUID, e); + } + } + + public String getUUID() { + return UUID; + } + + public String getUsername() { + return username; + } + + public Password.PasswordInfos getPasswordInfos() { + return passwordInfos; + } + + public String getMail() { + return mail; + } + + public boolean getActive() { + return active; + } + + public int getUserLevel() { + return userLevel; + } + + public int getLogLevel() { + return logLevel; + } + + public long getMaxFiles() { + return maxFiles; + } + + public long getFiles() { + return files; + } + + public double getMaxFilesSize() { + return maxFilesSize; + } + + public double getFilesSize() { + return filesSize; + } + + public String getUserfileDirectory() { + return new ServerFiles.user_files(getUUID()).user_files_dir; + } + +} diff --git a/src/org/blueshard/olymp/userfiles/empty b/src/org/blueshard/olymp/userfiles/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/src/org/blueshard/olymp/userfiles/empty @@ -0,0 +1 @@ +#empty diff --git a/src/org/blueshard/olymp/utils/ConsoleColors.java b/src/org/blueshard/olymp/utils/ConsoleColors.java new file mode 100644 index 0000000..a9a80a2 --- /dev/null +++ b/src/org/blueshard/olymp/utils/ConsoleColors.java @@ -0,0 +1,76 @@ +package org.blueshard.olymp.utils; + +public class ConsoleColors { + // Reset + public static final String RESET = "\033[0m"; // Text Reset + + // Regular Colors + public static final String BLACK = "\033[0;30m"; // BLACK + public static final String RED = "\033[0;31m"; // RED + public static final String GREEN = "\033[0;32m"; // GREEN + public static final String YELLOW = "\033[0;33m"; // YELLOW + public static final String BLUE = "\033[0;34m"; // BLUE + public static final String PURPLE = "\033[0;35m"; // PURPLE + public static final String CYAN = "\033[0;36m"; // CYAN + public static final String WHITE = "\033[0;37m"; // WHITE + + // Bold + public static final String BLACK_BOLD = "\033[1;30m"; // BLACK + public static final String RED_BOLD = "\033[1;31m"; // RED + public static final String GREEN_BOLD = "\033[1;32m"; // GREEN + public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW + public static final String BLUE_BOLD = "\033[1;34m"; // BLUE + public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE + public static final String CYAN_BOLD = "\033[1;36m"; // CYAN + public static final String WHITE_BOLD = "\033[1;37m"; // WHITE + + // Underline + public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK + public static final String RED_UNDERLINED = "\033[4;31m"; // RED + public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN + public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW + public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE + public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE + public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN + public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE + + // Background + public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK + public static final String RED_BACKGROUND = "\033[41m"; // RED + public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN + public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW + public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE + public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE + public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN + public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + + // High Intensity + public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK + public static final String RED_BRIGHT = "\033[0;91m"; // RED + public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN + public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW + public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE + public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE + public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN + public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE + + // Bold High Intensity + public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK + public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED + public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN + public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW + public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE + public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE + public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN + public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE + + // High Intensity backgrounds + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE +} diff --git a/src/org/blueshard/olymp/utils/ExceptionUtils.java b/src/org/blueshard/olymp/utils/ExceptionUtils.java new file mode 100644 index 0000000..467094c --- /dev/null +++ b/src/org/blueshard/olymp/utils/ExceptionUtils.java @@ -0,0 +1,38 @@ +package org.blueshard.olymp.utils; + +import org.blueshard.olymp.exception.ErrorCodes; + +import java.lang.reflect.Field; +import java.util.Arrays; + +public class ExceptionUtils { + + public static String errorNumberToString(int errorNumber) { + String name; + int errno; + ErrorCodes errorCodes = new ErrorCodes(); + Field[] fields = ErrorCodes.class.getFields(); + + for (Field field : fields) { + try { + name = field.getName(); + errno = (int) field.get(errorCodes); + if (errno == errorNumber) { + return name; + } + } catch (IllegalAccessException illegalAccessException) { + illegalAccessException.printStackTrace(); + } + } + return null; + } + + public static String extractExceptionMessage(Throwable throwable) { + StringBuilder stringBuilder = new StringBuilder(); + + Arrays.asList(throwable.getStackTrace()).forEach(stackTraceElement -> stringBuilder.append(stackTraceElement).append("\n")); + + return stringBuilder.toString(); + } + +} diff --git a/src/org/blueshard/olymp/utils/FileUtils.java b/src/org/blueshard/olymp/utils/FileUtils.java new file mode 100644 index 0000000..9954864 --- /dev/null +++ b/src/org/blueshard/olymp/utils/FileUtils.java @@ -0,0 +1,70 @@ +package org.blueshard.olymp.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; + +public class FileUtils { + + public static ArrayList getAllFilesInDirectory(String path) throws IOException { + ArrayList files = new ArrayList<>(); + Files.walk(Paths.get(path)).map(Path::toFile).forEach(files::add); + return files; + } + + public static File[] sortFilesInDirectory(File path) { + File[] files = path.listFiles(); + + Arrays.sort(files, (object1, object2) -> object1.getName().compareToIgnoreCase(object2.getName())); + + return files; + } + + public class CreateHashSum { + + String file; + + CreateHashSum(String file) { + this.file = file; + } + + public String MD5() throws IOException { + try { + StringBuilder hexString = new StringBuilder(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + + InputStream inputStream = Files.newInputStream(Paths.get(file)); + byte[] buffer = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + md5.update(buffer, 0 , length); + } + + byte[] digest = md5.digest(); + + for (byte b : digest) { + if ((0xff & b) < 0x10) { + hexString.append("0").append(Integer.toHexString((0xFF & b))); + } else { + hexString.append(Integer.toHexString(0xFF & b)); + } + } + + return hexString.toString(); + + } catch (NoSuchAlgorithmException ignore) { + return null; + } + } + + } + +} diff --git a/src/org/blueshard/olymp/utils/SizeUnit.java b/src/org/blueshard/olymp/utils/SizeUnit.java new file mode 100644 index 0000000..d1985b3 --- /dev/null +++ b/src/org/blueshard/olymp/utils/SizeUnit.java @@ -0,0 +1,196 @@ +package org.blueshard.olymp.utils; + +public class SizeUnit { + + private int unit; + private double size; + + private final static int BYTE = 1; + private final static int KILOBYTE = 3; + private final static int MEGABYTE = 5; + private final static int GIGABYTE = 7; + private final static int TERRABYTE = 9; + private final static int PETABYTE = 11; + private final static int EXABYTE = 13; + + SizeUnit(int unit, double size){ + this.unit = unit; + this.size = size; + } + + public static SizeUnit BYTES(double bytes){ + return new SizeUnit(BYTE, bytes); + } + + public static SizeUnit KILOBYTE(double kilobytes) { + return new SizeUnit(KILOBYTE, kilobytes); + } + + public static SizeUnit MEGABYTE(double megabytes) { + return new SizeUnit(MEGABYTE, megabytes); + } + + public static SizeUnit GIGABYTE(double gigabytes) { + return new SizeUnit(GIGABYTE, gigabytes); + } + + public static SizeUnit TERRABYTE(double terrabytes) { + return new SizeUnit(TERRABYTE, terrabytes); + } + + public static SizeUnit PETABYTE(double petabytes) { + return new SizeUnit(PETABYTE, petabytes); + } + + public static SizeUnit EXABYTE(double exabytes) { + return new SizeUnit(EXABYTE, exabytes); + } + + public Double toByte(){ + switch (unit) { + case BYTE: + return size; + case KILOBYTE: + return size * 1000; + case MEGABYTE: + return size * 1000000; + case GIGABYTE: + return size * 1000000000; + case TERRABYTE: + return size * 1000000000000L; + case PETABYTE: + return size * 1000000000000000L; + case EXABYTE: + return size * 1000000000000000000L; + default: + return 0D; + } + } + + public Double toKilobyte(){ + switch (unit) { + case BYTE: + return size / 1000; + case KILOBYTE: + return size; + case MEGABYTE: + return size * 1000; + case GIGABYTE: + return size * 1000000; + case TERRABYTE: + return size * 1000000000; + case PETABYTE: + return size * 1000000000000L; + case EXABYTE: + return size * 1000000000000000L; + default: + return 0D; + } + } + + public Double toMegabyte(){ + switch (unit) { + case BYTE: + return size / 1000000; + case KILOBYTE: + return size / 1000; + case MEGABYTE: + return size; + case GIGABYTE: + return size * 1000; + case TERRABYTE: + return size * 1000000; + case PETABYTE: + return size * 1000000000; + case EXABYTE: + return size * 1000000000000L; + default: + return 0D; + } + } + + public Double toGigabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000L; + case KILOBYTE: + return size / 1000000; + case MEGABYTE: + return size / 1000; + case GIGABYTE: + return size; + case TERRABYTE: + return size * 1000; + case PETABYTE: + return size * 1000000; + case EXABYTE: + return size * 1000000000; + default: + return 0D; + } + } + + public Double toTerrabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000L; + case KILOBYTE: + return size / 1000000000; + case MEGABYTE: + return size / 1000000; + case GIGABYTE: + return size / 1000; + case TERRABYTE: + return size; + case PETABYTE: + return size * 1000; + case EXABYTE: + return size * 1000000; + default: + return 0D; + } + } + + public Double toPetabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000000L; + case KILOBYTE: + return size / 1000000000000L; + case MEGABYTE: + return size / 1000000000; + case GIGABYTE: + return size / 1000000; + case TERRABYTE: + return size / 1000; + case PETABYTE: + return size; + case EXABYTE: + return size * 1000; + default: + return 0D; + } + } + + public Double toExabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000000000L; + case KILOBYTE: + return size / 1000000000000000L; + case MEGABYTE: + return size / 1000000000000L; + case GIGABYTE: + return size / 1000000000; + case TERRABYTE: + return size / 1000000; + case PETABYTE: + return size / 1000; + case EXABYTE: + return size; + default: + return 0D; + } + } + +} diff --git a/src/org/blueshard/olymp/utils/StringUtils.java b/src/org/blueshard/olymp/utils/StringUtils.java new file mode 100644 index 0000000..135ffc5 --- /dev/null +++ b/src/org/blueshard/olymp/utils/StringUtils.java @@ -0,0 +1,17 @@ +package org.blueshard.olymp.utils; + +import java.util.Map; + +public class StringUtils { + + public static String format(String string, Map formatMap){ + + for(Map.Entry entry: formatMap.entrySet()) { + string = string.replace("{" + entry.getKey() + "}", entry.getValue()); + } + + return string; + + } + +} diff --git a/src/org/blueshard/olymp/version/ServerVersion.java b/src/org/blueshard/olymp/version/ServerVersion.java new file mode 100644 index 0000000..f12228f --- /dev/null +++ b/src/org/blueshard/olymp/version/ServerVersion.java @@ -0,0 +1,40 @@ +package org.blueshard.olymp.version; + +public class ServerVersion extends Version { + + public ServerVersion(String version) { + super(version); + } + + @Override + public int toInt() { + switch (toString()) { + case "0.1.0": + return 1; + default: + return 0; + } + } + + public boolean higherThan(String version) { + return higherThan(new ServerVersion(version)); + } + + @Override + public boolean higherThan(Version version) { + return toInt() > version.toInt(); + } + + public boolean lowerThan(String version) { + return lowerThan(new ServerVersion(version)); + } + + @Override + public boolean lowerThan(Version version) { + return toInt() < version.toInt(); + } + public static ServerVersion currentVersion() { + return new ServerVersion("0.1.0"); + } + +} diff --git a/src/org/blueshard/olymp/version/TheosUIVersion.java b/src/org/blueshard/olymp/version/TheosUIVersion.java new file mode 100644 index 0000000..9c2d53b --- /dev/null +++ b/src/org/blueshard/olymp/version/TheosUIVersion.java @@ -0,0 +1,133 @@ +package org.blueshard.olymp.version; + +import org.blueshard.olymp.exception.ErrorCodes; +import org.blueshard.olymp.exception.FatalIOException; +import org.blueshard.olymp.files.ConfReader; +import org.blueshard.olymp.files.ServerFiles; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +public class TheosUIVersion extends Version { + + TreeMap versions; + Set versionsKeySet; + + public TheosUIVersion(String version) throws FatalIOException { + super(version); + + try { + versions = new ConfReader.MultipleConfReader(ServerFiles.etc.versions).getAll("TheosUI", true); + } catch (IOException e) { + throw new FatalIOException(ErrorCodes.couldnt_read_versions_conf, "Failed to read versions.conf", e); + } + + versionsKeySet = versions.keySet(); + } + + @Override + public int toInt() { + String[] allVersions = versionsKeySet.toArray(new String[versionsKeySet.size()]); + + for (int i = 0; i < allVersions.length; i++) { + if (allVersions[i].equals(toString())) { + return i + 1; + } + } + return 0; + } + + private int toInt(String version) { + String[] allVersions = versionsKeySet.toArray(new String[versionsKeySet.size()]); + + for (int i = 0; i < allVersions.length; i++) { + if (allVersions[i].equals(version)) { + return i + 1; + } + } + return 0; + } + + public boolean higherThan(String version) { + return toInt() > toInt(version); + } + + @Override + public boolean higherThan(Version version) { + return toInt() > toInt(version.toString()); + } + + public boolean lowerThan(String version) { + return toInt() < toInt(version); + } + + @Override + public boolean lowerThan(Version version) { + return toInt() < toInt(version.toString()); + } + + public String getChanges() { + return versions.get(toString()).split(":")[1]; + } + + public boolean hasOptionalUpdate() throws FatalIOException { + if (toInt() != currentVersion().toInt()) { + Map reverseVersions = versions.descendingMap(); + + for (Map.Entry stringStringEntry : reverseVersions.entrySet()) { + String key = stringStringEntry.getKey(); + String value = stringStringEntry.getValue().split(":")[0]; + if (!key.equals(toString())) { + if (value.equals("optional")) { + return true; + } + } else { + return false; + } + } + } + return false; + } + + public boolean hasRequiredUpdate() throws FatalIOException { + if (toInt() != currentVersion().toInt()) { + Map reverseVersions = versions.descendingMap(); + + for (Map.Entry stringStringEntry : reverseVersions.entrySet()) { + String key = stringStringEntry.getKey(); + String value = stringStringEntry.getValue().split(":")[0]; + if (!key.equals(toString())) { + if (value.equals("required")) { + return true; + } + } else { + return false; + } + } + } + return false; + } + + public static TheosUIVersion currentVersion() throws FatalIOException { + try { + return new TheosUIVersion(new ConfReader.MultipleConfReader(ServerFiles.etc.versions).getAll("TheosUI", true).lastKey()); + } catch (IOException e) { + throw new FatalIOException(ErrorCodes.couldnt_read_versions_conf, "Failed to read versions.conf", e); + } + } + + public static TheosUIVersion toArtificeUIVersion(int versionAsInt) throws IOException, FatalIOException { + Set versionsKeySet = new ConfReader.MultipleConfReader(ServerFiles.etc.versions).getAll("TheosUI", true).keySet(); + String[] allVersions = versionsKeySet.toArray(new String[versionsKeySet.size()]); + + for (int i = allVersions.length; i > 0; i--) { + if (i == versionAsInt) { + return new TheosUIVersion(allVersions[i]); + } + } + return null; + } + +} diff --git a/src/org/blueshard/olymp/version/Version.java b/src/org/blueshard/olymp/version/Version.java new file mode 100644 index 0000000..1ef67c8 --- /dev/null +++ b/src/org/blueshard/olymp/version/Version.java @@ -0,0 +1,21 @@ +package org.blueshard.olymp.version; + +public abstract class Version { + + private final String version; + + public Version(String version) { + this.version = version; + } + + @Override + public String toString() { + return version; + } + + public abstract int toInt(); + + public abstract boolean higherThan(Version version); + + public abstract boolean lowerThan(Version version); +} diff --git a/src/org/blueshard/sekaijuclt/Main.java b/src/org/blueshard/sekaijuclt/Main.java new file mode 100644 index 0000000..d8fd225 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/Main.java @@ -0,0 +1,16 @@ +package org.blueshard.sekaijuclt; + +import org.apache.log4j.Level; +import org.blueshard.sekaijuclt.client.MainClient; +import org.blueshard.sekaijuclt.logging.MainLogger; + +import java.io.IOException; + +public class Main { + + public static void main(String[] args) throws IOException { + MainClient client = new MainClient(8269, "192.168.2.104", new MainLogger(Level.ALL).getLogger()); + client.start("/srv/ssl/sslTrustStore.jks", "@VR&_*p%9!L+kC3FZ4QX"); + } + +} diff --git a/src/org/blueshard/sekaijuclt/cli/empty b/src/org/blueshard/sekaijuclt/cli/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/cli/empty @@ -0,0 +1 @@ +#empty diff --git a/src/org/blueshard/sekaijuclt/client/Action.java b/src/org/blueshard/sekaijuclt/client/Action.java new file mode 100644 index 0000000..c540443 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/client/Action.java @@ -0,0 +1,52 @@ +package org.blueshard.sekaijuclt.client; + +import org.blueshard.sekaijuclt.data.Data; +import org.blueshard.sekaijuclt.data.DataCodes; +import org.blueshard.sekaijuclt.exception.IllegalCodeException; +import org.blueshard.sekaijuclt.security.Password; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +public class Action { + + private final DataInputStream dataInputStream; + private final ServerSender serverSender; + + public Action(InputStream inputStream, ServerSender serverSender) { + this.dataInputStream = new DataInputStream(inputStream); + this.serverSender = serverSender; + } + + public int login(String username, String clearPassword) throws IOException { + Password.PasswordInfos passwordInfos = Password.createPassword(clearPassword, new byte[64]); + serverSender.login(username, passwordInfos); + return new Data(dataInputStream.readUTF()).getCode(); + } + + public int register(String username, String clearPassword, String email) throws IOException { + Password.PasswordInfos passwordInfos = Password.createPassword(clearPassword, new byte[64]); + serverSender.register(username, passwordInfos, email); + return new Data(dataInputStream.readUTF()).getCode(); + } + + public String[][] getFilesData(String directory) throws IOException, IllegalCodeException { + serverSender.getFilesData(); + Data data = new Data(dataInputStream.readUTF()); + String[][] files = new String[2][data.getData().hashCode()]; + if (data.getCode() != DataCodes.Server.SENDFILESDATA) { + throw new IllegalCodeException(data.getCode(), DataCodes.Server.SENDFILESDATA); + } + data.getData().forEach((index, file) -> { + if (index.startsWith("d")) { + files[0][Integer.parseInt(index.substring(1))] = file; + } else { + files[1][Integer.parseInt(index.substring(1))] = file; + } + }); + return files; + } + +} diff --git a/src/org/blueshard/sekaijuclt/client/MainClient.java b/src/org/blueshard/sekaijuclt/client/MainClient.java new file mode 100644 index 0000000..77ed849 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/client/MainClient.java @@ -0,0 +1,110 @@ +package org.blueshard.sekaijuclt.client; + +import org.apache.log4j.Logger; +import org.blueshard.sekaijuclt.data.DataCodes; +import org.blueshard.sekaijuclt.exception.IllegalCodeException; +import org.blueshard.sekaijuserv.data.Data; +import org.blueshard.sekaijuserv.exception.UnexpectedException; +import org.blueshard.sekaijuserv.server.ClientSender; +import org.blueshard.sekaijuserv.user.UserParams; + +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.*; +import java.security.GeneralSecurityException; +import java.util.Base64; + +public class MainClient { + + private final int serverPort; + private final String serverIP; + private final Logger logger; + + public MainClient(int serverPort, String serverIP, Logger logger) { + this.serverPort = serverPort; + this.serverIP = serverIP; + this.logger = logger; + } + + public void start(String trustStoreFile, String trustStorePassword) throws IOException { + System.setProperty("javax.net.ssl.trustStore", trustStoreFile); + System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword); + + SSLSocket server = (SSLSocket) SSLSocketFactory.getDefault().createSocket("192.168", 8269); + + byte[] privateKey; + try { + privateKey = new org.blueshard.sekaijuserv.server.Action(null, new ClientSender(server, new byte[0], logger)).publicKey().getEncoded(); + } catch (GeneralSecurityException | UnexpectedException ignore) { + return; + } + byte[] serverPublicKey = Base64.getDecoder().decode(new Data(new DataInputStream(server.getInputStream()).readUTF()).getFromData(UserParams.Key.PUBLICKEY)); + + ServerSender serverSender; + try { + serverSender = new ServerSender(server.getOutputStream(), serverPublicKey, logger); + } catch (GeneralSecurityException | UnexpectedException ignore) { + return; + } + Action action = new Action(null, serverSender); + + logger.info("Started client"); + + Console console = System.console(); + + while (true) { + String logReg = console.readLine("To connect type 'login' to login, or 'register' to register: ").strip().toLowerCase(); + if (logReg.equals("login")) { + String username = console.readLine("Username: ").strip(); + String password = String.valueOf(console.readPassword("Password: ")).strip(); + + int resultCode = action.login(username, password); + + if (resultCode == DataCodes.Server.LOGINFAIL) { + logger.warn("Login failed"); + } else if (resultCode == DataCodes.Server.LOGINSUCCESS) { + logger.info("Logged in successfully"); + break; + } else if (resultCode == DataCodes.Server.UNEXPECTEDERROR) { + logger.warn("An unexpected error occurred"); + } else if (resultCode == DataCodes.Server.UNEXPECTEDEXIT) { + logger.fatal("Server exited unexpected"); + return; + } + } else if (logReg.equals("register")) { + String password; + String passwordAgain; + + String username = console.readLine("Username: "); + do { + password = String.valueOf(console.readPassword("Password: ")); + passwordAgain = String.valueOf(console.readPassword("Re-type your Password: ")); + } while (!password.equals(passwordAgain)); + String email = console.readLine("Email: "); + + int resultCode = action.register(username, password, email); + + if (resultCode == DataCodes.Server.REGISTERFAIL) { + logger.warn("Register failed"); + } else if (resultCode == DataCodes.Server.REGISTERFAIL_USER_EXIST) { + logger.warn("The user already exists"); + } else if (resultCode == DataCodes.Server.REGISTERSUCCESS) { + logger.info("Registered successfully"); + break; + } else if (resultCode == DataCodes.Server.UNEXPECTEDERROR) { + logger.warn("An unexpected error occurred"); + } else if (resultCode == DataCodes.Server.UNEXPECTEDEXIT) { + logger.fatal("Server exited unexpected"); + return; + } + } + } + + ServerSendRecv sendRecv = new ServerSendRecv(server, logger); + try { + sendRecv.main(); + } catch (IllegalCodeException e) { + serverSender.unexpectedExit(); + } + } +} diff --git a/src/org/blueshard/sekaijuclt/client/ServerSendRecv.java b/src/org/blueshard/sekaijuclt/client/ServerSendRecv.java new file mode 100644 index 0000000..3173815 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/client/ServerSendRecv.java @@ -0,0 +1,143 @@ +package org.blueshard.sekaijuclt.client; + +import org.apache.log4j.Logger; +import org.blueshard.sekaijuclt.exception.IllegalCodeException; + +import javax.net.ssl.SSLSocket; +import java.io.Console; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; + +public class ServerSendRecv { + + private final Logger logger; + + private final Action action; + private final DataInputStream serverInput; + private final ServerSender serverSender; + + public ServerSendRecv(SSLSocket socket, ServerSender serverSender, byte[] privateKey, Logger logger) throws IOException { + this.logger = logger; + + try { + this.serverInput = new DataInputStream(socket.getInputStream()); + this.serverSender = serverSender; + } catch (IOException e) { + throw new IOException(ResultCode.UNEXPECTEDEXIT + ";" + e.getMessage()); + } + this.action = new Action(socket.getInputStream(), this.serverSender); + } + + public int main() throws IOException, IllegalCodeException { + Console console = System.console(); + String input; + + System.out.println("Type ... to ...: " + + " exit Close connection to server" + + " file-mode Enter file mode"); + while (true) { + input = console.readLine("Action: ").strip().toLowerCase(); + + if (input.equals("exit")) { + serverSender.exit(); + return ResultCode.EXIT; + } else if (input.equals("file-mode")) { + while (true) { + SendRecvFiles files = new SendRecvFiles(action); + input = console.readLine(files.getCurrentDirectory() + ": ").strip().toLowerCase(); + + if (input.startsWith("cd")) { + files.cdDirectory(input.substring(2).strip()); + } else if (input.equals("ls")) { + StringBuilder stringBuilder = new StringBuilder(); + files.listFilesAsList().forEach(s -> stringBuilder.append(s).append(" ")); + System.out.println(stringBuilder.toString()); + } else if (input.equals("exit")) { + return ResultCode.EXIT; + } + } + } + } + } + + public static class SendRecvFiles { + + private final Action action; + + private ArrayList currentDirectory = new ArrayList<>(); + private HashMap files = new HashMap<>(); + + public SendRecvFiles(Action action) throws IOException, IllegalCodeException { + this.action = action; + addToFiles(action.getFilesData("")); + } + + private void addToFiles(String[][] data) { + for (int i = 0; i < data[0].length; i++) { + files.put(data[0][i], new HashMap<>()); + } + for (int i = 0; i < data[1].length; i++) { + files.put(data[1][i], null); + } + } + + private ArrayList toSortedArrayList(String[] files) { + Arrays.sort(files, String::compareToIgnoreCase); + return new ArrayList<>(Arrays.asList(files)); + } + + public void cdDirectory(String directory) throws IOException, IllegalCodeException { + directory = directory.strip(); + if (directory.equals("..")) { + if (currentDirectory.isEmpty()) { + return; + } else { + currentDirectory.remove(currentDirectory.size() - 1); + } + } else { + if (listFiles().get(directory) != null) { + HashMap files = (HashMap) listFiles().get(directory); + if (files.isEmpty()) { + addToFiles(action.getFilesData(getCurrentDirectory() + "/")); + } + currentDirectory.add(directory); + } + } + } + + public ArrayList listFilesAsList() { + HashMap currentFiles = new HashMap<>(); + for (String s: currentDirectory) { + currentFiles = (HashMap) files.get(s); + } + return toSortedArrayList((String[]) currentFiles.keySet().toArray()); + } + + public HashMap listFiles() { + HashMap currentFiles = new HashMap<>(); + for (String s: currentDirectory) { + currentFiles = (HashMap) files.get(s); + } + return currentFiles; + } + + public String getCurrentDirectory() { + StringBuilder stringBuilder = new StringBuilder(); + currentDirectory.forEach(stringBuilder::append); + return stringBuilder.toString(); + } + + } + + public static class ResultCode { + + public static final int EXIT = 25; + public static final int UNEXPECTEDEXIT = 84; + + } + +} diff --git a/src/org/blueshard/sekaijuclt/client/ServerSender.java b/src/org/blueshard/sekaijuclt/client/ServerSender.java new file mode 100644 index 0000000..b93f04e --- /dev/null +++ b/src/org/blueshard/sekaijuclt/client/ServerSender.java @@ -0,0 +1,145 @@ +package org.blueshard.sekaijuclt.client; + +import org.apache.log4j.Logger; +import org.blueshard.sekaijuclt.data.Data; +import org.blueshard.sekaijuclt.data.DataCodes; +import org.blueshard.sekaijuclt.security.Password; +import org.blueshard.sekaijuclt.user.UserParams; +import org.blueshard.sekaijuserv.e2ee.E2EEConverter; +import org.blueshard.sekaijuserv.exception.UnexpectedException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +public class ServerSender { + + private final DataOutputStream dataOutputStream; + private final byte[] serverPublicKey; + private final Logger logger; + + public ServerSender(OutputStream outputStream, byte[] serverPublicKey, Logger logger) throws IllegalBlockSizeException, UnexpectedException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + this.dataOutputStream = new DataOutputStream(outputStream); + this.serverPublicKey = serverPublicKey; + this.logger = logger; + + if (serverPublicKey.length != 0) { + E2EEConverter.encrypt("Test", serverPublicKey); // just test if the server key works + } + } + + private void send(Data data) throws IOException { + if (serverPublicKey.length == 0) { + dataOutputStream.writeUTF(data.getDataAsString() + "\n"); + } else { + try { + dataOutputStream.writeUTF(E2EEConverter.encrypt(data.getDataAsString() + "\n", serverPublicKey)); + } catch (UnexpectedException e) { + logger.error("An unexpected error occurred", e); + unexpectedError(); + } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidKeySpecException ignore) { + } + } + dataOutputStream.flush(); + } + + private void send(Data.Builder data) throws IOException { + send(data.getData()); + } + + private String loggerInfo(String data) { + return "Send " + data + " data"; + } + + private String loggerWarning(String data) { + return "Failed to send " + data + " data"; + } + + public void exit() { + try { + send(new Data.Builder(DataCodes.Client.EXIT)); + logger.info(loggerInfo("exit")); + } catch (IOException e) { + logger.warn(loggerWarning("exit")); + } + } + + public void unexpectedError() { + try { + send(new Data.Builder(DataCodes.Client.UNEXPECTEDERROR)); + logger.info(loggerInfo("unexpected error")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected error"), e); + } + } + + public void unexpectedExit() { + try { + send(new Data.Builder(DataCodes.Client.UNEXPECTEDEXIT)); + logger.info(loggerInfo("unexpected exit")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected exit"), e); + } + } + + public void publicKey(String publicKey) { + try { + Data.Builder data = new Data.Builder(DataCodes.Client.PUBLICKEY); + data.addData(org.blueshard.sekaijuserv.user.UserParams.Key.PUBLICKEY, publicKey); + + send(data); + logger.info(loggerInfo("public key")); + } catch (IOException e) { + logger.warn(loggerWarning("public key")); + } + } + + //----- login / register -----// + + public void login(String username, Password.PasswordInfos passwordInfos) { + Data.Builder data = new Data.Builder(DataCodes.Client.LOGIN); + data.addData(UserParams.USERNAME, username); + data.addData(UserParams.PASSWORD, passwordInfos.getPasswordAsString()); + data.addData(UserParams.SALT, passwordInfos.getSaltAsString()); + + try { + send(data); + logger.info(loggerInfo("login")); + } catch (IOException e) { + logger.warn(loggerWarning("login"), e); + } + } + + public void register(String username, Password.PasswordInfos passwordInfos, String email) { + Data.Builder data = new Data.Builder(DataCodes.Client.REGISTER); + data.addData(UserParams.USERNAME, username); + data.addData(UserParams.PASSWORD, passwordInfos.getPasswordAsString()); + data.addData(UserParams.SALT, passwordInfos.getSaltAsString()); + data.addData(UserParams.EMAIL, email); + + try { + send(data); + logger.info(loggerInfo("register")); + } catch (IOException e) { + logger.warn(loggerWarning("register"), e); + } + } + + //----- files -----// + + public void getFilesData() { + Data.Builder data = new Data.Builder(DataCodes.Client.GETFILESDATA); + + try { + send(data); + logger.info(loggerInfo("get files data")); + } catch (IOException e) { + logger.warn(loggerWarning("get files data"), e); + } + } + +} diff --git a/src/org/blueshard/sekaijuclt/data/Data.java b/src/org/blueshard/sekaijuclt/data/Data.java new file mode 100644 index 0000000..6ece665 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/data/Data.java @@ -0,0 +1,161 @@ +package org.blueshard.sekaijuclt.data; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class Data { + + private String dataAsString; + private Map data = new HashMap<>(); + + public Data(String data) { + this.dataAsString = data; + + String key = ""; + String dataString = dataAsString; + + String separator = getSeparator(); + try { + if (separator.length() == 1) { + dataString = dataString.substring(dataString.indexOf(",")).strip(); + } else { + dataString = dataString.substring(dataString.indexOf(",") + 1).strip(); + } + } catch (StringIndexOutOfBoundsException e) { + dataString = ""; + } + for (String string: dataString.split(separator)) { + string = string.strip(); + if (string.equals(":") || string.equals(",") || string.equals("{") || string.equals("}")) { + continue; + } else if (key.isEmpty()) { + key = string; + } else { + this.data.put(key, string); + key = ""; + } + } + } + + public int getCode() { + int lenBeforeCode = 1 + getSeparator().length() + 1; + return Integer.parseInt(dataAsString.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + } + + public Map getData() { + return data; + } + + public String getDataAsString() { + return dataAsString; + } + + public String getFromData(String key) { + return data.get(key); + } + + private String getSeparator() { + return dataAsString.substring(1).split(":")[0]; + } + + public static class Builder { + + private Map data = new HashMap<>(); + private int code; + + public Builder(int code) { + this.code = code; + } + + public String createData() { + String separator = createSeparator(); + + StringBuilder dataAsString = new StringBuilder("{" + separator + ":" + code); + data.forEach((key, value) -> dataAsString.append(",") + .append(separator) + .append(key) + .append(separator) + .append(":") + .append(separator) + .append(value) + .append(separator)); + dataAsString.append("}"); + + return dataAsString.toString(); + } + + public String createSeparator() { + char choice; + + StringBuilder stringBuilder = new StringBuilder(); + String indicator = "'"; + char[] choices = {'\'', '"', '^'}; + + data.forEach((key, value) -> stringBuilder.append(key).append(value)); + + String string = stringBuilder.toString(); + + while (true) { + if (string.contains(indicator)) { + switch (indicator) { + case "'" -> indicator = "\""; + case "\"" -> indicator = "^"; + default -> { + choice = choices[new Random().nextInt(choices.length) - 1]; + if (indicator.contains("|")) { + String[] splitted_indicator = indicator.split("\\|"); + indicator = splitted_indicator[0] + choice + '|' + choice + splitted_indicator[1]; + } else { + indicator = indicator + choice + '|' + choice + indicator; + } + } + } + } else { + return indicator; + } + } + } + + public void addData(String key, String value) { + this.data.put(key, value); + } + + public void addAllData(Map allData) { + this.data.putAll(allData); + } + + public int getCode() { + return code; + } + + public Data getData() { + return new Data(getDataAsString()); + } + + public Map getDataMap() { + return data; + } + + public String getDataAsString() { + return createData(); + } + } + + public static boolean isDataString(String string) { + try { + string = string.strip(); + if (string.startsWith("{") && string.endsWith("}") && string.contains(":")) { + String separator = string.substring(1).split(":")[0]; + int lenBeforeCode = 1 + separator.length() + 1; + Integer.parseInt(string.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } + +} diff --git a/src/org/blueshard/sekaijuclt/data/DataCodes.java b/src/org/blueshard/sekaijuclt/data/DataCodes.java new file mode 100644 index 0000000..00e3860 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/data/DataCodes.java @@ -0,0 +1,50 @@ +package org.blueshard.sekaijuclt.data; + +public class DataCodes { + + public static final int DATACODESLENGHT = 5; + + public static class Client { + + public static final int UNEXPECTEDERROR = 56400; + public static final int UNEXPECTEDEXIT = 95078; + + public static final int EXIT = 69826; + + public static final int PUBLICKEY = 19294; + + public static final int LOGIN = 39208; + public static final int REGISTER = 84219; + + public static final int GETFILESDATA = 28926; + public static final int GETFILE = 95868; + public static final int SENDFILE = 53639; + + } + + public static class Server { + + public static final int UNEXPECTEDERROR = 29875; + public static final int UNEXPECTEDEXIT = 85048; + + public static final int NOTLOGGEDIN = 77015; + + public static final int EXIT = 42812; + + public static final int PUBLICKEY = 19294; + + public static final int LOGINFAIL = 11868; + public static final int LOGINSUCCESS = 54151; + public static final int REGISTERFAIL = 52300; + public static final int REGISTERFAIL_USER_EXIST= 77444; + public static final int REGISTERSUCCESS = 34367; + + public static final int RECEIVEFILEFAIL = 45747; + public static final int RECEIVEFILESUCCESS = 75368; + public static final int SENDFILESDATA = 78946; + public static final int SENDFILEFAIL = 90173; + public static final int SENDFILESSUCCESS = 37272; + + } + +} diff --git a/src/org/blueshard/sekaijuclt/e2ee/AESCipher.java b/src/org/blueshard/sekaijuclt/e2ee/AESCipher.java new file mode 100644 index 0000000..a9dd89b --- /dev/null +++ b/src/org/blueshard/sekaijuclt/e2ee/AESCipher.java @@ -0,0 +1,48 @@ +package org.blueshard.sekaijuclt.e2ee; + +import org.blueshard.sekaijuserv.exception.UnexpectedException; +import org.blueshard.sekaijuserv.utils.ExceptionUtils; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class AESCipher { + + private static final int keySize = 256; + + public static byte[] generateKey() throws UnexpectedException { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(keySize); + SecretKey secretKey = keyGenerator.generateKey(); + return secretKey.getEncoded(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] input, byte[] key) throws UnexpectedException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new UnexpectedException(e); + } + } + + public static byte[] decrypt(byte[] input, byte[] key) throws UnexpectedException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchPaddingException | NoSuchAlgorithmException e) { + throw new UnexpectedException(e); + } + } + +} diff --git a/src/org/blueshard/sekaijuclt/e2ee/E2EEConverter.java b/src/org/blueshard/sekaijuclt/e2ee/E2EEConverter.java new file mode 100644 index 0000000..3fee339 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/e2ee/E2EEConverter.java @@ -0,0 +1,36 @@ +package org.blueshard.sekaijuclt.e2ee; + +import org.blueshard.sekaijuserv.exception.UnexpectedException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class E2EEConverter { + + private final static String separator = "@"; + + public static String decrypt(String input, byte[] privateKey) throws UnexpectedException, BadPaddingException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException { + String[] inputAsArray = input.split(separator); + String key = inputAsArray[0]; + String realInput = inputAsArray[1]; + + byte[] AESKey = RSACipher.decrypt(Base64.getDecoder().decode(key), privateKey); + + return new String(AESCipher.decrypt(Base64.getDecoder().decode(realInput), AESKey)); + } + + public static String encrypt(String input, byte[] publicKey) throws UnexpectedException, BadPaddingException, InvalidKeyException, IllegalBlockSizeException, InvalidKeySpecException { + byte[] AESKey = AESCipher.generateKey(); + + String encryptedKey = Base64.getEncoder().encodeToString(RSACipher.encrypt(AESKey, publicKey)); + String encryptedInput = Base64.getEncoder().encodeToString(AESCipher.encrypt(input.getBytes(StandardCharsets.UTF_8), AESKey)); + + return encryptedKey + separator + encryptedInput; + } + +} diff --git a/src/org/blueshard/sekaijuclt/e2ee/RSACipher.java b/src/org/blueshard/sekaijuclt/e2ee/RSACipher.java new file mode 100644 index 0000000..d879ab8 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/e2ee/RSACipher.java @@ -0,0 +1,57 @@ +package org.blueshard.sekaijuclt.e2ee; + +import org.blueshard.sekaijuserv.exception.UnexpectedException; +import org.blueshard.sekaijuserv.utils.ExceptionUtils; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.*; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RSACipher { + + private static final int keySize = 2048; + + public static KeyPair generateKeyPair() throws UnexpectedException { + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(keySize); + return keyPairGenerator.generateKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] key, byte[] publicKey) throws UnexpectedException, InvalidKeyException, InvalidKeySpecException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); + RSAPublicKey publicRSAKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicRSAKey); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] decrypt(byte[] key, byte[] privateKey) throws UnexpectedException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privatePKCS8Key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey)); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privatePKCS8Key); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/ErrorCodes.java b/src/org/blueshard/sekaijuclt/exception/ErrorCodes.java new file mode 100644 index 0000000..256603d --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/ErrorCodes.java @@ -0,0 +1,37 @@ +package org.blueshard.sekaijuclt.exception; + +import java.util.HashSet; +import java.util.Set; + +public class ErrorCodes { + + public final static int couldnt_read_users_conf = 545; + public final static int couldnt_write_users_conf = 376; + + public final static int couldnt_create_user_folder = 639; + public final static int couldnt_delete_user_folder = 152; + + public final static int couldnt_create_user_userfiles_folder = 293; + public final static int couldnt_delete_user_userfiles_folder = 219; + + public final static int couldnt_create_user_user_conf = 934; + public final static int couldnt_read_user_user_conf = 177; + public final static int couldnt_write_user_user_conf = 990; + public final static int couldnt_delete_user_user_conf = 680; + + public final static int couldnt_create_user_user_files_conf = 353; + public final static int couldnt_read_user_user_files_conf = 155; + public final static int couldnt_write_user_user_files_conf = 476; + public final static int couldnt_delete_user_user_files_conf = 559; + + public final static int couldnt_delete_custom_user_directory = 383; + public final static int couldnt_delete_custom_user_file = 942; + + public final static HashSet allFatalUserLoginRegisterErrors = new HashSet<>(Set.of(couldnt_read_users_conf, couldnt_write_users_conf, + couldnt_create_user_folder, couldnt_delete_user_folder, + couldnt_create_user_userfiles_folder, couldnt_delete_user_userfiles_folder, + couldnt_create_user_user_conf, couldnt_read_user_user_conf, couldnt_write_user_user_conf, couldnt_delete_user_user_conf, + couldnt_create_user_user_files_conf, couldnt_read_user_user_files_conf, couldnt_write_user_user_files_conf, couldnt_delete_user_user_files_conf, + couldnt_delete_custom_user_directory, couldnt_delete_custom_user_file)); + +} diff --git a/src/org/blueshard/sekaijuclt/exception/FatalIOException.java b/src/org/blueshard/sekaijuclt/exception/FatalIOException.java new file mode 100644 index 0000000..874fc25 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/FatalIOException.java @@ -0,0 +1,17 @@ +package org.blueshard.sekaijuclt.exception; + +public class FatalIOException extends Exception { + + private final int errno; + + public FatalIOException(int errno, String message) { + super("Errno: " + errno + " - " + message); + + this.errno = errno; + } + + public int getErrno() { + return errno; + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/IllegalCodeException.java b/src/org/blueshard/sekaijuclt/exception/IllegalCodeException.java new file mode 100644 index 0000000..1eac1fb --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/IllegalCodeException.java @@ -0,0 +1,15 @@ +package org.blueshard.sekaijuclt.exception; + +public class IllegalCodeException extends Exception { + + private final int givenCode; + private final int requiredCode; + + public IllegalCodeException(int givenCode, int requiredCode){ + super("Wrong data code is given '" + givenCode + "', expected '" + requiredCode + "'"); + + this.givenCode = givenCode; + this.requiredCode = requiredCode; + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/IllegalPasswordException.java b/src/org/blueshard/sekaijuclt/exception/IllegalPasswordException.java new file mode 100644 index 0000000..4cbe3ce --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/IllegalPasswordException.java @@ -0,0 +1,9 @@ +package org.blueshard.sekaijuclt.exception; + +public class IllegalPasswordException extends Exception { + + public IllegalPasswordException(String errorMessage){ + super(errorMessage); + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/UnexpectedException.java b/src/org/blueshard/sekaijuclt/exception/UnexpectedException.java new file mode 100644 index 0000000..e8fd03a --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/UnexpectedException.java @@ -0,0 +1,23 @@ +package org.blueshard.sekaijuclt.exception; + +public class UnexpectedException extends Exception { + + public UnexpectedException() { + super("An unexpected error occurred"); + } + + public UnexpectedException(Throwable t) { + super("An unexpected error occurred (" + t.getMessage() + ")"); + this.setStackTrace(t.getStackTrace()); + } + + public UnexpectedException(String message) { + super(message); + } + + public UnexpectedException(String message, Throwable t) { + super(message); + this.setStackTrace(t.getStackTrace()); + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/UserAlreadyExistException.java b/src/org/blueshard/sekaijuclt/exception/UserAlreadyExistException.java new file mode 100644 index 0000000..940dfcc --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/UserAlreadyExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.sekaijuclt.exception; + +public class UserAlreadyExistException extends UserException { + + public UserAlreadyExistException(String username, String message) { + super(username, message); + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/UserException.java b/src/org/blueshard/sekaijuclt/exception/UserException.java new file mode 100644 index 0000000..727b9df --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/UserException.java @@ -0,0 +1,13 @@ +package org.blueshard.sekaijuclt.exception; + +public class UserException extends Exception { + + final String username; + + public UserException(String username, String message) { + super(message); + + this.username = username; + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/UserNotExistException.java b/src/org/blueshard/sekaijuclt/exception/UserNotExistException.java new file mode 100644 index 0000000..e3bbd86 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/UserNotExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.sekaijuclt.exception; + +public class UserNotExistException extends UserException { + + public UserNotExistException(String username, String message){ + super(username, message); + } + +} diff --git a/src/org/blueshard/sekaijuclt/exception/UserNotLoggedInException.java b/src/org/blueshard/sekaijuclt/exception/UserNotLoggedInException.java new file mode 100644 index 0000000..79d48f0 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/exception/UserNotLoggedInException.java @@ -0,0 +1,8 @@ +package org.blueshard.sekaijuclt.exception; + +public class UserNotLoggedInException extends UserException { + + public UserNotLoggedInException(String username, String message) { + super(username, message); + } +} diff --git a/src/org/blueshard/sekaijuclt/logging/empty b/src/org/blueshard/sekaijuclt/logging/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/logging/empty @@ -0,0 +1 @@ +#empty diff --git a/src/org/blueshard/sekaijuclt/security/Password.java b/src/org/blueshard/sekaijuclt/security/Password.java new file mode 100644 index 0000000..e70d79b --- /dev/null +++ b/src/org/blueshard/sekaijuclt/security/Password.java @@ -0,0 +1,65 @@ +package org.blueshard.sekaijuclt.security; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; + +public class Password { + + public static PasswordInfos createPassword(String password, byte[] salt) { + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(salt); + + KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); + SecretKeyFactory factory = null; + try { + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException ignore) { + } + + byte[] hashedPassword = new byte[0]; + try { + hashedPassword = factory.generateSecret(keySpec).getEncoded(); + } catch (InvalidKeySpecException ignore) { + } + + return new PasswordInfos(hashedPassword, salt); + } + + public static class PasswordInfos { + + private final byte[] password; + private final byte[] salt; + + public PasswordInfos(byte[] password, byte[] salt) { + this.password = password; + this.salt = salt; + } + + public byte[] getPasswordAsBytes() { + return password; + } + + public String getPasswordAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(password); + } + + public byte[] getSaltAsBytes() { + return salt; + } + + public String getSaltAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(salt); + } + + } + +} diff --git a/src/org/blueshard/sekaijuclt/user/UserParams.java b/src/org/blueshard/sekaijuclt/user/UserParams.java new file mode 100644 index 0000000..2893b02 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/user/UserParams.java @@ -0,0 +1,58 @@ +package org.blueshard.sekaijuclt.user; + +public class UserParams { + + public final static String USERNAME = "username"; + public final static String PASSWORD = "password"; + public final static String SALT = "salt"; + public final static String EMAIL = "email"; + + public static class File { + + public final static String STARTDIRECOTRY = "startDirectory"; + public final static String FILEPATH = "filepath"; + + } + + public static class CheckSum { + + public final static String MD5 = "md5"; + + } + + public static class Key { + + public final static String PUBLICKEY = "key"; + + } + + public static class LogLevel { + + public final static String LOGLEVEL = "logLevel"; + + public final static String ALL = "0"; + public final static String WARNING = "1"; + public final static String NOTHING = "2"; + + } + + public static class UserLevel { + + public final static String USERLEVEL = "userLevel"; + + public final static String PUBLIC = "0"; + public final static String PROTECTED = "1"; + public final static String PRIVATE = "2"; + + } + + public static class State { + + public final static String STATE = "state"; + + public final static String ACTIVE = "active"; + public final static String DISABLED = "disabled"; + + } + +} diff --git a/src/org/blueshard/sekaijuclt/utils/ConsoleColors.java b/src/org/blueshard/sekaijuclt/utils/ConsoleColors.java new file mode 100644 index 0000000..0285c2c --- /dev/null +++ b/src/org/blueshard/sekaijuclt/utils/ConsoleColors.java @@ -0,0 +1,76 @@ +package org.blueshard.sekaijuclt.utils; + +public class ConsoleColors { + // Reset + public static final String RESET = "\033[0m"; // Text Reset + + // Regular Colors + public static final String BLACK = "\033[0;30m"; // BLACK + public static final String RED = "\033[0;31m"; // RED + public static final String GREEN = "\033[0;32m"; // GREEN + public static final String YELLOW = "\033[0;33m"; // YELLOW + public static final String BLUE = "\033[0;34m"; // BLUE + public static final String PURPLE = "\033[0;35m"; // PURPLE + public static final String CYAN = "\033[0;36m"; // CYAN + public static final String WHITE = "\033[0;37m"; // WHITE + + // Bold + public static final String BLACK_BOLD = "\033[1;30m"; // BLACK + public static final String RED_BOLD = "\033[1;31m"; // RED + public static final String GREEN_BOLD = "\033[1;32m"; // GREEN + public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW + public static final String BLUE_BOLD = "\033[1;34m"; // BLUE + public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE + public static final String CYAN_BOLD = "\033[1;36m"; // CYAN + public static final String WHITE_BOLD = "\033[1;37m"; // WHITE + + // Underline + public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK + public static final String RED_UNDERLINED = "\033[4;31m"; // RED + public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN + public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW + public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE + public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE + public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN + public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE + + // Background + public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK + public static final String RED_BACKGROUND = "\033[41m"; // RED + public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN + public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW + public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE + public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE + public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN + public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + + // High Intensity + public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK + public static final String RED_BRIGHT = "\033[0;91m"; // RED + public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN + public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW + public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE + public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE + public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN + public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE + + // Bold High Intensity + public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK + public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED + public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN + public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW + public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE + public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE + public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN + public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE + + // High Intensity backgrounds + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE +} diff --git a/src/org/blueshard/sekaijuclt/utils/FileUtils.java b/src/org/blueshard/sekaijuclt/utils/FileUtils.java new file mode 100644 index 0000000..d5c4190 --- /dev/null +++ b/src/org/blueshard/sekaijuclt/utils/FileUtils.java @@ -0,0 +1,71 @@ +package org.blueshard.sekaijuclt.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; + +public class FileUtils { + + public static ArrayList getAllFilesInDirectory(String path) throws IOException { + ArrayList files = new ArrayList<>(); + Files.walk(Paths.get(path)).map(Path::toFile).forEach(files::add); + return files; + } + + public static File[] sortFilesInDirectory(File path) { + File[] files = path.listFiles(); + + Arrays.sort(files, (object1, object2) -> object1.getName().compareToIgnoreCase(object2.getName())); + + return files; + } + + public class CreateHashSum { + + String file; + + CreateHashSum(String file) { + this.file = file; + } + + public String MD5() throws IOException { + try { + StringBuilder hexString = new StringBuilder(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + + InputStream inputStream = Files.newInputStream(Paths.get(file)); + byte[] buffer = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + md5.update(buffer, 0 , length); + } + + byte[] digest = md5.digest(); + + for (byte b : digest) { + if ((0xff & b) < 0x10) { + hexString.append("0").append(Integer.toHexString((0xFF & b))); + } else { + hexString.append(Integer.toHexString(0xFF & b)); + } + } + + return hexString.toString(); + + } catch (NoSuchAlgorithmException ignore) { + return null; + } + } + + } + +} diff --git a/src/org/blueshard/sekaijuclt/utils/SizeUnit.java b/src/org/blueshard/sekaijuclt/utils/SizeUnit.java new file mode 100644 index 0000000..a966f1e --- /dev/null +++ b/src/org/blueshard/sekaijuclt/utils/SizeUnit.java @@ -0,0 +1,140 @@ +package org.blueshard.sekaijuclt.utils; + +public class SizeUnit { + + private int unit; + private double size; + + private final static int BYTE = 1; + private final static int KILOBYTE = 3; + private final static int MEGABYTE = 5; + private final static int GIGABYTE = 7; + private final static int TERRABYTE = 9; + private final static int PETABYTE = 11; + private final static int EXABYTE = 13; + + SizeUnit(int unit, double size){ + this.unit = unit; + this.size = size; + } + + public static SizeUnit BYTES(double bytes){ + return new SizeUnit(BYTE, bytes); + } + + public static SizeUnit KILOBYTE(double kilobytes) { + return new SizeUnit(KILOBYTE, kilobytes); + } + + public static SizeUnit MEGABYTE(double megabytes) { + return new SizeUnit(MEGABYTE, megabytes); + } + + public static SizeUnit GIGABYTE(double gigabytes) { + return new SizeUnit(GIGABYTE, gigabytes); + } + + public static SizeUnit TERRABYTE(double terrabytes) { + return new SizeUnit(TERRABYTE, terrabytes); + } + + public static SizeUnit PETABYTE(double petabytes) { + return new SizeUnit(PETABYTE, petabytes); + } + + public static SizeUnit EXABYTE(double exabytes) { + return new SizeUnit(EXABYTE, exabytes); + } + + public Double toByte(){ + return switch (unit) { + case BYTE -> size; + case KILOBYTE -> size * 1000; + case MEGABYTE -> size * 1000000; + case GIGABYTE -> size * 1000000000; + case TERRABYTE -> size * 1000000000000L; + case PETABYTE -> size * 1000000000000000L; + case EXABYTE -> size * 1000000000000000000L; + default -> 0D; + }; + } + + public Double toKilobyte(){ + return switch (unit) { + case BYTE -> size / 1000; + case KILOBYTE -> size; + case MEGABYTE -> size * 1000; + case GIGABYTE -> size * 1000000; + case TERRABYTE -> size * 1000000000; + case PETABYTE -> size * 1000000000000L; + case EXABYTE -> size * 1000000000000000L; + default -> 0D; + }; + } + + public Double toMegabyte(){ + return switch (unit) { + case BYTE -> size / 1000000; + case KILOBYTE -> size / 1000; + case MEGABYTE -> size; + case GIGABYTE -> size * 1000; + case TERRABYTE -> size * 1000000; + case PETABYTE -> size * 1000000000; + case EXABYTE -> size * 1000000000000L; + default -> 0D; + }; + } + + public Double toGigabyte(){ + return switch (unit) { + case BYTE -> size / 1000000000L; + case KILOBYTE -> size / 1000000; + case MEGABYTE -> size / 1000; + case GIGABYTE -> size; + case TERRABYTE -> size * 1000; + case PETABYTE -> size * 1000000; + case EXABYTE -> size * 1000000000; + default -> 0D; + }; + } + + public Double toTerrabyte(){ + return switch (unit) { + case BYTE -> size / 1000000000000L; + case KILOBYTE -> size / 1000000000; + case MEGABYTE -> size / 1000000; + case GIGABYTE -> size / 1000; + case TERRABYTE -> size; + case PETABYTE -> size * 1000; + case EXABYTE -> size * 1000000; + default -> 0D; + }; + } + + public Double toPetabyte(){ + return switch (unit) { + case BYTE -> size / 1000000000000000L; + case KILOBYTE -> size / 1000000000000L; + case MEGABYTE -> size / 1000000000; + case GIGABYTE -> size / 1000000; + case TERRABYTE -> size / 1000; + case PETABYTE -> size; + case EXABYTE -> size * 1000; + default -> 0D; + }; + } + + public Double toExabyte(){ + return switch (unit) { + case BYTE -> size / 1000000000000000000L; + case KILOBYTE -> size / 1000000000000000L; + case MEGABYTE -> size / 1000000000000L; + case GIGABYTE -> size / 1000000000; + case TERRABYTE -> size / 1000000; + case PETABYTE -> size / 1000; + case EXABYTE -> size; + default -> 0D; + }; + } + +} diff --git a/src/org/blueshard/sekaijuclt/utils/StringUtils.java b/src/org/blueshard/sekaijuclt/utils/StringUtils.java new file mode 100644 index 0000000..36cc73d --- /dev/null +++ b/src/org/blueshard/sekaijuclt/utils/StringUtils.java @@ -0,0 +1,17 @@ +package org.blueshard.sekaijuclt.utils; + +import java.util.Map; + +public class StringUtils { + + public static String format(String string, Map formatMap){ + + for(Map.Entry entry: formatMap.entrySet()) { + string = string.replace("{" + entry.getKey() + "}", entry.getValue()); + } + + return string; + + } + +} diff --git a/srv/etc/versions.conf b/srv/etc/versions.conf new file mode 100644 index 0000000..7eafb07 --- /dev/null +++ b/srv/etc/versions.conf @@ -0,0 +1,7 @@ +[TheosUI] + +0.1.0 = required: + +[olymp] + +0.1.0 = \ No newline at end of file diff --git a/srv/file_rooms/private_file_rooms/empty b/srv/file_rooms/private_file_rooms/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/file_rooms/private_file_rooms/empty @@ -0,0 +1 @@ +#empty diff --git a/srv/file_rooms/public_file_rooms/empty b/srv/file_rooms/public_file_rooms/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/file_rooms/public_file_rooms/empty @@ -0,0 +1 @@ +#empty diff --git a/srv/hsqldb/empty b/srv/hsqldb/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/hsqldb/empty @@ -0,0 +1 @@ +#empty diff --git a/srv/logs/main.log b/srv/logs/main.log new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/logs/main.log @@ -0,0 +1 @@ +#empty diff --git a/srv/public_files/empty b/srv/public_files/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/public_files/empty @@ -0,0 +1 @@ +#empty diff --git a/srv/ssl/java ssl.txt b/srv/ssl/java ssl.txt new file mode 100644 index 0000000..5020176 --- /dev/null +++ b/srv/ssl/java ssl.txt @@ -0,0 +1,6 @@ +Keystore password: @VR&_*p%9!L+kC3FZ4QX +keytool -keygen -keyalg RSA -keysize 2048 -validity 365 -alias sslkey -keystore sslKeyStore.jks +keytool -export -alias sslkey -keystore sslKeyStore.jks -file sslKey.cert +keytool -import -file sslKey.cert -alias sslkey -keystore sslTrustStore.jts + +365 28.03.2020 \ No newline at end of file diff --git a/srv/ssl/sslKey.cert b/srv/ssl/sslKey.cert new file mode 100644 index 0000000..12b5351 Binary files /dev/null and b/srv/ssl/sslKey.cert differ diff --git a/srv/ssl/sslKeyStore.jks b/srv/ssl/sslKeyStore.jks new file mode 100644 index 0000000..9ce7f98 Binary files /dev/null and b/srv/ssl/sslKeyStore.jks differ diff --git a/srv/ssl/sslTrustStore.jks b/srv/ssl/sslTrustStore.jks new file mode 100644 index 0000000..901707f Binary files /dev/null and b/srv/ssl/sslTrustStore.jks differ diff --git a/srv/user_files/a71c1ceb-7379-4085-8a51-edd703463d5b/empty b/srv/user_files/a71c1ceb-7379-4085-8a51-edd703463d5b/empty new file mode 100644 index 0000000..ea30561 --- /dev/null +++ b/srv/user_files/a71c1ceb-7379-4085-8a51-edd703463d5b/empty @@ -0,0 +1 @@ +#empty diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..d6cc837 --- /dev/null +++ b/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +java -Dfile.encoding=UTF-8 -classpath "out/production/olymp:lib/*:lib/batik/*:lib/hsqldb/*" org.blueshard.olymp.Main \ No newline at end of file diff --git a/theosui/lib/TFX.jar b/theosui/lib/TFX.jar new file mode 100644 index 0000000..0ae1c92 Binary files /dev/null and b/theosui/lib/TFX.jar differ diff --git a/theosui/lib/TheosUIWindow.jar b/theosui/lib/TheosUIWindow.jar new file mode 100644 index 0000000..c3e9f33 Binary files /dev/null and b/theosui/lib/TheosUIWindow.jar differ diff --git a/theosui/lib/batik/batik-anim-1.8.jar b/theosui/lib/batik/batik-anim-1.8.jar new file mode 100644 index 0000000..9470058 Binary files /dev/null and b/theosui/lib/batik/batik-anim-1.8.jar differ diff --git a/theosui/lib/batik/batik-awt-util-1.8.jar b/theosui/lib/batik/batik-awt-util-1.8.jar new file mode 100644 index 0000000..740acb7 Binary files /dev/null and b/theosui/lib/batik/batik-awt-util-1.8.jar differ diff --git a/theosui/lib/batik/batik-bridge-1.8.jar b/theosui/lib/batik/batik-bridge-1.8.jar new file mode 100644 index 0000000..36e8e03 Binary files /dev/null and b/theosui/lib/batik/batik-bridge-1.8.jar differ diff --git a/theosui/lib/batik/batik-codec-1.8.jar b/theosui/lib/batik/batik-codec-1.8.jar new file mode 100644 index 0000000..07b6e79 Binary files /dev/null and b/theosui/lib/batik/batik-codec-1.8.jar differ diff --git a/theosui/lib/batik/batik-css-1.8.jar b/theosui/lib/batik/batik-css-1.8.jar new file mode 100644 index 0000000..1c9fb19 Binary files /dev/null and b/theosui/lib/batik/batik-css-1.8.jar differ diff --git a/theosui/lib/batik/batik-dom-1.8.jar b/theosui/lib/batik/batik-dom-1.8.jar new file mode 100644 index 0000000..4899b51 Binary files /dev/null and b/theosui/lib/batik/batik-dom-1.8.jar differ diff --git a/theosui/lib/batik/batik-ext-1.8.jar b/theosui/lib/batik/batik-ext-1.8.jar new file mode 100644 index 0000000..d7c850b Binary files /dev/null and b/theosui/lib/batik/batik-ext-1.8.jar differ diff --git a/theosui/lib/batik/batik-gvt-1.8.jar b/theosui/lib/batik/batik-gvt-1.8.jar new file mode 100644 index 0000000..7bb4e58 Binary files /dev/null and b/theosui/lib/batik/batik-gvt-1.8.jar differ diff --git a/theosui/lib/batik/batik-parser-1.8.jar b/theosui/lib/batik/batik-parser-1.8.jar new file mode 100644 index 0000000..1c1223d Binary files /dev/null and b/theosui/lib/batik/batik-parser-1.8.jar differ diff --git a/theosui/lib/batik/batik-script-1.8.jar b/theosui/lib/batik/batik-script-1.8.jar new file mode 100644 index 0000000..c3e9a9f Binary files /dev/null and b/theosui/lib/batik/batik-script-1.8.jar differ diff --git a/theosui/lib/batik/batik-svg-dom-1.8.jar b/theosui/lib/batik/batik-svg-dom-1.8.jar new file mode 100644 index 0000000..6429550 Binary files /dev/null and b/theosui/lib/batik/batik-svg-dom-1.8.jar differ diff --git a/theosui/lib/batik/batik-transcoder-1.8.jar b/theosui/lib/batik/batik-transcoder-1.8.jar new file mode 100644 index 0000000..f3c3c4f Binary files /dev/null and b/theosui/lib/batik/batik-transcoder-1.8.jar differ diff --git a/theosui/lib/batik/batik-util-1.8.jar b/theosui/lib/batik/batik-util-1.8.jar new file mode 100644 index 0000000..23e3625 Binary files /dev/null and b/theosui/lib/batik/batik-util-1.8.jar differ diff --git a/theosui/lib/batik/batik-xml-1.8.jar b/theosui/lib/batik/batik-xml-1.8.jar new file mode 100644 index 0000000..1101455 Binary files /dev/null and b/theosui/lib/batik/batik-xml-1.8.jar differ diff --git a/theosui/lib/batik/fop-transcoder-allinone-1.1.jar b/theosui/lib/batik/fop-transcoder-allinone-1.1.jar new file mode 100644 index 0000000..931a8e6 Binary files /dev/null and b/theosui/lib/batik/fop-transcoder-allinone-1.1.jar differ diff --git a/theosui/lib/batik/xml-apis-ext-1.3.04.jar b/theosui/lib/batik/xml-apis-ext-1.3.04.jar new file mode 100644 index 0000000..a7869d6 Binary files /dev/null and b/theosui/lib/batik/xml-apis-ext-1.3.04.jar differ diff --git a/theosui/lib/jfoenix-8.0.10.jar b/theosui/lib/jfoenix-8.0.10.jar new file mode 100644 index 0000000..742c237 Binary files /dev/null and b/theosui/lib/jfoenix-8.0.10.jar differ diff --git a/theosui/lib/log4j-1.2.17.jar b/theosui/lib/log4j-1.2.17.jar new file mode 100644 index 0000000..1d425cf Binary files /dev/null and b/theosui/lib/log4j-1.2.17.jar differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/Main.class b/theosui/out/production/thoesui/org/blueshard/theosUI/Main.class new file mode 100644 index 0000000..eaf87bc Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/Main.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/Test.class b/theosui/out/production/thoesui/org/blueshard/theosUI/Test.class new file mode 100644 index 0000000..9e141e6 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/Test.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Login.class b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Login.class new file mode 100644 index 0000000..7b16292 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Login.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Main.class b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Main.class new file mode 100644 index 0000000..f70385f Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Main.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Register.class b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Register.class new file mode 100644 index 0000000..bf4efd3 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/UIStarter/Register.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/client/Action.class b/theosui/out/production/thoesui/org/blueshard/theosUI/client/Action.class new file mode 100644 index 0000000..1d89f83 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/client/Action.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/client/MainClient.class b/theosui/out/production/thoesui/org/blueshard/theosUI/client/MainClient.class new file mode 100644 index 0000000..cc5fac0 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/client/MainClient.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/client/ServerSender.class b/theosui/out/production/thoesui/org/blueshard/theosUI/client/ServerSender.class new file mode 100644 index 0000000..731825f Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/client/ServerSender.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config$ConfigEntryKeys.class b/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config$ConfigEntryKeys.class new file mode 100644 index 0000000..0cf4edf Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config$ConfigEntryKeys.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config.class b/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config.class new file mode 100644 index 0000000..d644eb4 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/config/Config.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/LoginController.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/LoginController.class new file mode 100644 index 0000000..957766a Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/LoginController.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/RegisterController.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/RegisterController.class new file mode 100644 index 0000000..8f9fa8a Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/RegisterController.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainController.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainController.class new file mode 100644 index 0000000..a00896c Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainController.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils$ServerStatusController.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils$ServerStatusController.class new file mode 100644 index 0000000..d345cfd Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils$ServerStatusController.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils.class new file mode 100644 index 0000000..02b9eda Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MainControllerUtils.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MyFilesController.class b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MyFilesController.class new file mode 100644 index 0000000..22166e5 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/controller/main/MyFilesController.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data$Builder.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data$Builder.class new file mode 100644 index 0000000..84c1355 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data$Builder.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data.class new file mode 100644 index 0000000..ac31509 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/Data.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Client.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Client.class new file mode 100644 index 0000000..0034730 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Client.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$CheckSum.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$CheckSum.class new file mode 100644 index 0000000..3f95be8 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$CheckSum.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$ClientAgent.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$ClientAgent.class new file mode 100644 index 0000000..06b0ff5 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$ClientAgent.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$File.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$File.class new file mode 100644 index 0000000..cf0ba8c Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$File.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Key.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Key.class new file mode 100644 index 0000000..84b3ab7 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Key.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogLevel.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogLevel.class new file mode 100644 index 0000000..3b2ab4f Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogLevel.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogReg.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogReg.class new file mode 100644 index 0000000..6260394 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$LogReg.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$RegisterCode.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$RegisterCode.class new file mode 100644 index 0000000..bbe1f92 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$RegisterCode.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$State.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$State.class new file mode 100644 index 0000000..b9ee5be Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$State.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Update.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Update.class new file mode 100644 index 0000000..07bc0bc Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Update.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$UserLevel.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$UserLevel.class new file mode 100644 index 0000000..5e64247 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$UserLevel.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Version.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Version.class new file mode 100644 index 0000000..56202b0 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params$Version.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params.class new file mode 100644 index 0000000..c6ed833 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Params.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Server.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Server.class new file mode 100644 index 0000000..dc903ff Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes$Server.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes.class b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes.class new file mode 100644 index 0000000..66ef4f3 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/data/DataCodes.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/AESCipher.class b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/AESCipher.class new file mode 100644 index 0000000..050983b Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/AESCipher.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/E2EEConverter.class b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/E2EEConverter.class new file mode 100644 index 0000000..e827343 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/E2EEConverter.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/RSACipher.class b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/RSACipher.class new file mode 100644 index 0000000..c4e93e0 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/e2ee/RSACipher.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/ErrorCodes.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/ErrorCodes.class new file mode 100644 index 0000000..dd0eaa0 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/ErrorCodes.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/FatalIOException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/FatalIOException.class new file mode 100644 index 0000000..4c5ca11 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/FatalIOException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalCodeException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalCodeException.class new file mode 100644 index 0000000..5a703f7 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalCodeException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalPasswordException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalPasswordException.class new file mode 100644 index 0000000..ef33359 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/IllegalPasswordException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UnexpectedException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UnexpectedException.class new file mode 100644 index 0000000..0a1bbcd Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UnexpectedException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserAlreadyExistException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserAlreadyExistException.class new file mode 100644 index 0000000..424bf27 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserAlreadyExistException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserException.class new file mode 100644 index 0000000..b27e121 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotExistException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotExistException.class new file mode 100644 index 0000000..13e9d09 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotExistException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotLoggedInException.class b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotLoggedInException.class new file mode 100644 index 0000000..345444a Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/exception/UserNotLoggedInException.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$MultipleConfReader.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$MultipleConfReader.class new file mode 100644 index 0000000..c351132 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$MultipleConfReader.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$SingleConfReader.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$SingleConfReader.class new file mode 100644 index 0000000..c49d42d Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader$SingleConfReader.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader.class new file mode 100644 index 0000000..4a5f1b1 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfReader.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$MultipleConfWriter.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$MultipleConfWriter.class new file mode 100644 index 0000000..b9eb932 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$MultipleConfWriter.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$SingleConfWriter.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$SingleConfWriter.class new file mode 100644 index 0000000..9e113b8 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter$SingleConfWriter.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter.class new file mode 100644 index 0000000..b1141d4 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ConfWriter.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$logs.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$logs.class new file mode 100644 index 0000000..9178c3f Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$logs.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$ssl.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$ssl.class new file mode 100644 index 0000000..9eed3be Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$ssl.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user$userfiles.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user$userfiles.class new file mode 100644 index 0000000..9d717ae Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user$userfiles.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user.class new file mode 100644 index 0000000..8c2426d Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users$user.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users.class new file mode 100644 index 0000000..7523285 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles$users.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles.class b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles.class new file mode 100644 index 0000000..9add3ad Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/files/ServerFiles.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$1.class b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$1.class new file mode 100644 index 0000000..b6b23fc Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$1.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$2.class b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$2.class new file mode 100644 index 0000000..8d85a0b Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger$2.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger.class b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger.class new file mode 100644 index 0000000..48c1ce8 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/logging/MainLogger.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXPasswordField.css b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXPasswordField.css new file mode 100644 index 0000000..3b980f4 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXPasswordField.css @@ -0,0 +1,8 @@ +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0, 0 0 1 0 ; + -fx-background-radius: 0 ; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXTextField.css b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXTextField.css new file mode 100644 index 0000000..3b980f4 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/css/TFXTextField.css @@ -0,0 +1,8 @@ +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0, 0 0 1 0 ; + -fx-background-radius: 0 ; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/email.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/email.svg new file mode 100644 index 0000000..46107f8 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/email.svg @@ -0,0 +1,2 @@ +Email \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/green_dot.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/green_dot.svg new file mode 100644 index 0000000..9f4e287 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/green_dot.svg @@ -0,0 +1 @@ +Green dot \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/lock.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/lock.svg new file mode 100644 index 0000000..7d3c303 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/lock.svg @@ -0,0 +1 @@ +Lock \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_hide.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_hide.svg new file mode 100644 index 0000000..0ee3609 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_hide.svg @@ -0,0 +1,4 @@ +Password hide \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_show.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_show.svg new file mode 100644 index 0000000..5f3744c --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/password_show.svg @@ -0,0 +1,3 @@ +Password show \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_0.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_0.svg new file mode 100644 index 0000000..afd0fda --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_0.svg @@ -0,0 +1,3 @@ +Ping 0 \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_1.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_1.svg new file mode 100644 index 0000000..e749dca --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_1.svg @@ -0,0 +1,4 @@ +Ping 1 \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_2.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_2.svg new file mode 100644 index 0000000..badcefd --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_2.svg @@ -0,0 +1,4 @@ +Ping 2 \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_3.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_3.svg new file mode 100644 index 0000000..9b5c5a0 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/ping_3.svg @@ -0,0 +1,3 @@ +Ping 3 \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/question_mark.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/question_mark.svg new file mode 100644 index 0000000..b55732c --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/question_mark.svg @@ -0,0 +1,2 @@ +Question mark \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/red_dot.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/red_dot.svg new file mode 100644 index 0000000..5c840f6 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/red_dot.svg @@ -0,0 +1 @@ +Red dot \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/theos_logo.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/theos_logo.svg new file mode 100644 index 0000000..a8f3ea3 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/theos_logo.svg @@ -0,0 +1,17 @@ +Theos Logo \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/user.svg b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/user.svg new file mode 100644 index 0000000..15828f0 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/images/user.svg @@ -0,0 +1 @@ +User \ No newline at end of file diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/login.fxml b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/login.fxml new file mode 100644 index 0000000..846c8f1 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/login.fxml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/main.fxml b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/main.fxml new file mode 100644 index 0000000..3ca55cc --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/main.fxml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/myFiles.fxml b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/myFiles.fxml new file mode 100644 index 0000000..4c8ee28 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/myFiles.fxml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+
+
+ +
+
+
+
+ + + + + +
+
diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/question.png b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/question.png new file mode 100644 index 0000000..26b4c3d Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/question.png differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/resources/register.fxml b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/register.fxml new file mode 100644 index 0000000..98dc1d3 --- /dev/null +++ b/theosui/out/production/thoesui/org/blueshard/theosUI/resources/register.fxml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password$PasswordInfos.class b/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password$PasswordInfos.class new file mode 100644 index 0000000..96d8da4 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password$PasswordInfos.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password.class b/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password.class new file mode 100644 index 0000000..09dc91c Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/security/Password.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ConsoleColors.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ConsoleColors.class new file mode 100644 index 0000000..59b8998 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ConsoleColors.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ExceptionUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ExceptionUtils.class new file mode 100644 index 0000000..fa35859 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/ExceptionUtils.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils$CreateHashSum.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils$CreateHashSum.class new file mode 100644 index 0000000..f13ea4f Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils$CreateHashSum.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils.class new file mode 100644 index 0000000..963222e Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/FileUtils.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/OSUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/OSUtils.class new file mode 100644 index 0000000..ae20d48 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/OSUtils.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage$Transcoder.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage$Transcoder.class new file mode 100644 index 0000000..48280cc Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage$Transcoder.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage.class new file mode 100644 index 0000000..2591fa9 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SVGToGenericImage.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SizeUnit.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SizeUnit.class new file mode 100644 index 0000000..2dba10c Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/SizeUnit.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/StringUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/StringUtils.class new file mode 100644 index 0000000..6887b84 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/StringUtils.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosFile.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosFile.class new file mode 100644 index 0000000..7224185 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosFile.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage$ImageName.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage$ImageName.class new file mode 100644 index 0000000..f1f252a Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage$ImageName.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage.class new file mode 100644 index 0000000..7db0d28 Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/TheosUIImage.class differ diff --git a/theosui/out/production/thoesui/org/blueshard/theosUI/utils/UIUtils.class b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/UIUtils.class new file mode 100644 index 0000000..eebd0dd Binary files /dev/null and b/theosui/out/production/thoesui/org/blueshard/theosUI/utils/UIUtils.class differ diff --git a/theosui/src/org/blueshard/theosUI/Main.java b/theosui/src/org/blueshard/theosUI/Main.java new file mode 100644 index 0000000..357daae --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/Main.java @@ -0,0 +1,175 @@ +package org.blueshard.theosUI; + +import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Screen; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.blueshard.theosUI.UIStarter.Login; +import org.blueshard.theosUI.client.Action; +import org.blueshard.theosUI.client.ServerSender; +import org.blueshard.theosUI.config.Config; +import org.blueshard.theosUI.data.DataCodes; +import org.blueshard.theosUI.exception.FatalIOException; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.logging.MainLogger; +import org.blueshard.theosUI.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; +import org.blueshard.theosUI.utils.UIUtils; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.net.SocketFactory; +import java.io.IOException; +import java.net.Socket; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.concurrent.atomic.AtomicReference; + +import static org.blueshard.theosUI.utils.UIUtils.errorAlert; +import static org.blueshard.theosUI.utils.UIUtils.onClose; + +public class Main extends Application { + + public static final String version = "0.1.0"; + + protected static Socket server; + protected static Config config; + protected static Logger logger; + protected static byte[] privateKey; + protected static ServerSender serverSender; + protected static Action action; + + public static void main(String[] args) throws IOException, UnexpectedException, BadPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, NoSuchPaddingException { + /*config = new Config(); + if (config.getFileLogging()) { + logger = new MainLogger(config.getLogLevel(), OSUtils.getLogFile().getAbsolutePath()).getLogger(); + } else { + logger = new MainLogger(config.getLogLevel()).getLogger(); + }*/ + logger = new MainLogger(Level.ALL).getLogger(); + server = SocketFactory.getDefault().createSocket("localhost", 8269); + logger.info("Connected to server"); + + Object[] keys; + try { + keys = Action.initE2EE(server.getInputStream(), server.getOutputStream(), logger); + logger.info("Received server public key"); + } catch (UnexpectedException ignore) { + return; + } + privateKey = (byte[]) keys[0]; + byte[] serverPublicKey = (byte[]) keys[1]; + + serverSender = new ServerSender(server.getOutputStream(), serverPublicKey, logger); + action = new Action(server.getInputStream(), privateKey, serverSender); + + try { + if (action.initConnection()) { + int update = action.decryptE2EEData().getCode(); + + if (update == DataCodes.Server.OPTIONALUPDATE) { + // + } else if (update == DataCodes.Server.REQUIREDUPDATE) { + // + } + } + } catch (FatalIOException e) { + logger.fatal("Send wrong server agent, close connection"); + server.close(); + } + + launch(args); + } + + @Override + public void start(Stage primaryStage) throws Exception { + Thread.setDefaultUncaughtExceptionHandler(Main::notCaughtExceptionAlert); + + AnchorPane main = FXMLLoader.load(getClass().getResource("resources/main.fxml")); + Scene scene = new Scene(main, 1280, 720); + + main.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, event -> onClose()); + + primaryStage.setTitle(UIUtils.HEADING); + try { + primaryStage.getIcons().add(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.theos_logo).asStream(), + SVGToGenericImage.Transcoder.PNG, 30f, 30f).asByteArrayInputStream())); + } catch (TranscoderException | IOException e) { + e.printStackTrace(); + } + primaryStage.setScene(scene); + + Thread t = new Thread(() -> { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Platform.runLater(() -> { + primaryStage.setResizable(false); + try { + new Login(primaryStage).getStage().show(); + } catch (IOException e) { + logger.fatal("Couldn't show login window"); + errorAlert(null, "Login Fenster konnte nicht angezeigt werden", e); + } + }); + }); + t.start(); + + primaryStage.show(); + } + + private static void notCaughtExceptionAlert(Thread thread, Throwable throwable) { + throwable.printStackTrace(); + + AtomicReference exceptionAlertX = new AtomicReference<>(Screen.getPrimary().getBounds().getMaxX() / 2); + AtomicReference exceptionAlertY = new AtomicReference<>(Screen.getPrimary().getBounds().getMaxY() / 2); + + Alert notCaughtException = new Alert(Alert.AlertType.ERROR, "Error: " + throwable, ButtonType.OK); + notCaughtException.setTitle("Error"); + notCaughtException.setResizable(true); + try { + ((Stage) notCaughtException.getDialogPane().getScene().getWindow()).getIcons().add(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.theos_logo).asStream(), + SVGToGenericImage.Transcoder.PNG, 30f, 30f).asByteArrayInputStream())); + } catch (TranscoderException | IOException e) { + e.printStackTrace(); + } + notCaughtException.getDialogPane().setContent(new Label("Error: " + throwable)); + + Scene window = notCaughtException.getDialogPane().getScene(); + + window.setOnMouseDragged(dragEvent -> { + notCaughtException.setX(dragEvent.getScreenX() + exceptionAlertX.get()); + notCaughtException.setY(dragEvent.getScreenY() + exceptionAlertY.get()); + }); + window.setOnMousePressed(pressEvent -> { + exceptionAlertX.set(window.getX() - pressEvent.getSceneX()); + exceptionAlertY.set(window.getY() - pressEvent.getSceneY()); + }); + + notCaughtException.show(); + } + + public static Action getAction() { + return action; + } + + public static Logger getLogger() { + return logger; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/Test.java b/theosui/src/org/blueshard/theosUI/Test.java new file mode 100644 index 0000000..8ea06bf --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/Test.java @@ -0,0 +1,31 @@ +package org.blueshard.theosUI; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; +import org.blueshard.theosUI.theosFX.TFXFileItem; +import org.blueshard.theosUI.utils.UIUtils; + +public class Test extends Application { + + @Override + public void start(Stage primaryStage) throws Exception { + BorderPane main = new TFXFileItem("null", "null", "null"); + + Scene scene = new Scene(main); + + primaryStage.setTitle(UIUtils.HEADING); + primaryStage.setScene(scene); + + primaryStage.show(); + } + + public static void main(String[] args) { + launch(args); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/UIStarter/Login.java b/theosui/src/org/blueshard/theosUI/UIStarter/Login.java new file mode 100644 index 0000000..8ba0d89 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/UIStarter/Login.java @@ -0,0 +1,46 @@ +package org.blueshard.theosUI.UIStarter; + +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; +import javafx.stage.WindowEvent; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; +import org.blueshard.theosUI.utils.UIUtils; + +import java.io.IOException; + +public class Login { + + private final Stage rootStage = new Stage(); + + public Login(Window rootWindow) throws IOException { + rootStage.initOwner(rootWindow); + rootStage.initModality(Modality.WINDOW_MODAL); + + AnchorPane login = FXMLLoader.load(Login.class.getResource("../resources/login.fxml")); + Scene scene = new Scene(login); + + rootStage.setOnCloseRequest(event -> { + this.onClose(); + }); + + rootStage.setTitle(UIUtils.HEADING); + //rootStage.setResizable(false); + rootStage.setScene(scene); + } + + public void onClose() { + UIUtils.onClose(); + } + + public Stage getStage() { + return rootStage; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/UIStarter/Main.java b/theosui/src/org/blueshard/theosUI/UIStarter/Main.java new file mode 100644 index 0000000..ea11017 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/UIStarter/Main.java @@ -0,0 +1,43 @@ +package org.blueshard.theosUI.UIStarter; + +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; +import org.blueshard.theosUI.utils.UIUtils; + +import java.io.IOException; + +public class Main { + + private final Stage rootStage = new Stage(); + + public Main(Window rootWindow) throws IOException { + rootStage.initOwner(rootWindow); + rootStage.initModality(Modality.WINDOW_MODAL); + + AnchorPane login = FXMLLoader.load(Login.class.getResource("../resources/main.fxml")); + Scene scene = new Scene(login); + + rootStage.setOnCloseRequest(event -> this.onClose()); + + rootStage.setTitle(UIUtils.HEADING); + rootStage.setResizable(false); + rootStage.setScene(scene); + } + + public Stage getStage() { + return rootStage; + } + + public void onClose() { + UIUtils.onClose(); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/UIStarter/Register.java b/theosui/src/org/blueshard/theosUI/UIStarter/Register.java new file mode 100644 index 0000000..80ae85b --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/UIStarter/Register.java @@ -0,0 +1,45 @@ +package org.blueshard.theosUI.UIStarter; + +import javafx.application.Platform; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; +import javafx.stage.WindowEvent; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; +import org.blueshard.theosUI.utils.UIUtils; + +import java.io.IOException; + +public class Register { + + private final Stage rootStage = new Stage(); + + public Register(Window rootWindow) throws IOException { + rootStage.initOwner(rootWindow); + rootStage.initModality(Modality.WINDOW_MODAL); + + AnchorPane register = FXMLLoader.load(Register.class.getResource("../resources/register.fxml")); + Scene scene = new Scene(register); + + rootStage.setOnCloseRequest(event -> this.onClose()); + rootStage.setTitle(UIUtils.HEADING); + rootStage.setResizable(false); + rootStage.setScene(scene); + } + + public void onClose() { + rootStage.close(); + } + + public Stage getStage() { + return rootStage; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/client/Action.java b/theosui/src/org/blueshard/theosUI/client/Action.java new file mode 100644 index 0000000..f93ae59 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/client/Action.java @@ -0,0 +1,105 @@ +package org.blueshard.theosUI.client; + +import org.apache.log4j.Logger; +import org.blueshard.theosUI.data.Data; +import org.blueshard.theosUI.data.DataCodes; +import org.blueshard.theosUI.e2ee.E2EEConverter; +import org.blueshard.theosUI.e2ee.RSACipher; +import org.blueshard.theosUI.exception.ErrorCodes; +import org.blueshard.theosUI.exception.FatalIOException; +import org.blueshard.theosUI.exception.IllegalCodeException; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.security.Password; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.*; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.spec.InvalidKeySpecException; +import java.util.*; + + +public class Action { + + private final DataInputStream dataInputStream; + private final byte[] privateKey; + private final ServerSender serverSender; + + public Action(InputStream inputStream, byte[] privateKey, ServerSender serverSender) { + this.dataInputStream = new DataInputStream(inputStream); + this.privateKey = privateKey; + this.serverSender = serverSender; + } + + public Data decryptE2EEData() throws IOException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, UnexpectedException, InvalidKeyException, InvalidKeySpecException { + return new Data(E2EEConverter.decrypt(dataInputStream.readUTF(), privateKey)); + } + + public void closeConnection() { + serverSender.close(); + } + + public int login(String username, String clearPassword) throws IOException, InvalidKeySpecException, IllegalBlockSizeException, UnexpectedException, NoSuchPaddingException, InvalidKeyException, BadPaddingException { + Password.PasswordInfos passwordInfos = Password.createPassword(clearPassword, new byte[64]); + serverSender.login(username, passwordInfos); + return decryptE2EEData().getCode(); + } + + public boolean registerCode(String registerCode) throws IOException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, UnexpectedException, InvalidKeyException, InvalidKeySpecException { + serverSender.isRegisterCode(registerCode); + return Boolean.parseBoolean(decryptE2EEData().getFromData(DataCodes.Params.RegisterCode.REGISTERCODE)); + } + + public int register(String username, String clearPassword, String email) throws IOException, InvalidKeySpecException, IllegalBlockSizeException, UnexpectedException, NoSuchPaddingException, InvalidKeyException, BadPaddingException { + Password.PasswordInfos passwordInfos = Password.createPassword(clearPassword, new byte[64]); + serverSender.register(username, passwordInfos, email); + return decryptE2EEData().getCode(); + } + + public Object[] getFilesData(String directory) throws IOException, IllegalCodeException, BadPaddingException, IllegalBlockSizeException, UnexpectedException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException { + serverSender.getFilesData(directory); + Data data = decryptE2EEData(); + HashSet directories = new HashSet<>(); + HashMap files = new HashMap<>(); + if (data.getCode() != DataCodes.Server.SENDFILESDATA) { + throw new IllegalCodeException(data.getCode(), DataCodes.Server.SENDFILESDATA); + } + data.getData().forEach((index, file) -> { + if (index.startsWith("d")) { + directories.add(file); + } else { + files.put(file, index.substring(1)); + } + }); + + Object[] returnObjects = new Object[2]; + returnObjects[0] = directories; + returnObjects[1] = files; + + return returnObjects; + } + + public static Object[] initE2EE(InputStream inputStream, OutputStream outputStream, Logger logger) throws UnexpectedException, IOException { + Object[] returnArray = new Object[2]; + KeyPair keyPair = RSACipher.generateKeyPair(); + returnArray[0] = keyPair.getPrivate().getEncoded(); + + ServerSender.publicKey(keyPair.getPublic(), new DataOutputStream(outputStream), logger); + returnArray[1] = Base64.getDecoder().decode(new Data(new DataInputStream(inputStream).readUTF()).getFromData(DataCodes.Params.Key.PUBLICKEY)); + + + return returnArray; + } + + public boolean initConnection() throws BadPaddingException, InvalidKeySpecException, IOException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException, UnexpectedException, FatalIOException { + serverSender.firstConnect(); + Data result = decryptE2EEData(); + + if (!Boolean.parseBoolean(result.getFromData(DataCodes.Params.ClientAgent.VALIDAGENT))) { + throw new FatalIOException(ErrorCodes.invalid_client_agent, "Using an invalid client agent"); // this should never get thrown + } else return Boolean.parseBoolean(result.getFromData(DataCodes.Params.Update.UPDATE)); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/client/MainClient.java b/theosui/src/org/blueshard/theosUI/client/MainClient.java new file mode 100644 index 0000000..37d7f3a --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/client/MainClient.java @@ -0,0 +1,4 @@ +package org.blueshard.theosUI.client; + +public class MainClient { +} diff --git a/theosui/src/org/blueshard/theosUI/client/ServerSender.java b/theosui/src/org/blueshard/theosUI/client/ServerSender.java new file mode 100644 index 0000000..ab3f0bb --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/client/ServerSender.java @@ -0,0 +1,176 @@ +package org.blueshard.theosUI.client; + +import org.apache.log4j.Logger; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.data.Data; +import org.blueshard.theosUI.data.DataCodes; +import org.blueshard.theosUI.e2ee.E2EEConverter; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.security.Password; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.InvalidKeyException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class ServerSender { + + private final DataOutputStream dataOutputStream; + private final byte[] serverPublicKey; + private final Logger logger; + + public ServerSender(OutputStream outputStream, byte[] serverPublicKey, Logger logger) throws IllegalBlockSizeException, UnexpectedException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + this.dataOutputStream = new DataOutputStream(outputStream); + this.serverPublicKey = serverPublicKey; + this.logger = logger; + + if (serverPublicKey.length != 0) { + E2EEConverter.encrypt("Test", serverPublicKey); // just test if the server key works + } + } + + private void send(Data data) throws IOException { + if (serverPublicKey.length == 0) { + dataOutputStream.writeUTF(data.getDataAsString() + "\n"); + } else { + try { + dataOutputStream.writeUTF(E2EEConverter.encrypt(data.getDataAsString() + "\n", serverPublicKey)); + } catch (UnexpectedException e) { + logger.error("An unexpected error occurred", e); + unexpectedError(); + } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidKeySpecException ignore) { + } + } + dataOutputStream.flush(); + } + + private void send(Data.Builder data) throws IOException { + send(data.getData()); + } + + private String loggerInfo(String data) { + return "Send " + data + " data"; + } + + private String loggerWarning(String data) { + return "Failed to send " + data + " data"; + } + + public void close() { + try { + send(new Data.Builder(DataCodes.Client.CLOSE)); + logger.info(loggerInfo("close")); + } catch (IOException e) { + logger.warn(loggerWarning("close")); + } + } + + public void unexpectedError() { + try { + send(new Data.Builder(DataCodes.Client.UNEXPECTEDERROR)); + logger.info(loggerInfo("unexpected error")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected error"), e); + } + } + + public void unexpectedExit() { + try { + send(new Data.Builder(DataCodes.Client.UNEXPECTEDEXIT)); + logger.info(loggerInfo("unexpected close")); + } catch (IOException e) { + logger.warn(loggerWarning("unexpected close"), e); + } + } + + public void firstConnect() { + Data.Builder data = new Data.Builder(DataCodes.Client.FIRSTCONNECT); + data.addData(DataCodes.Params.ClientAgent.CLIENTAGENT, DataCodes.Params.ClientAgent.TheosUI); + data.addData(DataCodes.Params.Version.VERSION, Main.version); + + try { + send(data); + logger.info(loggerInfo("first connect")); + } catch (IOException e) { + logger.warn(loggerWarning("first connect"), e); + } + } + + //----- login / register -----// + + public void login(String username, Password.PasswordInfos passwordInfos) { + Data.Builder data = new Data.Builder(DataCodes.Client.LOGIN); + data.addData(DataCodes.Params.LogReg.USERNAME, username); + data.addData(DataCodes.Params.LogReg.PASSWORD, passwordInfos.getPasswordAsString()); + data.addData(DataCodes.Params.LogReg.SALT, passwordInfos.getSaltAsString()); + + try { + send(data); + logger.info(loggerInfo("login")); + } catch (IOException e) { + logger.warn(loggerWarning("login"), e); + } + } + + public void isRegisterCode(String registerCode) { + Data.Builder data = new Data.Builder(DataCodes.Client.REGISTERCODE); + data.addData(DataCodes.Params.RegisterCode.REGISTERCODE, registerCode); + + try { + send(data); + logger.info(loggerInfo("register code")); + } catch (IOException e) { + logger.warn(loggerWarning("register code"), e); + } + } + + public void register(String username, Password.PasswordInfos passwordInfos, String email) { + Data.Builder data = new Data.Builder(DataCodes.Client.REGISTER); + data.addData(DataCodes.Params.LogReg.USERNAME, username); + data.addData(DataCodes.Params.LogReg.PASSWORD, passwordInfos.getPasswordAsString()); + data.addData(DataCodes.Params.LogReg.SALT, passwordInfos.getSaltAsString()); + data.addData(DataCodes.Params.LogReg.EMAIL, email); + + try { + send(data); + logger.info(loggerInfo("register")); + } catch (IOException e) { + logger.warn(loggerWarning("register"), e); + } + } + + //----- files -----// + + public void getFilesData(String directory) { + Data.Builder data = new Data.Builder(DataCodes.Client.GETFILESDATA); + + data.addData(DataCodes.Params.File.STARTDIRECOTRY, directory); + try { + send(data); + logger.info(loggerInfo("get files data")); + } catch (IOException e) { + logger.warn(loggerWarning("get files data"), e); + } + } + + public static void publicKey(PublicKey publicKey, OutputStream outputStream, Logger logger) { + try { + Data.Builder data = new Data.Builder(DataCodes.Client.PUBLICKEY); + data.addData(DataCodes.Params.Key.PUBLICKEY, Base64.getEncoder().encodeToString(publicKey.getEncoded())); + + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + dataOutputStream.writeUTF(data.getDataAsString() + "\n"); + dataOutputStream.flush(); + + logger.info("Send public key data"); + } catch (IOException e) { + logger.warn("Failed to send public key data"); + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/config/Config.java b/theosui/src/org/blueshard/theosUI/config/Config.java new file mode 100644 index 0000000..2cc699c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/config/Config.java @@ -0,0 +1,67 @@ +package org.blueshard.theosUI.config; + +import org.apache.log4j.Level; +import org.blueshard.theosUI.files.ConfReader; +import org.blueshard.theosUI.files.ConfWriter; +import org.blueshard.theosUI.utils.OSUtils; + +import java.io.File; +import java.io.IOException; +import java.util.TreeMap; + +public class Config { + + private TreeMap configElements; + private final File configFile; + + public Config() throws IOException { + configFile = OSUtils.getLogFile(); + + if (!configFile.isFile()) { + File theosFolder = new File(configFile.getAbsolutePath().substring(0, configFile.getAbsolutePath().length() - configFile.getName().length())); + if (!theosFolder.isDirectory()) { + if (!theosFolder.mkdir()) { + throw new IOException("Couldn't create theos folder"); + } + } + if (!configFile.createNewFile()) { + throw new IOException("Couldn't create config file"); + } else { + configElements = new TreeMap<>(); + configElements.put(ConfigEntryKeys.LOGLEVEL, String.valueOf(Level.ALL.toInt())); + configElements.put(ConfigEntryKeys.FILELOGGING, String.valueOf(true)); + } + } else { + configElements = new ConfReader.SingleConfReader(configFile).getAll(); + } + } + + public boolean getFileLogging() { + return Boolean.parseBoolean(configElements.get(ConfigEntryKeys.FILELOGGING)); + } + + public void setFileLogging(boolean fileLogging) { + configElements.put(ConfigEntryKeys.FILELOGGING, String.valueOf(fileLogging)); + } + + public Level getLogLevel() { + return Level.toLevel(configElements.get(ConfigEntryKeys.LOGLEVEL)); + } + + public void setLogLevel(Level logLevel) { + configElements.replace(ConfigEntryKeys.LOGLEVEL, String.valueOf(logLevel.toInt())); + } + + private void write() throws IOException { + ConfWriter.SingleConfWriter config = new ConfWriter.SingleConfWriter(); + config.addAll(configElements); + + } + + private static class ConfigEntryKeys { + + public static final String FILELOGGING = "fileLogging"; + public static final String LOGLEVEL = "logLevel"; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/controller/LoginController.java b/theosui/src/org/blueshard/theosUI/controller/LoginController.java new file mode 100644 index 0000000..8cdd68e --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/controller/LoginController.java @@ -0,0 +1,117 @@ +package org.blueshard.theosUI.controller; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXTextField; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.log4j.Logger; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.UIStarter.Register; +import org.blueshard.theosUI.client.Action; +import org.blueshard.theosUI.data.DataCodes; +import org.blueshard.theosUI.exception.ErrorCodes; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.theosFX.TFXPasswordField; +import org.blueshard.theosUI.utils.SVGToGenericImage; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.ResourceBundle; + +public class LoginController implements Initializable { + + @FXML private AnchorPane root; + + @FXML private ImageView theosLogo; + @FXML private ImageView usernameImage; + @FXML private JFXTextField usernameInput; + @FXML private ImageView passwordImage; + @FXML private TFXPasswordField passwordInput; + @FXML private Button login; + @FXML private JFXButton passwordForget; + @FXML private Text result; + + private Action action; + private Logger logger = Main.getLogger(); + + public void toRegister() throws IOException { + Thread t = new Thread(() -> Platform.runLater(() -> ((Stage) root.getScene().getWindow()).close())); + t.start(); + new Register(((Stage) root.getScene().getWindow()).getOwner()).getStage().show(); + } + + public void login() throws IOException, InvalidKeySpecException, UnexpectedException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException { + int resultCode = action.login(usernameInput.getText(), passwordInput.getText()); + + switch (resultCode) { + case DataCodes.Server.LOGINFAIL: + result.setFill(Color.RED); + result.setText("Login fehlgeschlagen"); + logger.warn("Login failed"); + break; + case DataCodes.Server.LOGINSUCCESS: + result.setFill(Color.GREEN); + result.setText("Erfolgreich eingeloggt"); + logger.info("Logged in successfully"); + + Thread t = new Thread(() -> Platform.runLater(() -> { + ((Stage) root.getScene().getWindow()).close(); + })); + t.start(); + + break; + default: + result.setFill(Color.RED); + result.setText("Der Server hat eine unerwartete antwort gesendet, bitte erneut versuchen"); + String name = ""; + int code; + DataCodes.Server server = new DataCodes.Server(); + Field[] fields = ErrorCodes.class.getFields(); + + for (Field field : fields) { + try { + name = field.getName(); + code = (int) field.get(server); + if (code == resultCode) { + break; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + logger.warn("The server sent an unexpected result (" + name + ")"); + } + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + try { + theosLogo.setImage(new Image(new SVGToGenericImage(this.getClass().getResource("../resources/images/theos_logo.svg").getFile(), + SVGToGenericImage.Transcoder.PNG, (float) theosLogo.getFitHeight(), (float) theosLogo.getFitWidth()).asByteArrayInputStream())); + usernameImage.setImage(new Image(new SVGToGenericImage(this.getClass().getResource("../resources/images/user.svg").getFile(), + SVGToGenericImage.Transcoder.PNG, (float) usernameImage.getFitHeight(), (float) usernameImage.getFitWidth()).asByteArrayInputStream())); + passwordImage.setImage(new Image(new SVGToGenericImage(this.getClass().getResource("../resources/images/lock.svg").getFile(), + SVGToGenericImage.Transcoder.PNG, (float) usernameImage.getFitHeight(), (float) usernameImage.getFitWidth()).asByteArrayInputStream())); + } catch (TranscoderException | IOException e) { + e.printStackTrace(); + return; + } + + action = Main.getAction(); + } +} diff --git a/theosui/src/org/blueshard/theosUI/controller/RegisterController.java b/theosui/src/org/blueshard/theosUI/controller/RegisterController.java new file mode 100644 index 0000000..c18b82e --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/controller/RegisterController.java @@ -0,0 +1,126 @@ +package org.blueshard.theosUI.controller; + +import com.jfoenix.controls.JFXCheckBox; +import com.jfoenix.controls.JFXTextField; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.*; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import org.apache.log4j.Logger; +import org.blueshard.theosUI.UIStarter.Login; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.client.Action; +import org.blueshard.theosUI.data.DataCodes; +import org.blueshard.theosUI.exception.ErrorCodes; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.theosFX.TFXPasswordField; +import org.blueshard.theosUI.utils.UIUtils; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.ResourceBundle; + +public class RegisterController implements Initializable { + + @FXML private AnchorPane root; + @FXML private ImageView theosLogo; + @FXML private JFXTextField registerCode; + @FXML private JFXTextField usernameInput; + @FXML private JFXTextField mailInput; + @FXML private TFXPasswordField passwordInput; + @FXML private Text passwordSafety; + @FXML private TFXPasswordField rePasswordInput; + @FXML private Text passwordMatch; + @FXML private JFXCheckBox keepLoggedIn; + @FXML private Text result; + + private Action action = Main.getAction(); + private Logger logger = Main.getLogger(); + private boolean doPasswordsMatch = false; + + public void toLogin() throws IOException { + Thread t = new Thread(() -> Platform.runLater(() -> ((Stage) root.getScene().getWindow()).close())); + t.start(); + new Login(((Stage) root.getScene().getWindow()).getOwner()).getStage().show(); + } + public void register() throws IOException, InvalidKeySpecException, UnexpectedException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException { + if (!doPasswordsMatch) { + result.setFill(Color.RED); + result.setText("Die Passwörter stimmen nicht überein"); + } else if (!action.registerCode(registerCode.getText().trim())) { + result.setFill(Color.RED); + result.setText("Der Registrierungscode '" + registerCode.getText() + "' existiert nicht"); + } else { + int resultCode; + resultCode = action.register(usernameInput.getText(), passwordInput.getText(), mailInput.getText()); + + switch (resultCode) { + case DataCodes.Server.REGISTERFAIL: + result.setFill(Color.RED); + result.setText("Registrierung fehlgeschlagen"); + logger.warn("Register failed"); + break; + case DataCodes.Server.REGISTERFAIL_USER_EXIST: + result.setFill(Color.RED); + result.setText("Der Nutzer existiert bereits"); + logger.warn("Register failed, the user already exist"); + break; + case DataCodes.Server.REGISTERSUCCESS: + result.setFill(Color.GREEN); + result.setText("Erfolgreich registriert"); + logger.info("Registered successfully"); + break; + case DataCodes.Server.REGISTERCODE_NOT_EXIST: + result.setFill(Color.RED); + result.setText("Der Registrierungscode existiert nicht"); + logger.warn("Register failed, the register code doesn't exist"); + break; + default: + result.setFill(Color.RED); + result.setText("Der Server hat eine unerwartete antwort gesendet, bitte erneut versuchen"); + String name = ""; + int code; + DataCodes.Server server = new DataCodes.Server(); + Field[] fields = ErrorCodes.class.getFields(); + + for (Field field : fields) { + try { + name = field.getName(); + code = (int) field.get(server); + if (code == resultCode) { + break; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + logger.warn("The server sent an unexpected result (" + name + ")"); + } + } + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + rePasswordInput.addTextListener((observable, oldValue, newValue) -> { + if (!newValue.equals(passwordInput.getText())) { + passwordMatch.setVisible(true); + doPasswordsMatch = false; + } else { + passwordMatch.setVisible(false); + doPasswordsMatch = true; + } + }); + } +} diff --git a/theosui/src/org/blueshard/theosUI/controller/main/MainController.java b/theosui/src/org/blueshard/theosUI/controller/main/MainController.java new file mode 100644 index 0000000..786e728 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/controller/main/MainController.java @@ -0,0 +1,87 @@ +package org.blueshard.theosUI.controller.main; + +import com.jfoenix.controls.JFXButton; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.fxml.Initializable; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.image.ImageView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Pane; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.utils.UIUtils; + +import java.io.IOException; +import java.net.URL; +import java.util.ResourceBundle; + +public class MainController implements Initializable { + + private MainControllerUtils mainControllerUtils = new MainControllerUtils(this); + private MainControllerUtils.ServerStatusController serverStatusController = mainControllerUtils.getServerStatusController(); + + //main + + @FXML protected AnchorPane root; + @FXML protected Pane mainApplication; + @FXML protected TextField searchBar; + + //choose items + + @FXML protected JFXButton myFiles; + + //server status + + @FXML protected Label serverStatusText; + @FXML protected Label serverStatus; + @FXML protected ImageView serverStatusImage; + @FXML protected Label clientStatus; + @FXML protected ImageView clientStatusImage; + + public void onMyFiles() throws IOException { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("resources/myFiles.fxml")); + + MyFilesController myFilesController = new MyFilesController(); + + fxmlLoader.setController(myFilesController); + + searchBar.setPromptText("In '" + myFilesController.getWindowName() + "' suchen"); + + UIUtils.addAutocompleteToTextField(searchBar, myFilesController.getSearchItems().keySet()); + + mainApplication.getChildren().add(fxmlLoader.load()); + } + + public boolean isClientConnected() { + return serverStatusController.clientConnected; + } + + public void setClientConnected(boolean clientConnected) throws IOException, TranscoderException { + serverStatusController.setClientConnected(clientConnected); + } + + public boolean isServerOnline() { + return serverStatusController.serverOnline; + } + + public void setServerOnline(boolean serverOnline) throws IOException, TranscoderException { + serverStatusController.setServerOnline(serverOnline); + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + try { + setServerOnline(true); + setClientConnected(true); + } catch (IOException | TranscoderException e) { + e.printStackTrace(); + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/controller/main/MainControllerUtils.java b/theosui/src/org/blueshard/theosUI/controller/main/MainControllerUtils.java new file mode 100644 index 0000000..dd2fcd4 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/controller/main/MainControllerUtils.java @@ -0,0 +1,55 @@ +package org.blueshard.theosUI.controller.main; + +import javafx.scene.image.Image; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.theosFX.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; + +import java.io.IOException; + +public class MainControllerUtils { + + private MainController mainController; + + public MainControllerUtils(MainController mainController) { + this.mainController = mainController; + } + + public ServerStatusController getServerStatusController() { + return new ServerStatusController(); + } + + public class ServerStatusController { + + protected boolean clientConnected; + protected boolean serverOnline; + + public void setClientConnected(boolean clientConnected) throws IOException, TranscoderException { + this.clientConnected = clientConnected; + if (clientConnected) { + mainController.clientStatus.setText("Verbunden"); + mainController.clientStatusImage.setImage(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.green_dot).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) mainController.clientStatusImage.getFitHeight(), (float) mainController.clientStatusImage.getFitWidth()).asByteArrayInputStream())); + } else { + mainController.clientStatus.setText("Nicht verbunden"); + mainController.clientStatusImage.setImage(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.red_dot).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) mainController.clientStatusImage.getFitHeight(), (float) mainController.clientStatusImage.getFitWidth()).asByteArrayInputStream())); + } + } + + public void setServerOnline(boolean serverOnline) throws IOException, TranscoderException { + this.serverOnline = serverOnline; + if (serverOnline) { + mainController.serverStatus.setText("Online"); + mainController.serverStatusImage.setImage(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.green_dot).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) mainController.serverStatusImage.getFitHeight(), (float) mainController.serverStatusImage.getFitWidth()).asByteArrayInputStream())); + } else { + mainController.serverStatus.setText("Offline"); + mainController.serverStatusImage.setImage(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.red_dot).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) mainController.serverStatusImage.getFitHeight(), (float) mainController.serverStatusImage.getFitWidth()).asByteArrayInputStream())); + } + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/controller/main/MyFilesController.java b/theosui/src/org/blueshard/theosUI/controller/main/MyFilesController.java new file mode 100644 index 0000000..dd8c508 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/controller/main/MyFilesController.java @@ -0,0 +1,93 @@ +package org.blueshard.theosUI.controller.main; + +import com.jfoenix.controls.JFXButton; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.Main; +import org.blueshard.theosUI.client.Action; +import org.blueshard.theosUI.exception.IllegalCodeException; +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.theosFX.TFXFileItem; +import org.blueshard.theosUI.utils.SVGToGenericImage; +import org.blueshard.theosUI.utils.TheosUIImage; +import org.blueshard.theosUIWindow.Window; +import org.blueshard.theosUIWindow.WindowPreferences; + +import java.io.IOException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.util.*; + +public class MyFilesController extends Window implements Initializable { + + private Action action = Main.getAction(); + + @FXML private BorderPane root; + @FXML private JFXButton upload; + @FXML private VBox filesBox; + + public MyFilesController() { + super("Meine Dateien"); + } + + @Override + public Node searchContainer() { + ScrollPane searchContainer = new ScrollPane(); + searchContainer.setPrefSize(WindowPreferences.WIDTH, WindowPreferences.HEIGHT); + searchContainer.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + + return searchContainer; + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + try { + upload.setGraphic(new ImageView(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.option_dots).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) upload.getPrefHeight() - 10, (float) upload.getPrefWidth() - 10).asByteArrayInputStream()))); + } catch (TranscoderException | IOException e) { + e.printStackTrace(); + } + try { + Object[] filesData = action.getFilesData("/"); + HashSet directories = (HashSet) filesData[0]; + HashMap files = (HashMap) filesData[1]; + + String[] realFiles = new String[directories.size() + files.size()]; + + Iterator iterator = directories.iterator(); + int index = 0; + + while (iterator.hasNext()) { + realFiles[index] = iterator.next(); + index++; + } + + iterator = files.keySet().iterator(); + + while (iterator.hasNext()) { + realFiles[index] = iterator.next(); + } + + Arrays.sort(realFiles, String::compareToIgnoreCase); + + for (String realFile : realFiles) { + System.out.println(realFile); + TFXFileItem fileItem = new TFXFileItem(realFile, "Coming soon...", files.get(realFile)); + + fileItem.setPrefSize(filesBox.getPrefWidth(), filesBox.getPrefHeight()); + + filesBox.getChildren().add(fileItem); + addSearchItem(realFile, fileItem); + } + } catch (UnexpectedException | IOException | GeneralSecurityException | IllegalCodeException e) { + e.printStackTrace(); + } + } +} diff --git a/theosui/src/org/blueshard/theosUI/data/Data.java b/theosui/src/org/blueshard/theosUI/data/Data.java new file mode 100644 index 0000000..1a3da44 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/data/Data.java @@ -0,0 +1,163 @@ +package org.blueshard.theosUI.data; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class Data { + + private String dataAsString; + private Map data = new HashMap<>(); + + public Data(String data) { + this.dataAsString = data; + + String key = ""; + String dataString = dataAsString; + + String separator = getSeparator(); + try { + if (separator.length() == 1) { + dataString = dataString.substring(dataString.indexOf(",")).trim(); + } else { + dataString = dataString.substring(dataString.indexOf(",") + 1).trim(); + } + } catch (StringIndexOutOfBoundsException e) { + dataString = ""; + } + for (String string: dataString.split(separator)) { + string = string.trim(); + if (string.equals(":") || string.equals(",") || string.equals("{") || string.equals("}")) { + continue; + } else if (key.isEmpty()) { + key = string; + } else { + this.data.put(key, string); + key = ""; + } + } + } + + public int getCode() { + int lenBeforeCode = 1 + getSeparator().length() + 1; + return Integer.parseInt(dataAsString.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + } + + public Map getData() { + return data; + } + + public String getDataAsString() { + return dataAsString; + } + + public String getFromData(String key) { + return data.get(key); + } + + private String getSeparator() { + return dataAsString.substring(1).split(":")[0]; + } + + public static class Builder { + + private Map data = new HashMap<>(); + private int code; + + public Builder(int code) { + this.code = code; + } + + public String createData() { + String separator = createSeparator(); + + StringBuilder dataAsString = new StringBuilder("{" + separator + ":" + code); + data.forEach((key, value) -> dataAsString.append(",") + .append(separator) + .append(key) + .append(separator) + .append(":") + .append(separator) + .append(value) + .append(separator)); + dataAsString.append("}"); + + return dataAsString.toString(); + } + + public String createSeparator() { + char choice; + + StringBuilder stringBuilder = new StringBuilder(); + String indicator = "'"; + char[] choices = {'\'', '"', '^'}; + + data.forEach((key, value) -> stringBuilder.append(key).append(value)); + + String string = stringBuilder.toString(); + + while (true) { + if (string.contains(indicator)) { + switch (indicator) { + case "'": + indicator = "\""; + case "\"": + indicator = "^"; + default: { + choice = choices[new Random().nextInt(choices.length) - 1]; + if (indicator.contains("|")) { + String[] splitted_indicator = indicator.split("\\|"); + indicator = splitted_indicator[0] + choice + '|' + choice + splitted_indicator[1]; + } else { + indicator = indicator + choice + '|' + choice + indicator; + } + } + } + } else { + return indicator; + } + } + } + + public void addData(String key, String value) { + this.data.put(key, value); + } + + public void addAllData(Map allData) { + this.data.putAll(allData); + } + + public int getCode() { + return code; + } + + public Data getData() { + return new Data(getDataAsString()); + } + + public Map getDataMap() { + return data; + } + + public String getDataAsString() { + return createData(); + } + } + + public static boolean isDataString(String string) { + try { + string = string.trim(); + if (string.startsWith("{") && string.endsWith("}") && string.contains(":")) { + String separator = string.substring(1).split(":")[0]; + int lenBeforeCode = 1 + separator.length() + 1; + Integer.parseInt(string.substring(lenBeforeCode, lenBeforeCode + DataCodes.DATACODESLENGHT)); + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/data/DataCodes.java b/theosui/src/org/blueshard/theosUI/data/DataCodes.java new file mode 100644 index 0000000..a5a7ea1 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/data/DataCodes.java @@ -0,0 +1,155 @@ +package org.blueshard.theosUI.data; + +public class DataCodes { + + public static final int DATACODESLENGHT = 5; + + public static class Client { + + public static final int UNEXPECTEDERROR = 56400; + public static final int UNEXPECTEDEXIT = 95078; + + public static final int CLOSE = 69826; + + public static final int FIRSTCONNECT = 19938; + + public static final int PUBLICKEY = 19294; + + public static final int UPDATEYES = 80515; + public static final int UPDATENO = 38510; + + public static final int LOGIN = 39208; + public static final int REGISTERCODE = 18981; + public static final int REGISTER = 84219; + + public static final int GETFILESDATA = 28926; + public static final int GETFILE = 95868; + public static final int SENDFILE = 53639; + + } + + public static class Server { + + public static final int UNEXPECTEDERROR = 29875; + public static final int UNEXPECTEDEXIT = 85048; + + public static final int NOTLOGGEDIN = 77015; + + public static final int CLOSE = 42812; + + public static final int FIRSTCONNECT = 76896; + + public static final int PUBLICKEY = 19294; + + public static final int OPTIONALUPDATE = 12925; + public static final int REQUIREDUPDATE = 97103; + + public static final int LOGINFAIL = 11868; + public static final int LOGINSUCCESS = 54151; + public static final int REGISTERCODE_EXIST = 31166; + public static final int REGISTERCODE_NOT_EXIST = 47648; + public static final int REGISTERFAIL = 52300; + public static final int REGISTERFAIL_USER_EXIST= 77444; + public static final int REGISTERSUCCESS = 34367; + + public static final int RECEIVEFILEFAIL = 45747; + public static final int RECEIVEFILESUCCESS = 75368; + public static final int SENDFILESDATA = 78946; + public static final int SENDFILEFAIL = 90173; + public static final int SENDFILESSUCCESS = 37272; + + } + + public static class Params { + + public static class CheckSum { + + public static final String MD5 = "md5"; + + } + + public static class ClientAgent { + + public static final String CLIENTAGENT = "clientAgent"; + + public static final String VALIDAGENT = "validAgent"; + + public static final String TheosUI = "theosUI"; + + } + + public static class File { + + public static final String STARTDIRECOTRY = "startDirectory"; + public static final String FILEPATH = "filepath"; + + } + + public static class Key { + + public static final String PUBLICKEY = "key"; + + } + + public static class LogLevel { + + public static final String LOGLEVEL = "logLevel"; + + public static final String ALL = "0"; + public static final String WARNING = "1"; + public static final String NOTHING = "2"; + + } + + public static class LogReg { + + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String SALT = "salt"; + public static final String EMAIL = "email"; + + } + + public static class RegisterCode { + + public static final String REGISTERCODE = "registerCode"; + + } + + public static class Update { + + public static final String UPDATE = "update"; + + public static final String NEWVERSION = "newVersion"; + public static final String CHANGES = "changes"; + + } + + public static class UserLevel { + + public static final String USERLEVEL = "userLevel"; + + public static final String PUBLIC = "0"; + public static final String PROTECTED = "1"; + public static final String PRIVATE = "2"; + + } + + public static class State { + + public static final String STATE = "state"; + + public static final String ACTIVE = "active"; + public static final String DISABLED = "disabled"; + + } + + public static class Version { + + public static final String VERSION = "version"; + + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/e2ee/AESCipher.java b/theosui/src/org/blueshard/theosUI/e2ee/AESCipher.java new file mode 100644 index 0000000..cfde078 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/e2ee/AESCipher.java @@ -0,0 +1,48 @@ +package org.blueshard.theosUI.e2ee; + +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.utils.ExceptionUtils; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class AESCipher { + + private static final int keySize = 256; + + public static byte[] generateKey() throws UnexpectedException { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(keySize); + SecretKey secretKey = keyGenerator.generateKey(); + return secretKey.getEncoded(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] input, byte[] key) throws UnexpectedException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new UnexpectedException(e); + } + } + + public static byte[] decrypt(byte[] input, byte[] key) throws UnexpectedException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException { + try { + SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + return cipher.doFinal(input); + } catch (NoSuchPaddingException | NoSuchAlgorithmException e) { + throw new UnexpectedException(e); + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/e2ee/E2EEConverter.java b/theosui/src/org/blueshard/theosUI/e2ee/E2EEConverter.java new file mode 100644 index 0000000..6850825 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/e2ee/E2EEConverter.java @@ -0,0 +1,36 @@ +package org.blueshard.theosUI.e2ee; + +import org.blueshard.theosUI.exception.UnexpectedException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; + +public class E2EEConverter { + + private final static String separator = "@"; + + public static String decrypt(String input, byte[] privateKey) throws UnexpectedException, BadPaddingException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException { + String[] inputAsArray = input.split(separator); + String key = inputAsArray[0]; + String realInput = inputAsArray[1]; + + byte[] AESKey = RSACipher.decrypt(Base64.getDecoder().decode(key), privateKey); + + return new String(AESCipher.decrypt(Base64.getDecoder().decode(realInput), AESKey)); + } + + public static String encrypt(String input, byte[] publicKey) throws UnexpectedException, BadPaddingException, InvalidKeyException, IllegalBlockSizeException, InvalidKeySpecException { + byte[] AESKey = AESCipher.generateKey(); + + String encryptedKey = Base64.getEncoder().encodeToString(RSACipher.encrypt(AESKey, publicKey)); + String encryptedInput = Base64.getEncoder().encodeToString(AESCipher.encrypt(input.getBytes(StandardCharsets.UTF_8), AESKey)); + + return encryptedKey + separator + encryptedInput; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/e2ee/RSACipher.java b/theosui/src/org/blueshard/theosUI/e2ee/RSACipher.java new file mode 100644 index 0000000..635702e --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/e2ee/RSACipher.java @@ -0,0 +1,57 @@ +package org.blueshard.theosUI.e2ee; + +import org.blueshard.theosUI.exception.UnexpectedException; +import org.blueshard.theosUI.utils.ExceptionUtils; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.*; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RSACipher { + + private static final int keySize = 2048; + + public static KeyPair generateKeyPair() throws UnexpectedException { + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(keySize); + return keyPairGenerator.generateKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] encrypt(byte[] key, byte[] publicKey) throws UnexpectedException, InvalidKeyException, InvalidKeySpecException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); + RSAPublicKey publicRSAKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicRSAKey); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + + public static byte[] decrypt(byte[] key, byte[] privateKey) throws UnexpectedException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, BadPaddingException { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privatePKCS8Key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey)); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privatePKCS8Key); + return cipher.doFinal(key); + } catch (NoSuchAlgorithmException | IllegalBlockSizeException e) { + throw new UnexpectedException(ExceptionUtils.extractExceptionMessage(e)); + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/ErrorCodes.java b/theosui/src/org/blueshard/theosUI/exception/ErrorCodes.java new file mode 100644 index 0000000..6bb8c0d --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/ErrorCodes.java @@ -0,0 +1,7 @@ +package org.blueshard.theosUI.exception; + +public class ErrorCodes { + + public final static int invalid_client_agent = 148; + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/FatalIOException.java b/theosui/src/org/blueshard/theosUI/exception/FatalIOException.java new file mode 100644 index 0000000..bb49864 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/FatalIOException.java @@ -0,0 +1,17 @@ +package org.blueshard.theosUI.exception; + +public class FatalIOException extends Exception { + + private final int errno; + + public FatalIOException(int errno, String message) { + super("Errno: " + errno + " - " + message); + + this.errno = errno; + } + + public int getErrno() { + return errno; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/IllegalCodeException.java b/theosui/src/org/blueshard/theosUI/exception/IllegalCodeException.java new file mode 100644 index 0000000..f4b431c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/IllegalCodeException.java @@ -0,0 +1,15 @@ +package org.blueshard.theosUI.exception; + +public class IllegalCodeException extends Exception { + + private final int givenCode; + private final int requiredCode; + + public IllegalCodeException(int givenCode, int requiredCode){ + super("Wrong data code is given '" + givenCode + "', expected '" + requiredCode + "'"); + + this.givenCode = givenCode; + this.requiredCode = requiredCode; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/IllegalPasswordException.java b/theosui/src/org/blueshard/theosUI/exception/IllegalPasswordException.java new file mode 100644 index 0000000..0952317 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/IllegalPasswordException.java @@ -0,0 +1,9 @@ +package org.blueshard.theosUI.exception; + +public class IllegalPasswordException extends Exception { + + public IllegalPasswordException(String errorMessage){ + super(errorMessage); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/UnexpectedException.java b/theosui/src/org/blueshard/theosUI/exception/UnexpectedException.java new file mode 100644 index 0000000..cf7b192 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/UnexpectedException.java @@ -0,0 +1,23 @@ +package org.blueshard.theosUI.exception; + +public class UnexpectedException extends Exception { + + public UnexpectedException() { + super("An unexpected error occurred"); + } + + public UnexpectedException(Throwable t) { + super("An unexpected error occurred (" + t.getMessage() + ")"); + this.setStackTrace(t.getStackTrace()); + } + + public UnexpectedException(String message) { + super(message); + } + + public UnexpectedException(String message, Throwable t) { + super(message); + this.setStackTrace(t.getStackTrace()); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/UserAlreadyExistException.java b/theosui/src/org/blueshard/theosUI/exception/UserAlreadyExistException.java new file mode 100644 index 0000000..1d6d865 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/UserAlreadyExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.theosUI.exception; + +public class UserAlreadyExistException extends UserException { + + public UserAlreadyExistException(String username, String message) { + super(username, message); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/UserException.java b/theosui/src/org/blueshard/theosUI/exception/UserException.java new file mode 100644 index 0000000..bb29176 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/UserException.java @@ -0,0 +1,13 @@ +package org.blueshard.theosUI.exception; + +public class UserException extends Exception { + + final String username; + + public UserException(String username, String message) { + super(message); + + this.username = username; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/UserNotExistException.java b/theosui/src/org/blueshard/theosUI/exception/UserNotExistException.java new file mode 100644 index 0000000..e064d41 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/UserNotExistException.java @@ -0,0 +1,9 @@ +package org.blueshard.theosUI.exception; + +public class UserNotExistException extends UserException { + + public UserNotExistException(String username, String message){ + super(username, message); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/exception/UserNotLoggedInException.java b/theosui/src/org/blueshard/theosUI/exception/UserNotLoggedInException.java new file mode 100644 index 0000000..b691beb --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/exception/UserNotLoggedInException.java @@ -0,0 +1,8 @@ +package org.blueshard.theosUI.exception; + +public class UserNotLoggedInException extends UserException { + + public UserNotLoggedInException(String username, String message) { + super(username, message); + } +} diff --git a/theosui/src/org/blueshard/theosUI/files/ConfReader.java b/theosui/src/org/blueshard/theosUI/files/ConfReader.java new file mode 100644 index 0000000..71f188e --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/files/ConfReader.java @@ -0,0 +1,171 @@ +package org.blueshard.theosUI.files; + +import java.io.*; +import java.util.Map; +import java.util.TreeMap; + +public class ConfReader { + + public static class SingleConfReader { + + private File confFile; + private TreeMap entries = new TreeMap<>(); + + public SingleConfReader(File confFile) throws IOException { + initialize(confFile); + } + + public SingleConfReader(String confFile) throws IOException { + initialize(new File(confFile)); + } + + private void initialize(File confFile) throws IOException { + this.confFile = confFile; + + BufferedReader bufferedReader = new BufferedReader(new FileReader(confFile)); + String line; + + while ((line = bufferedReader.readLine()) != null) { + line = line.trim(); + + if (line.trim().isEmpty() || line.isEmpty()) { + entries.put("#", null); + } else if (line.contains("#")) { + entries.put("#", line.substring(1)); + } else { + String[] keyValue = line.split("=", 1); + + entries.put(keyValue[0].trim(), keyValue[1].trim()); + } + } + + bufferedReader.close(); + } + + public boolean containsKey(String sectionName, String key) { + return entries.containsKey(key); + } + + public boolean containsValue(String sectionName, String value) { + return entries.containsKey(value); + } + + public TreeMap getAll() { + return entries; + } + + public String getKey(String value) { + for (Map.Entry entry: entries.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String key) { + return entries.get(key); + } + + public void remove(String key) { + entries.remove(key); + } + + public void replace(String key, String newValue) { + entries.replace(key, newValue); + } + + } + + public static class MultipleConfReader { + + private File confFile; + private TreeMap> entries = new TreeMap<>(); + + public MultipleConfReader(File confFile) throws IOException { + initialize(confFile); + } + + public MultipleConfReader(String confFile) throws IOException { + initialize(new File(confFile)); + } + + private void initialize(File confFile) throws IOException { + this.confFile = confFile; + + BufferedReader bufferedReader = new BufferedReader(new FileReader(confFile)); + String currentSection = null; + TreeMap currentEntries = new TreeMap<>(); + String line; + + while ((line = bufferedReader.readLine()) != null) { + line = line.trim(); + + if (line.trim().isEmpty() || line.isEmpty()) { + currentEntries.put("#", null); + } else if (line.contains("#")) { + currentEntries.put("#", line.substring(1)); + } else if (line.startsWith("[") && line.endsWith("]")) { + if (currentSection != null) { + entries.put(currentSection, currentEntries); + } + currentSection = line.substring(1, line.length() - 1); + } else { + String[] keyValue = line.split("=", 1); + if (keyValue.length == 1) { + currentEntries.put(keyValue[0].trim(), ""); + } else { + currentEntries.put(keyValue[0].trim(), keyValue[1].trim()); + } + } + } + + bufferedReader.close(); + } + + public boolean containsKey(String sectionName, String key) { + return entries.get(sectionName).containsKey(key); + } + + public boolean containsValue(String sectionName, String value) { + return entries.get(sectionName).containsKey(value); + } + + public boolean containsSection(String sectionName) { + return entries.containsKey(sectionName); + } + + public TreeMap> getAll() { + return entries; + } + + public String getKey(String sectionName, String value) { + for (Map.Entry entry: entries.get(sectionName).entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String sectionName, String key) { + return entries.get(sectionName).get(key); + } + + public void remove(String sectionName, String key) { + entries.remove(sectionName).remove(key); + } + + public void removeSection(String sectionName) { + entries.remove(sectionName); + } + + public void replace(String sectionName, String key, String newValue) { + entries.get(sectionName).replace(key, newValue); + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/files/ConfWriter.java b/theosui/src/org/blueshard/theosUI/files/ConfWriter.java new file mode 100644 index 0000000..99472c4 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/files/ConfWriter.java @@ -0,0 +1,267 @@ +package org.blueshard.theosUI.files; + +import java.io.*; +import java.util.*; + +public class ConfWriter { + + + public static class SingleConfWriter { + + private TreeMap entries = new TreeMap<>(); + + public void write(String filename) throws IOException { + write(new File(filename)); + } + + public void write(File file) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + String key; + String value; + + for (Map.Entry entry: entries.entrySet()) { + key = entry.getKey(); + value = entry.getValue(); + + if (key.equals("#")) { + if (value == null) { + bufferedWriter.newLine(); + } else { + bufferedWriter.write(key + value); + } + } else { + bufferedWriter.write(key + " = " + value); + } + bufferedWriter.newLine(); + } + + bufferedWriter.flush(); + bufferedWriter.close(); + } + + public void add(String key, String value) { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + entries.put(key, value); + } + } + + public void addAll(TreeMap newEntries) { + TreeMap tempEntries = new TreeMap<>(); + + newEntries.forEach((key, value) -> { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + tempEntries.put(key, value); + } + }); + + entries.putAll(tempEntries); + } + + public void addBlankLine() { + TreeMap newEntries = entries; + + newEntries.put("#", null); + + entries = newEntries; + } + + public void addComment(String comment) { + TreeMap newEntries = entries; + + newEntries.put("#", comment); + + entries = newEntries; + } + + public TreeMap getAll() { + return entries; + } + + public void getAndAdd(String string) throws IOException { + getAndAdd(new File(string)); + } + + public void getAndAdd(File file) throws IOException { + entries.putAll(new ConfReader.SingleConfReader(file).getAll()); + } + + public String getKey(String value) { + for (Map.Entry entry: entries.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String key) { + return entries.get(key); + } + + public void remove(String key) { + entries.remove(key); + } + + public void replace(String key, String newValue) { + entries.replace(key, newValue); + } + + } + + public static class MultipleConfWriter { + + private TreeMap> entries = new TreeMap<>(); + + public void createNewSection(String sectionName) { + entries.put(sectionName, new TreeMap<>()); + } + + public void write(String filename) throws IOException { + write(new File(filename)); + } + + public void write(File file) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + String sectionKey; + String sectionValue; + + for (Map.Entry> entry: entries.entrySet()) { + String sectionName = entry.getKey(); + + bufferedWriter.write("[" + sectionName + "]"); + bufferedWriter.newLine(); + bufferedWriter.newLine(); + + for (Map.Entry sectionEntry: entries.get(sectionName).entrySet()) { + sectionKey = sectionEntry.getKey(); + sectionValue = sectionEntry.getValue(); + + if (sectionKey.equals("#")) { + if (sectionValue == null) { + bufferedWriter.newLine(); + } else { + bufferedWriter.write(sectionKey + sectionValue); + } + } else { + bufferedWriter.write(sectionKey + " = " + sectionValue); + } + bufferedWriter.newLine(); + } + } + + bufferedWriter.flush(); + bufferedWriter.close(); + } + + public void add(String sectionName, String key, String value) { + if (sectionName == null || key == null || !entries.containsKey(sectionName)) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + TreeMap newEntries = entries.get(sectionName); + newEntries.put(key, value); + entries.replace(sectionName, new TreeMap<>(newEntries)); + } + } + + public void addAll(String sectionName, TreeMap newEntries) { + TreeMap tempEntries = new TreeMap<>(); + + if (sectionName == null || !newEntries.containsKey(sectionName)) { + return; + } else { + newEntries.forEach((key, value) -> { + if (key == null) { + return; + } else if (key.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + key); + } else if (value.contains("#")) { + throw new IllegalArgumentException("Found '#' in " + value); + } else { + tempEntries.put(key, value); + } + }); + } + + TreeMap newSectionEntries = entries.get(sectionName); + newSectionEntries.putAll(tempEntries); + entries.replace(sectionName, new TreeMap<>(newSectionEntries)); + } + + public void addBlankLine(String sectionName) { + TreeMap newEntries = entries.get(sectionName); + + newEntries.put("#", null); + + entries.put(sectionName, newEntries); + } + + public void addComment(String sectionName, String comment) { + TreeMap newEntries = entries.get(sectionName); + + newEntries.put("#", comment); + + entries.put(sectionName, newEntries); + } + + public void addSingleConfWriter(String sectionName, SingleConfWriter singleConfWriter) { + entries.put(sectionName, singleConfWriter.entries); + } + + public TreeMap> getAll() { + return entries; + } + + public void getAndAdd(String string) throws IOException { + getAndAdd(new File(string)); + } + + public void getAndAdd(File file) throws IOException { + entries.putAll(new ConfReader.MultipleConfReader(file).getAll()); + } + + public String getKey(String sectionName, String value) { + for (Map.Entry entry: entries.get(sectionName).entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + + return null; + } + + public String getValue(String sectionName, String key) { + return entries.get(sectionName).get(key); + } + + public void remove(String sectionName, String key) { + entries.remove(sectionName).remove(key); + } + + public void removeSection(String sectionName) { + entries.remove(sectionName); + } + + public void replace(String sectionName, String key, String newValue) { + entries.get(sectionName).replace(key, newValue); + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/files/ServerFiles.java b/theosui/src/org/blueshard/theosUI/files/ServerFiles.java new file mode 100644 index 0000000..e106af9 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/files/ServerFiles.java @@ -0,0 +1,52 @@ +package org.blueshard.theosUI.files; + +public class ServerFiles { + + public static class logs { + + public final static String dir = "/srv/logs/"; + public final static String main_log = dir + "main.log"; + + } + + public static class ssl { + + public final static String dir = "/srv/ssl/"; + public final static String sslKey_cert = dir + "sslKey.cert"; + public final static String sslKeyStore_jks = dir + "sslKeyStore.jks"; + public final static String sslTrustStore_jks = dir + "sslTrustStore.jks"; + + } + + public static class users { + + public final static String dir = "/srv/users/"; + public final static String users_conf = dir + "/users.conf"; + + public static class user { + + public final String dir; + public final String user_conf; + public final String userfiles_conf; + + public user(String username) { + dir = "/srv/users/" + username + "/"; + user_conf = dir + "user.conf"; + userfiles_conf = dir + "userfiles.conf"; + } + + public static class userfiles { + + public final String dir; + + public userfiles(String username) { + dir = "/srv/users/" + username + "/userfiles/"; + } + + } + + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/logging/MainLogger.java b/theosui/src/org/blueshard/theosUI/logging/MainLogger.java new file mode 100644 index 0000000..1c19a7c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/logging/MainLogger.java @@ -0,0 +1,102 @@ +package org.blueshard.theosUI.logging; + +import org.apache.log4j.*; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.spi.ThrowableInformation; +import org.blueshard.theosUI.utils.ConsoleColors; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Locale; + +public class MainLogger { + + private final Logger logger = Logger.getLogger(MainLogger.class); + + public MainLogger(Level logLevel) throws IOException { + new MainLogger(logLevel, true, false, ""); + } + + public MainLogger(Level logLevel, String filename) throws IOException { + new MainLogger(logLevel, true, true, filename); + } + + public MainLogger(Level logLevel, boolean logConsole, boolean logFile, String filename) throws IOException { + logger.setLevel(logLevel); + + if (logConsole) { + ConsoleAppender consoleAppender = new ConsoleAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + DateFormat date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.GERMANY); + Level level = loggingEvent.getLevel(); + StringBuilder extraData = new StringBuilder(); + String color; + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + switch (loggingEvent.getLevel().toInt()) { + case Level.WARN_INT: + color = ConsoleColors.RED_BRIGHT; + case Level.ERROR_INT: + color = ConsoleColors.RED_BOLD + ConsoleColors.RED_UNDERLINED; + case Level.FATAL_INT: + color = ConsoleColors.BLACK; + default: + color = ""; + } + + if (throwableInformation != null) { + extraData.append(ConsoleColors.RED); + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return color + "[" + date.format(loggingEvent.getTimeStamp()) + "] " + level + ": " + loggingEvent.getMessage() + "\n" + extraData.toString() + ConsoleColors.RESET; + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }); + logger.addAppender(consoleAppender); + } + if (logFile) { + RollingFileAppender rollingFileAppender = new RollingFileAppender(new Layout() { + @Override + public String format(LoggingEvent loggingEvent) { + DateFormat date = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.GERMANY); + Level level = loggingEvent.getLevel(); + StringBuilder extraData = new StringBuilder(); + ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation(); + + if (throwableInformation != null) { + Arrays.asList(throwableInformation.getThrowable().getStackTrace()).forEach(stackTraceElement -> extraData.append(stackTraceElement).append("\n")); + } + return "[" + date.format(loggingEvent.getTimeStamp()) + "] " + level + ": " + loggingEvent.getMessage() + "\n" + extraData.toString(); + } + + @Override + public boolean ignoresThrowable() { + return false; + } + + @Override + public void activateOptions() { + + } + }, filename, true); + logger.addAppender(rollingFileAppender); + } + } + + public Logger getLogger() { + return logger; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/resources/css/TFXPasswordField.css b/theosui/src/org/blueshard/theosUI/resources/css/TFXPasswordField.css new file mode 100644 index 0000000..3b980f4 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/css/TFXPasswordField.css @@ -0,0 +1,8 @@ +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0, 0 0 1 0 ; + -fx-background-radius: 0 ; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/css/TFXTextField.css b/theosui/src/org/blueshard/theosUI/resources/css/TFXTextField.css new file mode 100644 index 0000000..3b980f4 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/css/TFXTextField.css @@ -0,0 +1,8 @@ +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0, 0 0 1 0 ; + -fx-background-radius: 0 ; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/download.svg b/theosui/src/org/blueshard/theosUI/resources/images/download.svg new file mode 100644 index 0000000..fe4470d --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/download.svg @@ -0,0 +1 @@ +Download \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/email.svg b/theosui/src/org/blueshard/theosUI/resources/images/email.svg new file mode 100644 index 0000000..46107f8 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/email.svg @@ -0,0 +1,2 @@ +Email \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/green_dot.svg b/theosui/src/org/blueshard/theosUI/resources/images/green_dot.svg new file mode 100644 index 0000000..9f4e287 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/green_dot.svg @@ -0,0 +1 @@ +Green dot \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/lock.svg b/theosui/src/org/blueshard/theosUI/resources/images/lock.svg new file mode 100644 index 0000000..7d3c303 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/lock.svg @@ -0,0 +1 @@ +Lock \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/option_dots.svg b/theosui/src/org/blueshard/theosUI/resources/images/option_dots.svg new file mode 100644 index 0000000..35bc5db --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/option_dots.svg @@ -0,0 +1 @@ +3 dots \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/password_hide.svg b/theosui/src/org/blueshard/theosUI/resources/images/password_hide.svg new file mode 100644 index 0000000..0ee3609 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/password_hide.svg @@ -0,0 +1,4 @@ +Password hide \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/password_show.svg b/theosui/src/org/blueshard/theosUI/resources/images/password_show.svg new file mode 100644 index 0000000..5f3744c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/password_show.svg @@ -0,0 +1,3 @@ +Password show \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/ping_0.svg b/theosui/src/org/blueshard/theosUI/resources/images/ping_0.svg new file mode 100644 index 0000000..afd0fda --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/ping_0.svg @@ -0,0 +1,3 @@ +Ping 0 \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/ping_1.svg b/theosui/src/org/blueshard/theosUI/resources/images/ping_1.svg new file mode 100644 index 0000000..e749dca --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/ping_1.svg @@ -0,0 +1,4 @@ +Ping 1 \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/ping_2.svg b/theosui/src/org/blueshard/theosUI/resources/images/ping_2.svg new file mode 100644 index 0000000..badcefd --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/ping_2.svg @@ -0,0 +1,4 @@ +Ping 2 \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/ping_3.svg b/theosui/src/org/blueshard/theosUI/resources/images/ping_3.svg new file mode 100644 index 0000000..9b5c5a0 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/ping_3.svg @@ -0,0 +1,3 @@ +Ping 3 \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/question_mark.svg b/theosui/src/org/blueshard/theosUI/resources/images/question_mark.svg new file mode 100644 index 0000000..b55732c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/question_mark.svg @@ -0,0 +1,2 @@ +Question mark \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/red_dot.svg b/theosui/src/org/blueshard/theosUI/resources/images/red_dot.svg new file mode 100644 index 0000000..5c840f6 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/red_dot.svg @@ -0,0 +1 @@ +Red dot \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/theos_logo.svg b/theosui/src/org/blueshard/theosUI/resources/images/theos_logo.svg new file mode 100644 index 0000000..a8f3ea3 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/theos_logo.svg @@ -0,0 +1,17 @@ +Theos Logo \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/images/user.svg b/theosui/src/org/blueshard/theosUI/resources/images/user.svg new file mode 100644 index 0000000..15828f0 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/images/user.svg @@ -0,0 +1 @@ +User \ No newline at end of file diff --git a/theosui/src/org/blueshard/theosUI/resources/login.fxml b/theosui/src/org/blueshard/theosUI/resources/login.fxml new file mode 100644 index 0000000..846c8f1 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/login.fxml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theosui/src/org/blueshard/theosUI/resources/main.fxml b/theosui/src/org/blueshard/theosUI/resources/main.fxml new file mode 100644 index 0000000..3ca55cc --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/main.fxml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
diff --git a/theosui/src/org/blueshard/theosUI/resources/myFiles.fxml b/theosui/src/org/blueshard/theosUI/resources/myFiles.fxml new file mode 100644 index 0000000..4c8ee28 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/myFiles.fxml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+
+
+ +
+
+
+
+ + + + + +
+
diff --git a/theosui/src/org/blueshard/theosUI/resources/question.png b/theosui/src/org/blueshard/theosUI/resources/question.png new file mode 100644 index 0000000..26b4c3d Binary files /dev/null and b/theosui/src/org/blueshard/theosUI/resources/question.png differ diff --git a/theosui/src/org/blueshard/theosUI/resources/register.fxml b/theosui/src/org/blueshard/theosUI/resources/register.fxml new file mode 100644 index 0000000..98dc1d3 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/resources/register.fxml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theosui/src/org/blueshard/theosUI/security/Password.java b/theosui/src/org/blueshard/theosUI/security/Password.java new file mode 100644 index 0000000..ae68b98 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/security/Password.java @@ -0,0 +1,72 @@ +package org.blueshard.theosUI.security; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Arrays; +import java.util.Base64; + +public class Password { + + public static PasswordInfos createNewPassword(String password) throws InvalidKeySpecException { + byte[] salt = new byte[64]; + /*SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(salt);*/ + return createPassword(password, salt); + } + + public static PasswordInfos createPassword(String password, byte[] salt) throws InvalidKeySpecException { + KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); + SecretKeyFactory factory = null; + try { + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException ignore) { + } + + byte[] hashedPassword; + try { + factory.generateSecret(keySpec).getEncoded(); + } catch (InvalidKeySpecException ignore) { + } + + hashedPassword = factory.generateSecret(keySpec).getEncoded(); + + return new PasswordInfos(hashedPassword, salt); + } + + public static class PasswordInfos { + + private final byte[] password; + private final byte[] salt; + + public PasswordInfos(byte[] password, byte[] salt) { + this.password = password; + this.salt = salt; + } + + public byte[] getPasswordAsBytes() { + return password; + } + + public String getPasswordAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(password); + } + + public byte[] getSaltAsBytes() { + return salt; + } + + public String getSaltAsString() { + Base64.Encoder encoder = Base64.getEncoder(); + + return encoder.encodeToString(salt); + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/ConsoleColors.java b/theosui/src/org/blueshard/theosUI/utils/ConsoleColors.java new file mode 100644 index 0000000..44bc5fb --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/ConsoleColors.java @@ -0,0 +1,76 @@ +package org.blueshard.theosUI.utils; + +public class ConsoleColors { + // Reset + public static final String RESET = "\033[0m"; // Test Reset + + // Regular Colors + public static final String BLACK = "\033[0;30m"; // BLACK + public static final String RED = "\033[0;31m"; // RED + public static final String GREEN = "\033[0;32m"; // GREEN + public static final String YELLOW = "\033[0;33m"; // YELLOW + public static final String BLUE = "\033[0;34m"; // BLUE + public static final String PURPLE = "\033[0;35m"; // PURPLE + public static final String CYAN = "\033[0;36m"; // CYAN + public static final String WHITE = "\033[0;37m"; // WHITE + + // Bold + public static final String BLACK_BOLD = "\033[1;30m"; // BLACK + public static final String RED_BOLD = "\033[1;31m"; // RED + public static final String GREEN_BOLD = "\033[1;32m"; // GREEN + public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW + public static final String BLUE_BOLD = "\033[1;34m"; // BLUE + public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE + public static final String CYAN_BOLD = "\033[1;36m"; // CYAN + public static final String WHITE_BOLD = "\033[1;37m"; // WHITE + + // Underline + public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK + public static final String RED_UNDERLINED = "\033[4;31m"; // RED + public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN + public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW + public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE + public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE + public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN + public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE + + // Background + public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK + public static final String RED_BACKGROUND = "\033[41m"; // RED + public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN + public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW + public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE + public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE + public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN + public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + + // High Intensity + public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK + public static final String RED_BRIGHT = "\033[0;91m"; // RED + public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN + public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW + public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE + public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE + public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN + public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE + + // Bold High Intensity + public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK + public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED + public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN + public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW + public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE + public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE + public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN + public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE + + // High Intensity backgrounds + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE +} diff --git a/theosui/src/org/blueshard/theosUI/utils/ExceptionUtils.java b/theosui/src/org/blueshard/theosUI/utils/ExceptionUtils.java new file mode 100644 index 0000000..58a104e --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/ExceptionUtils.java @@ -0,0 +1,15 @@ +package org.blueshard.theosUI.utils; + +import java.util.Arrays; + +public class ExceptionUtils { + + public static String extractExceptionMessage(Throwable throwable) { + StringBuilder stringBuilder = new StringBuilder(); + + Arrays.asList(throwable.getStackTrace()).forEach(stackTraceElement -> stringBuilder.append(stackTraceElement).append("\n")); + + return stringBuilder.toString(); + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/FileUtils.java b/theosui/src/org/blueshard/theosUI/utils/FileUtils.java new file mode 100644 index 0000000..b14b74d --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/FileUtils.java @@ -0,0 +1,70 @@ +package org.blueshard.theosUI.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; + +public class FileUtils { + + public static ArrayList getAllFilesInDirectory(String path) throws IOException { + ArrayList files = new ArrayList<>(); + Files.walk(Paths.get(path)).map(Path::toFile).forEach(files::add); + return files; + } + + public static File[] sortFilesInDirectory(File path) { + File[] files = path.listFiles(); + + Arrays.sort(files, (object1, object2) -> object1.getName().compareToIgnoreCase(object2.getName())); + + return files; + } + + public class CreateHashSum { + + String file; + + CreateHashSum(String file) { + this.file = file; + } + + public String MD5() throws IOException { + try { + StringBuilder hexString = new StringBuilder(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + + InputStream inputStream = Files.newInputStream(Paths.get(file)); + byte[] buffer = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + md5.update(buffer, 0 , length); + } + + byte[] digest = md5.digest(); + + for (byte b : digest) { + if ((0xff & b) < 0x10) { + hexString.append("0").append(Integer.toHexString((0xFF & b))); + } else { + hexString.append(Integer.toHexString(0xFF & b)); + } + } + + return hexString.toString(); + + } catch (NoSuchAlgorithmException ignore) { + return null; + } + } + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/OSUtils.java b/theosui/src/org/blueshard/theosUI/utils/OSUtils.java new file mode 100644 index 0000000..8ae5ed2 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/OSUtils.java @@ -0,0 +1,29 @@ +package org.blueshard.theosUI.utils; + +import com.sun.javafx.PlatformUtil; + +import java.io.File; + +public class OSUtils { + + public static File getConfigFile() { + if (PlatformUtil.isLinux() || PlatformUtil.isUnix()) { + return new File(System.getProperty("user.home") + ".theos/theos.conf"); + } else if (PlatformUtil.isWindows()) { + return new File("C:\\Users\\" + System.getProperty("user.name") + "\\AppData\\Roaming\\Theos\\theos.config"); + } else { + return new File("theos.config"); + } + } + + public static File getLogFile() { + if (PlatformUtil.isLinux() || PlatformUtil.isUnix()) { + return new File(System.getProperty("user.home") + ".theos/theos.log"); + } else if (PlatformUtil.isWindows()) { + return new File("C:\\Users\\" + System.getProperty("user.name") + "\\AppData\\Theos\\theos.log"); + } else { + return new File("theos.log"); + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/SVGToGenericImage.java b/theosui/src/org/blueshard/theosUI/utils/SVGToGenericImage.java new file mode 100644 index 0000000..959466c --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/SVGToGenericImage.java @@ -0,0 +1,76 @@ +//http://batik.2283329.n4.nabble.com/Help-with-transcoding-SVG-to-PNG-Batik-1-9-td4656983.html + +package org.blueshard.theosUI.utils; + +import org.apache.batik.transcoder.SVGAbstractTranscoder; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.image.ImageTranscoder; +import org.apache.batik.transcoder.image.JPEGTranscoder; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.apache.batik.transcoder.image.TIFFTranscoder; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; + +public class SVGToGenericImage { + + private final ByteArrayOutputStream genericImage; + + public SVGToGenericImage(String file, Transcoder transcoder, float height, float width) throws TranscoderException, IOException { + this.genericImage = convert(new FileInputStream(file), transcoder, height, width); + } + + public SVGToGenericImage(InputStream inputStream, Transcoder transcoder, float height, float width) throws TranscoderException, IOException { + this.genericImage = convert(inputStream, transcoder, height, width); + } + + private ByteArrayOutputStream convert(InputStream inputStream, Transcoder transcoder, float height, float width) throws TranscoderException { + ImageTranscoder imageTranscoder; + + if (transcoder.equals(Transcoder.JPEG)) { + imageTranscoder = new JPEGTranscoder(); + } else if (transcoder.equals(Transcoder.PNG)) { + imageTranscoder = new PNGTranscoder(); + } else if (transcoder.equals(Transcoder.TIFF)) { + imageTranscoder = new TIFFTranscoder(); + } else { + return null; + } + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + TranscoderInput input = new TranscoderInput(inputStream); + TranscoderOutput output = new TranscoderOutput(byteArrayOutputStream); + + imageTranscoder.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, height); + imageTranscoder.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, width); + + imageTranscoder.transcode(input, output); + + return byteArrayOutputStream; + } + + public BufferedImage asBufferedImage() throws IOException { + return ImageIO.read(asByteArrayInputStream()); + } + + public ByteArrayInputStream asByteArrayInputStream() { + return new ByteArrayInputStream(genericImage.toByteArray()); + } + + public ByteArrayOutputStream asByteArrayOutputStream() { + return genericImage; + } + + public enum Transcoder { + + JPEG, + PNG, + TIFF + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/SizeUnit.java b/theosui/src/org/blueshard/theosUI/utils/SizeUnit.java new file mode 100644 index 0000000..d221a64 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/SizeUnit.java @@ -0,0 +1,196 @@ +package org.blueshard.theosUI.utils; + +public class SizeUnit { + + private int unit; + private double size; + + private final static int BYTE = 1; + private final static int KILOBYTE = 3; + private final static int MEGABYTE = 5; + private final static int GIGABYTE = 7; + private final static int TERRABYTE = 9; + private final static int PETABYTE = 11; + private final static int EXABYTE = 13; + + SizeUnit(int unit, double size){ + this.unit = unit; + this.size = size; + } + + public static SizeUnit BYTES(double bytes){ + return new SizeUnit(BYTE, bytes); + } + + public static SizeUnit KILOBYTE(double kilobytes) { + return new SizeUnit(KILOBYTE, kilobytes); + } + + public static SizeUnit MEGABYTE(double megabytes) { + return new SizeUnit(MEGABYTE, megabytes); + } + + public static SizeUnit GIGABYTE(double gigabytes) { + return new SizeUnit(GIGABYTE, gigabytes); + } + + public static SizeUnit TERRABYTE(double terrabytes) { + return new SizeUnit(TERRABYTE, terrabytes); + } + + public static SizeUnit PETABYTE(double petabytes) { + return new SizeUnit(PETABYTE, petabytes); + } + + public static SizeUnit EXABYTE(double exabytes) { + return new SizeUnit(EXABYTE, exabytes); + } + + public Double toByte(){ + switch (unit) { + case BYTE: + return size; + case KILOBYTE: + return size * 1000; + case MEGABYTE: + return size * 1000000; + case GIGABYTE: + return size * 1000000000; + case TERRABYTE: + return size * 1000000000000L; + case PETABYTE: + return size * 1000000000000000L; + case EXABYTE: + return size * 1000000000000000000L; + default: + return 0D; + } + } + + public Double toKilobyte(){ + switch (unit) { + case BYTE: + return size / 1000; + case KILOBYTE: + return size; + case MEGABYTE: + return size * 1000; + case GIGABYTE: + return size * 1000000; + case TERRABYTE: + return size * 1000000000; + case PETABYTE: + return size * 1000000000000L; + case EXABYTE: + return size * 1000000000000000L; + default: + return 0D; + } + } + + public Double toMegabyte(){ + switch (unit) { + case BYTE: + return size / 1000000; + case KILOBYTE: + return size / 1000; + case MEGABYTE: + return size; + case GIGABYTE: + return size * 1000; + case TERRABYTE: + return size * 1000000; + case PETABYTE: + return size * 1000000000; + case EXABYTE: + return size * 1000000000000L; + default: + return 0D; + } + } + + public Double toGigabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000L; + case KILOBYTE: + return size / 1000000; + case MEGABYTE: + return size / 1000; + case GIGABYTE: + return size; + case TERRABYTE: + return size * 1000; + case PETABYTE: + return size * 1000000; + case EXABYTE: + return size * 1000000000; + default: + return 0D; + } + } + + public Double toTerrabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000L; + case KILOBYTE: + return size / 1000000000; + case MEGABYTE: + return size / 1000000; + case GIGABYTE: + return size / 1000; + case TERRABYTE: + return size; + case PETABYTE: + return size * 1000; + case EXABYTE: + return size * 1000000; + default: + return 0D; + } + } + + public Double toPetabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000000L; + case KILOBYTE: + return size / 1000000000000L; + case MEGABYTE: + return size / 1000000000; + case GIGABYTE: + return size / 1000000; + case TERRABYTE: + return size / 1000; + case PETABYTE: + return size; + case EXABYTE: + return size * 1000; + default: + return 0D; + } + } + + public Double toExabyte(){ + switch (unit) { + case BYTE: + return size / 1000000000000000000L; + case KILOBYTE: + return size / 1000000000000000L; + case MEGABYTE: + return size / 1000000000000L; + case GIGABYTE: + return size / 1000000000; + case TERRABYTE: + return size / 1000000; + case PETABYTE: + return size / 1000; + case EXABYTE: + return size; + default: + return 0D; + } + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/StringUtils.java b/theosui/src/org/blueshard/theosUI/utils/StringUtils.java new file mode 100644 index 0000000..9754502 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/StringUtils.java @@ -0,0 +1,17 @@ +package org.blueshard.theosUI.utils; + +import java.util.Map; + +public class StringUtils { + + public static String format(String string, Map formatMap){ + + for(Map.Entry entry: formatMap.entrySet()) { + string = string.replace("{" + entry.getKey() + "}", entry.getValue()); + } + + return string; + + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/TheosFile.java b/theosui/src/org/blueshard/theosUI/utils/TheosFile.java new file mode 100644 index 0000000..55d5c86 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/TheosFile.java @@ -0,0 +1,33 @@ +package org.blueshard.theosUI.utils; + +public class TheosFile { + + private final String filename; + private final String path; + private final SizeUnit size; + private final String dateOfUpload; + + public TheosFile(String filename, String path, SizeUnit size, String dateOfUpload) { + this.filename = filename; + this.path = path; + this.size = size; + this.dateOfUpload = dateOfUpload; + } + + public String getFilename() { + return filename; + } + + public String getPath() { + return path; + } + + public SizeUnit getSize() { + return size; + } + + public String getDateOfUpload() { + return dateOfUpload; + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/TheosUIImage.java b/theosui/src/org/blueshard/theosUI/utils/TheosUIImage.java new file mode 100644 index 0000000..c00c7bf --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/TheosUIImage.java @@ -0,0 +1,44 @@ +package org.blueshard.theosUI.utils; + +import org.blueshard.theosUI.Main; + +import java.io.InputStream; +import java.net.URL; + +public class TheosUIImage { + + private URL imageURL; + private InputStream imageStream; + + public TheosUIImage(ImageName imageName) { + imageURL = Main.class.getResource("resources/images/" + imageName.name() + ".svg"); + imageStream = Main.class.getResourceAsStream("resources/images/" + imageName.name() + ".svg"); + } + + public URL asURL() { + return imageURL; + } + + public InputStream asStream() { + return imageStream; + } + + public enum ImageName { + option_dots, + download, + email, + green_dot, + lock, + password_hide, + password_show, + ping_0, + ping_1, + ping_2, + ping_3, + question_mark, + red_dot, + theos_logo, + user + } + +} diff --git a/theosui/src/org/blueshard/theosUI/utils/UIUtils.java b/theosui/src/org/blueshard/theosUI/utils/UIUtils.java new file mode 100644 index 0000000..98cbd42 --- /dev/null +++ b/theosui/src/org/blueshard/theosUI/utils/UIUtils.java @@ -0,0 +1,124 @@ +package org.blueshard.theosUI.utils; + +import com.sun.javafx.css.SizeUnits; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Side; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.Pane; +import org.apache.batik.transcoder.TranscoderException; +import org.blueshard.theosUI.Main; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +public class UIUtils { + + public static final String HEADING = "TheosUI | Version 0.1.0"; + + public static void advancedTooltipInstall(Node node, Tooltip tooltip, int delay) { + node.setOnMouseEntered(event -> Platform.runLater(() -> { + node.onMouseEnteredProperty(); + Thread thread = new Thread(() -> { + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Platform.runLater(() -> tooltip.show(node.getScene().getWindow(), event.getScreenX(), event.getScreenY() + 15)); + }); + thread.start(); + })); + node.setOnMouseExited(event -> Platform.runLater(() -> { + node.onMouseExitedProperty(); + tooltip.hide(); + })); + } + + public static void addAutocompleteToTextField(TextField textField, Set entries) { + ContextMenu autocompletePopup = new ContextMenu(); + + for (String s: entries) { + MenuItem menuItem = new MenuItem(s); + + menuItem.setOnAction(event -> textField.setText(menuItem.getText())); + + autocompletePopup.getItems().add(menuItem); + } + + textField.textProperty().addListener((observable, oldValue, newValue) -> { + if (newValue.isEmpty()) { + autocompletePopup.hide(); + } else { + autocompletePopup.show(textField, Side.BOTTOM, 0, 0); + } + }); + } + + public static BorderPane createFileItem(TheosFile theosFile, boolean download) throws IOException, TranscoderException { + BorderPane fileItem = FXMLLoader.load(Main.class.getResource("resources/myFiles.fxml")); + + ImageView fileImage = (ImageView) fileItem.lookup("#fileImage"); + fileImage.setImage(new Image(new SVGToGenericImage(new TheosUIImage(TheosUIImage.ImageName.question_mark).asStream(), + SVGToGenericImage.Transcoder.PNG, (float) fileImage.getFitHeight(), (float) fileImage.getFitWidth()).asByteArrayInputStream())); + + Button fileName = (Button) fileItem.lookup("#fileName"); + fileName.setText(theosFile.getFilename()); + + Label date = (Label) fileItem.lookup("#date"); + date.setText(theosFile.getDateOfUpload()); + + Label size = (Label) fileItem.lookup("#size"); + size.setText(theosFile.getSize().toMegabyte() + "MB"); + + return fileItem; + } + + public static void errorAlert(String title, String message, Throwable throwable) { + Alert alert = new Alert(Alert.AlertType.ERROR, message, ButtonType.OK); + + if (title == null) { + alert.setTitle("Error"); + } else { + alert.setTitle(title); + } + + if (message == null) { + message = "Error"; + } + if (throwable == null) { + alert.getDialogPane().setContent(new Label("Error: " + message)); + } else { + alert.getDialogPane().setContent(new Label("Error: " + message + "\n\n" + throwable)); + } + + alert.show(); + } + + public static void onClose() { + Platform.exit(); + Main.getAction().closeConnection(); + } + + public static void warningAlert(String title, String message) { + Alert alert = new Alert(Alert.AlertType.WARNING, message, ButtonType.OK); + + if (title == null) { + alert.setTitle("Warning"); + } else { + alert.setTitle(title); + } + alert.getDialogPane().setContent(new Label(message)); + alert.show(); + } + +} diff --git a/theosui/thoesui.iml b/theosui/thoesui.iml new file mode 100644 index 0000000..cb1e4ff --- /dev/null +++ b/theosui/thoesui.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file