Initial commit
This commit is contained in:
commit
691021ca70
3
README.md
Normal file
3
README.md
Normal file
@ -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.
|
BIN
lib/animatefx-1.2.1.jar
Normal file
BIN
lib/animatefx-1.2.1.jar
Normal file
Binary file not shown.
BIN
lib/controlsfx-8.40.17.jar
Normal file
BIN
lib/controlsfx-8.40.17.jar
Normal file
Binary file not shown.
BIN
lib/hsqldb/hsqldb.jar
Normal file
BIN
lib/hsqldb/hsqldb.jar
Normal file
Binary file not shown.
BIN
lib/hsqldb/servlet-2_3-fcs-classfiles.zip
Normal file
BIN
lib/hsqldb/servlet-2_3-fcs-classfiles.zip
Normal file
Binary file not shown.
BIN
lib/hsqldb/sqltool.jar
Normal file
BIN
lib/hsqldb/sqltool.jar
Normal file
Binary file not shown.
BIN
lib/log4j-1.2.17.jar
Normal file
BIN
lib/log4j-1.2.17.jar
Normal file
Binary file not shown.
58
src/org/blueshard/olymp/Main.java
Normal file
58
src/org/blueshard/olymp/Main.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
20
src/org/blueshard/olymp/cli/Main.java
Normal file
20
src/org/blueshard/olymp/cli/Main.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
15
src/org/blueshard/olymp/cli/SQLCli.java
Normal file
15
src/org/blueshard/olymp/cli/SQLCli.java
Normal file
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
166
src/org/blueshard/olymp/data/Data.java
Normal file
166
src/org/blueshard/olymp/data/Data.java
Normal file
@ -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<String, String> 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<String, String> 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<String, String> 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<String, String> allData) {
|
||||
this.data.putAll(allData);
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public Data getData() {
|
||||
return new Data(getDataAsString());
|
||||
}
|
||||
|
||||
public Map<String, String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
156
src/org/blueshard/olymp/data/DataCodes.java
Normal file
156
src/org/blueshard/olymp/data/DataCodes.java
Normal file
@ -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";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
48
src/org/blueshard/olymp/e2ee/AESCipher.java
Normal file
48
src/org/blueshard/olymp/e2ee/AESCipher.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
36
src/org/blueshard/olymp/e2ee/E2EEConverter.java
Normal file
36
src/org/blueshard/olymp/e2ee/E2EEConverter.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
57
src/org/blueshard/olymp/e2ee/RSACipher.java
Normal file
57
src/org/blueshard/olymp/e2ee/RSACipher.java
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
src/org/blueshard/olymp/exception/ErrorCodes.java
Normal file
24
src/org/blueshard/olymp/exception/ErrorCodes.java
Normal file
@ -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;
|
||||
|
||||
}
|
30
src/org/blueshard/olymp/exception/FatalIOException.java
Normal file
30
src/org/blueshard/olymp/exception/FatalIOException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
15
src/org/blueshard/olymp/exception/IllegalCodeException.java
Normal file
15
src/org/blueshard/olymp/exception/IllegalCodeException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.olymp.exception;
|
||||
|
||||
public class IllegalPasswordException extends Exception {
|
||||
|
||||
public IllegalPasswordException(String errorMessage){
|
||||
super(errorMessage);
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
23
src/org/blueshard/olymp/exception/UnexpectedException.java
Normal file
23
src/org/blueshard/olymp/exception/UnexpectedException.java
Normal file
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.olymp.exception;
|
||||
|
||||
public class UserAlreadyExistException extends UserException {
|
||||
|
||||
public UserAlreadyExistException(String username, String message) {
|
||||
super(username, message);
|
||||
}
|
||||
|
||||
}
|
13
src/org/blueshard/olymp/exception/UserException.java
Normal file
13
src/org/blueshard/olymp/exception/UserException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.olymp.exception;
|
||||
|
||||
public class UserNotExistException extends UserException {
|
||||
|
||||
public UserNotExistException(String username, String message){
|
||||
super(username, message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package org.blueshard.olymp.exception;
|
||||
|
||||
public class UserNotLoggedInException extends UserException {
|
||||
|
||||
public UserNotLoggedInException(String username, String message) {
|
||||
super(username, message);
|
||||
}
|
||||
}
|
209
src/org/blueshard/olymp/files/ConfReader.java
Normal file
209
src/org/blueshard/olymp/files/ConfReader.java
Normal file
@ -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<String, String> 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<String, String> getAll() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public TreeMap<String, String> getAll(boolean onlyText) {
|
||||
if (onlyText) {
|
||||
TreeMap<String, String> returnEntries = entries;
|
||||
returnEntries.entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#"));
|
||||
return returnEntries;
|
||||
} else {
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
public String getKey(String value) {
|
||||
for (Map.Entry<String, String> 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<String, TreeMap<String, String>> 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<String, String> 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<String, TreeMap<String, String>> getAll() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public TreeMap<String, TreeMap<String, String>> getAll(boolean onlyText) {
|
||||
if (onlyText) {
|
||||
TreeMap<String, TreeMap<String, String>> returnEntries = entries;
|
||||
for (Map.Entry<String, TreeMap<String, String>> entry : entries.entrySet()) {
|
||||
entry.getValue().entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#"));
|
||||
}
|
||||
return returnEntries;
|
||||
} else {
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
public TreeMap<String, String> getAll(String sectionName) {
|
||||
TreeMap<String, String> returnEntries = entries.get(sectionName);
|
||||
returnEntries.entrySet().removeIf(stringStringEntry -> stringStringEntry.getKey().equals("#"));
|
||||
return returnEntries;
|
||||
}
|
||||
|
||||
public TreeMap<String, String> getAll(String sectionName, boolean onlyText) {
|
||||
if (onlyText) {
|
||||
TreeMap<String, String> 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<String, String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
267
src/org/blueshard/olymp/files/ConfWriter.java
Normal file
267
src/org/blueshard/olymp/files/ConfWriter.java
Normal file
@ -0,0 +1,267 @@
|
||||
package org.blueshard.olymp.files;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ConfWriter {
|
||||
|
||||
|
||||
public static class SingleConfWriter {
|
||||
|
||||
private TreeMap<String, String> 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<String, String> 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<String, String> newEntries) {
|
||||
TreeMap<String, String> 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<String, String> newEntries = entries;
|
||||
|
||||
newEntries.put("#", null);
|
||||
|
||||
entries = newEntries;
|
||||
}
|
||||
|
||||
public void addComment(String comment) {
|
||||
TreeMap<String, String> newEntries = entries;
|
||||
|
||||
newEntries.put("#", comment);
|
||||
|
||||
entries = newEntries;
|
||||
}
|
||||
|
||||
public TreeMap<String, String> 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<String, String> 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<String, TreeMap<String, String>> 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<String, TreeMap<String, String>> entry: entries.entrySet()) {
|
||||
String sectionName = entry.getKey();
|
||||
|
||||
bufferedWriter.write("[" + sectionName + "]");
|
||||
bufferedWriter.newLine();
|
||||
bufferedWriter.newLine();
|
||||
|
||||
for (Map.Entry<String, String> 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<String, String> newEntries = entries.get(sectionName);
|
||||
newEntries.put(key, value);
|
||||
entries.replace(sectionName, new TreeMap<>(newEntries));
|
||||
}
|
||||
}
|
||||
|
||||
public void addAll(String sectionName, TreeMap<String, String> newEntries) {
|
||||
TreeMap<String, String> 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<String, String> newSectionEntries = entries.get(sectionName);
|
||||
newSectionEntries.putAll(tempEntries);
|
||||
entries.replace(sectionName, new TreeMap<>(newSectionEntries));
|
||||
}
|
||||
|
||||
public void addBlankLine(String sectionName) {
|
||||
TreeMap<String, String> newEntries = entries.get(sectionName);
|
||||
|
||||
newEntries.put("#", null);
|
||||
|
||||
entries.put(sectionName, newEntries);
|
||||
}
|
||||
|
||||
public void addComment(String sectionName, String comment) {
|
||||
TreeMap<String, String> 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<String, TreeMap<String, String>> 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<String, String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
39
src/org/blueshard/olymp/files/ServerFiles.java
Normal file
39
src/org/blueshard/olymp/files/ServerFiles.java
Normal file
@ -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 + "/";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
76
src/org/blueshard/olymp/fileserver/FileReceiver.java
Normal file
76
src/org/blueshard/olymp/fileserver/FileReceiver.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
74
src/org/blueshard/olymp/fileserver/FileSender.java
Normal file
74
src/org/blueshard/olymp/fileserver/FileSender.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
102
src/org/blueshard/olymp/logging/ClientLogger.java
Normal file
102
src/org/blueshard/olymp/logging/ClientLogger.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
14
src/org/blueshard/olymp/logging/EmptyLogger.java
Normal file
14
src/org/blueshard/olymp/logging/EmptyLogger.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
15
src/org/blueshard/olymp/logging/LogDeleter.java
Normal file
15
src/org/blueshard/olymp/logging/LogDeleter.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
92
src/org/blueshard/olymp/logging/ServerLogger.java
Normal file
92
src/org/blueshard/olymp/logging/ServerLogger.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
95
src/org/blueshard/olymp/register_code/RegisterCode.java
Normal file
95
src/org/blueshard/olymp/register_code/RegisterCode.java
Normal file
@ -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<String> getAllRegisterCodes() throws FatalIOException {
|
||||
HashSet<String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
67
src/org/blueshard/olymp/security/Password.java
Normal file
67
src/org/blueshard/olymp/security/Password.java
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
133
src/org/blueshard/olymp/server/Action.java
Normal file
133
src/org/blueshard/olymp/server/Action.java
Normal file
@ -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));
|
||||
}
|
||||
|
||||
}
|
86
src/org/blueshard/olymp/server/ClientFactory.java
Normal file
86
src/org/blueshard/olymp/server/ClientFactory.java
Normal file
@ -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<Integer, Client> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
86
src/org/blueshard/olymp/server/ClientReceiver.java
Normal file
86
src/org/blueshard/olymp/server/ClientReceiver.java
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
350
src/org/blueshard/olymp/server/ClientSender.java
Normal file
350
src/org/blueshard/olymp/server/ClientSender.java
Normal file
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
345
src/org/blueshard/olymp/server/MainServer.java
Normal file
345
src/org/blueshard/olymp/server/MainServer.java
Normal file
@ -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<String> 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");
|
||||
}
|
||||
|
||||
}
|
39
src/org/blueshard/olymp/sql/SQL.java
Normal file
39
src/org/blueshard/olymp/sql/SQL.java
Normal file
@ -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");
|
||||
}
|
||||
|
||||
}
|
22
src/org/blueshard/olymp/sql/SQLPosition.java
Normal file
22
src/org/blueshard/olymp/sql/SQLPosition.java
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
146
src/org/blueshard/olymp/user/User.java
Normal file
146
src/org/blueshard/olymp/user/User.java
Normal file
@ -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<File> customUserFiles = FileUtils.getAllFilesInDirectory(new ServerFiles.user_files(UUID).user_files_dir);
|
||||
ListIterator<File> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
112
src/org/blueshard/olymp/user/UserInfos.java
Normal file
112
src/org/blueshard/olymp/user/UserInfos.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
1
src/org/blueshard/olymp/userfiles/empty
Normal file
1
src/org/blueshard/olymp/userfiles/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
76
src/org/blueshard/olymp/utils/ConsoleColors.java
Normal file
76
src/org/blueshard/olymp/utils/ConsoleColors.java
Normal file
@ -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
|
||||
}
|
38
src/org/blueshard/olymp/utils/ExceptionUtils.java
Normal file
38
src/org/blueshard/olymp/utils/ExceptionUtils.java
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
70
src/org/blueshard/olymp/utils/FileUtils.java
Normal file
70
src/org/blueshard/olymp/utils/FileUtils.java
Normal file
@ -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<File> getAllFilesInDirectory(String path) throws IOException {
|
||||
ArrayList<File> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
196
src/org/blueshard/olymp/utils/SizeUnit.java
Normal file
196
src/org/blueshard/olymp/utils/SizeUnit.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
src/org/blueshard/olymp/utils/StringUtils.java
Normal file
17
src/org/blueshard/olymp/utils/StringUtils.java
Normal file
@ -0,0 +1,17 @@
|
||||
package org.blueshard.olymp.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
public static String format(String string, Map<String, String> formatMap){
|
||||
|
||||
for(Map.Entry<String, String> entry: formatMap.entrySet()) {
|
||||
string = string.replace("{" + entry.getKey() + "}", entry.getValue());
|
||||
}
|
||||
|
||||
return string;
|
||||
|
||||
}
|
||||
|
||||
}
|
40
src/org/blueshard/olymp/version/ServerVersion.java
Normal file
40
src/org/blueshard/olymp/version/ServerVersion.java
Normal file
@ -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");
|
||||
}
|
||||
|
||||
}
|
133
src/org/blueshard/olymp/version/TheosUIVersion.java
Normal file
133
src/org/blueshard/olymp/version/TheosUIVersion.java
Normal file
@ -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<String, String> versions;
|
||||
Set<String> 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<String, String> reverseVersions = versions.descendingMap();
|
||||
|
||||
for (Map.Entry<String, String> 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<String, String> reverseVersions = versions.descendingMap();
|
||||
|
||||
for (Map.Entry<String, String> 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<String> 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;
|
||||
}
|
||||
|
||||
}
|
21
src/org/blueshard/olymp/version/Version.java
Normal file
21
src/org/blueshard/olymp/version/Version.java
Normal file
@ -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);
|
||||
}
|
16
src/org/blueshard/sekaijuclt/Main.java
Normal file
16
src/org/blueshard/sekaijuclt/Main.java
Normal file
@ -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");
|
||||
}
|
||||
|
||||
}
|
1
src/org/blueshard/sekaijuclt/cli/empty
Normal file
1
src/org/blueshard/sekaijuclt/cli/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
52
src/org/blueshard/sekaijuclt/client/Action.java
Normal file
52
src/org/blueshard/sekaijuclt/client/Action.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
110
src/org/blueshard/sekaijuclt/client/MainClient.java
Normal file
110
src/org/blueshard/sekaijuclt/client/MainClient.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
143
src/org/blueshard/sekaijuclt/client/ServerSendRecv.java
Normal file
143
src/org/blueshard/sekaijuclt/client/ServerSendRecv.java
Normal file
@ -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<String> currentDirectory = new ArrayList<>();
|
||||
private HashMap<String, Object> 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<String> 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<String, Object> files = (HashMap<String, Object>) listFiles().get(directory);
|
||||
if (files.isEmpty()) {
|
||||
addToFiles(action.getFilesData(getCurrentDirectory() + "/"));
|
||||
}
|
||||
currentDirectory.add(directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<String> listFilesAsList() {
|
||||
HashMap<String, Object> currentFiles = new HashMap<>();
|
||||
for (String s: currentDirectory) {
|
||||
currentFiles = (HashMap<String, Object>) files.get(s);
|
||||
}
|
||||
return toSortedArrayList((String[]) currentFiles.keySet().toArray());
|
||||
}
|
||||
|
||||
public HashMap<String, Object> listFiles() {
|
||||
HashMap<String, Object> currentFiles = new HashMap<>();
|
||||
for (String s: currentDirectory) {
|
||||
currentFiles = (HashMap<String, Object>) 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
145
src/org/blueshard/sekaijuclt/client/ServerSender.java
Normal file
145
src/org/blueshard/sekaijuclt/client/ServerSender.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
161
src/org/blueshard/sekaijuclt/data/Data.java
Normal file
161
src/org/blueshard/sekaijuclt/data/Data.java
Normal file
@ -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<String, String> 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<String, String> 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<String, String> 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<String, String> allData) {
|
||||
this.data.putAll(allData);
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public Data getData() {
|
||||
return new Data(getDataAsString());
|
||||
}
|
||||
|
||||
public Map<String, String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
50
src/org/blueshard/sekaijuclt/data/DataCodes.java
Normal file
50
src/org/blueshard/sekaijuclt/data/DataCodes.java
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
48
src/org/blueshard/sekaijuclt/e2ee/AESCipher.java
Normal file
48
src/org/blueshard/sekaijuclt/e2ee/AESCipher.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
36
src/org/blueshard/sekaijuclt/e2ee/E2EEConverter.java
Normal file
36
src/org/blueshard/sekaijuclt/e2ee/E2EEConverter.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
57
src/org/blueshard/sekaijuclt/e2ee/RSACipher.java
Normal file
57
src/org/blueshard/sekaijuclt/e2ee/RSACipher.java
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
src/org/blueshard/sekaijuclt/exception/ErrorCodes.java
Normal file
37
src/org/blueshard/sekaijuclt/exception/ErrorCodes.java
Normal file
@ -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<Integer> 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));
|
||||
|
||||
}
|
17
src/org/blueshard/sekaijuclt/exception/FatalIOException.java
Normal file
17
src/org/blueshard/sekaijuclt/exception/FatalIOException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.sekaijuclt.exception;
|
||||
|
||||
public class IllegalPasswordException extends Exception {
|
||||
|
||||
public IllegalPasswordException(String errorMessage){
|
||||
super(errorMessage);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.sekaijuclt.exception;
|
||||
|
||||
public class UserAlreadyExistException extends UserException {
|
||||
|
||||
public UserAlreadyExistException(String username, String message) {
|
||||
super(username, message);
|
||||
}
|
||||
|
||||
}
|
13
src/org/blueshard/sekaijuclt/exception/UserException.java
Normal file
13
src/org/blueshard/sekaijuclt/exception/UserException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.blueshard.sekaijuclt.exception;
|
||||
|
||||
public class UserNotExistException extends UserException {
|
||||
|
||||
public UserNotExistException(String username, String message){
|
||||
super(username, message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package org.blueshard.sekaijuclt.exception;
|
||||
|
||||
public class UserNotLoggedInException extends UserException {
|
||||
|
||||
public UserNotLoggedInException(String username, String message) {
|
||||
super(username, message);
|
||||
}
|
||||
}
|
1
src/org/blueshard/sekaijuclt/logging/empty
Normal file
1
src/org/blueshard/sekaijuclt/logging/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
65
src/org/blueshard/sekaijuclt/security/Password.java
Normal file
65
src/org/blueshard/sekaijuclt/security/Password.java
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
58
src/org/blueshard/sekaijuclt/user/UserParams.java
Normal file
58
src/org/blueshard/sekaijuclt/user/UserParams.java
Normal file
@ -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";
|
||||
|
||||
}
|
||||
|
||||
}
|
76
src/org/blueshard/sekaijuclt/utils/ConsoleColors.java
Normal file
76
src/org/blueshard/sekaijuclt/utils/ConsoleColors.java
Normal file
@ -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
|
||||
}
|
71
src/org/blueshard/sekaijuclt/utils/FileUtils.java
Normal file
71
src/org/blueshard/sekaijuclt/utils/FileUtils.java
Normal file
@ -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<File> getAllFilesInDirectory(String path) throws IOException {
|
||||
ArrayList<File> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
140
src/org/blueshard/sekaijuclt/utils/SizeUnit.java
Normal file
140
src/org/blueshard/sekaijuclt/utils/SizeUnit.java
Normal file
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
17
src/org/blueshard/sekaijuclt/utils/StringUtils.java
Normal file
17
src/org/blueshard/sekaijuclt/utils/StringUtils.java
Normal file
@ -0,0 +1,17 @@
|
||||
package org.blueshard.sekaijuclt.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
public static String format(String string, Map<String, String> formatMap){
|
||||
|
||||
for(Map.Entry<String, String> entry: formatMap.entrySet()) {
|
||||
string = string.replace("{" + entry.getKey() + "}", entry.getValue());
|
||||
}
|
||||
|
||||
return string;
|
||||
|
||||
}
|
||||
|
||||
}
|
7
srv/etc/versions.conf
Normal file
7
srv/etc/versions.conf
Normal file
@ -0,0 +1,7 @@
|
||||
[TheosUI]
|
||||
|
||||
0.1.0 = required:
|
||||
|
||||
[olymp]
|
||||
|
||||
0.1.0 =
|
1
srv/file_rooms/private_file_rooms/empty
Normal file
1
srv/file_rooms/private_file_rooms/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
1
srv/file_rooms/public_file_rooms/empty
Normal file
1
srv/file_rooms/public_file_rooms/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
1
srv/hsqldb/empty
Normal file
1
srv/hsqldb/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
1
srv/logs/main.log
Normal file
1
srv/logs/main.log
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
1
srv/public_files/empty
Normal file
1
srv/public_files/empty
Normal file
@ -0,0 +1 @@
|
||||
#empty
|
6
srv/ssl/java ssl.txt
Normal file
6
srv/ssl/java ssl.txt
Normal file
@ -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
|
BIN
srv/ssl/sslKey.cert
Normal file
BIN
srv/ssl/sslKey.cert
Normal file
Binary file not shown.
BIN
srv/ssl/sslKeyStore.jks
Normal file
BIN
srv/ssl/sslKeyStore.jks
Normal file
Binary file not shown.
BIN
srv/ssl/sslTrustStore.jks
Normal file
BIN
srv/ssl/sslTrustStore.jks
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
#empty
|
3
start.sh
Normal file
3
start.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
java -Dfile.encoding=UTF-8 -classpath "out/production/olymp:lib/*:lib/batik/*:lib/hsqldb/*" org.blueshard.olymp.Main
|
BIN
theosui/lib/TFX.jar
Normal file
BIN
theosui/lib/TFX.jar
Normal file
Binary file not shown.
BIN
theosui/lib/TheosUIWindow.jar
Normal file
BIN
theosui/lib/TheosUIWindow.jar
Normal file
Binary file not shown.
BIN
theosui/lib/batik/batik-anim-1.8.jar
Normal file
BIN
theosui/lib/batik/batik-anim-1.8.jar
Normal file
Binary file not shown.
BIN
theosui/lib/batik/batik-awt-util-1.8.jar
Normal file
BIN
theosui/lib/batik/batik-awt-util-1.8.jar
Normal file
Binary file not shown.
BIN
theosui/lib/batik/batik-bridge-1.8.jar
Normal file
BIN
theosui/lib/batik/batik-bridge-1.8.jar
Normal file
Binary file not shown.
BIN
theosui/lib/batik/batik-codec-1.8.jar
Normal file
BIN
theosui/lib/batik/batik-codec-1.8.jar
Normal file
Binary file not shown.
BIN
theosui/lib/batik/batik-css-1.8.jar
Normal file
BIN
theosui/lib/batik/batik-css-1.8.jar
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user