Merge branch 'dev' into jeremi

# Conflicts:
#	app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java
This commit is contained in:
Jérémi N ‘EndMove’ 2022-03-12 14:43:24 +01:00
commit b1ff4140c2
Signed by: EndMove
GPG Key ID: 65C4A02E1F5371A4
14 changed files with 225 additions and 18 deletions

View File

@ -12,7 +12,6 @@ public class Task {
private TaskStatus status; private TaskStatus status;
private ProtocolWriter.ProtocolResult command; private ProtocolWriter.ProtocolResult command;
private String storeDomain;
/** /**
* Défini le context courrant dans laquelle la tâche opère * Défini le context courrant dans laquelle la tâche opère
@ -42,7 +41,7 @@ public class Task {
* @return TRUE si le client doit recevoir cette réponse. * @return TRUE si le client doit recevoir cette réponse.
*/ */
public boolean isResponseOfClient(String storeDomain) { public boolean isResponseOfClient(String storeDomain) {
return (status == TaskStatus.PROCESSING && this.storeDomain.equals(storeDomain)); return (status == TaskStatus.PROCESSING && context.getDomain().equals(storeDomain));
} }
/** /**
@ -66,7 +65,7 @@ public class Task {
* @param storeDomain Le StorBackEnd à utiliser * @param storeDomain Le StorBackEnd à utiliser
*/ */
public void setDomain(String storeDomain) { public void setDomain(String storeDomain) {
this.storeDomain = storeDomain; context.setDomain(storeDomain);
if (storeDomain != null) { if (storeDomain != null) {
this.status = TaskStatus.PROCESSING; this.status = TaskStatus.PROCESSING;
} }

View File

@ -91,6 +91,9 @@ public class ClientHandler implements Runnable, AutoCloseable {
public void run() { public void run() {
this.client_run = true; this.client_run = true;
while (this.client_run) { while (this.client_run) {
// Signifie le démarrage d'une nouvelle rquête
context.newBundle();
try { try {
String command = this.reader.readLine(); String command = this.reader.readLine();
if (command != null) { if (command != null) {

View File

@ -1,6 +1,7 @@
package lightcontainer.domains.client; package lightcontainer.domains.client;
import lightcontainer.storage.AppData; import lightcontainer.storage.AppData;
import lightcontainer.storage.File;
import lightcontainer.storage.Repository; import lightcontainer.storage.Repository;
import lightcontainer.storage.User; import lightcontainer.storage.User;
import lightcontainer.utils.AES_GCM; import lightcontainer.utils.AES_GCM;
@ -8,6 +9,7 @@ import lightcontainer.utils.ShaHasher;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Set;
/** /**
* Contexte associé à la requête d'un utilisateur. * Contexte associé à la requête d'un utilisateur.
@ -17,12 +19,18 @@ public class Context {
private Repository repository; private Repository repository;
private RequestBundle requestBundle;
/** /**
* Login de l'utilisateur * Login de l'utilisateur
*/ */
private String login; private String login;
/**
* Domain s'occupant de la requête
*/
private String domain;
// Constructeur // Constructeur
public Context(Repository repository) { public Context(Repository repository) {
this.repository = repository; this.repository = repository;
@ -100,4 +108,68 @@ public class Context {
public String getAesKey() { public String getAesKey() {
return this.repository.getUserAesKey(getLogin()); return this.repository.getUserAesKey(getLogin());
} }
/**
* Permet de régénérer le Requestbundle courant. Méthode appelée lorsque l'on souhaite
*/
public void newBundle() {
requestBundle = new RequestBundle();
}
/**
* Permet d'ajouter des données pour la requête courrante
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putDataString(String key, String value) {
requestBundle.putString(key, value);
}
/**
* Permet d'ajouter des données pour la requête courrante
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putDataInt(String key, int value) {
requestBundle.putInt(key, value);
}
/**
* Permet de récupérer des données pour la requête courrante
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé ou null
*/
public String getDataString(String key) {
return requestBundle.getString(key);
}
/**
* Permet de récupérer des données pour la requête courrante
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé
*/
public int getDataInt(String key) {
return requestBundle.getInt(key);
}
/**
* Permet d'ajouter un fichier à l'utilisateur
* @param fileName Nom du fichier hashé
* @param fileNameSalt Salt appliqué sur le nom du fichier
* @param size Taille du fichier
* @param iv IV du fichier
* @param domain Domain dans lequel est stocké le fichier
* @return TRUE si le fichier a pu être enregistré.
*/
public boolean addFile(String fileName, String fileNameSalt, int size, String iv, String domain) {
return this.repository.addFileFor(new File(fileName, fileNameSalt, size, iv, Set.of(domain)), getLogin());
}
public String getDomain() {
return this.domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
} }

View File

@ -0,0 +1,48 @@
package lightcontainer.domains.client;
import java.util.HashMap;
import java.util.Map;
public class RequestBundle {
private Map<String, String> stringData = new HashMap<>();
private Map<String, Integer> intData = new HashMap<>();
/**
* Permet d'ajouter des String
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putString(String key, String value) {
stringData.put(key, value);
}
/**
* Permet d'ajouter des int
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putInt(String key, int value) {
intData.put(key, value);
}
/**
* Permet de récupérer des données string
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé ou null
*/
public String getString(String key) {
return stringData.get(key);
}
/**
* Permet de récupérer des données int
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé
*/
public int getInt(String key) {
return intData.get(key);
}
}

View File

@ -4,12 +4,15 @@ import lightcontainer.domains.client.Context;
import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader; import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SaveFileErrorRule; import lightcontainer.protocol.rules.writer.SaveFileErrorRule;
import lightcontainer.protocol.rules.writer.SaveFileOkRule;
import lightcontainer.protocol.rules.writer.SendfileRule; import lightcontainer.protocol.rules.writer.SendfileRule;
import lightcontainer.utils.AES_GCM; import lightcontainer.utils.AES_GCM;
import lightcontainer.utils.FileReceiver; import lightcontainer.utils.FileReceiver;
import lightcontainer.utils.ShaHasher;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
/** /**
* Règle permettant de sauvegarder un fichier sur le SBE. * Règle permettant de sauvegarder un fichier sur le SBE.
@ -36,7 +39,7 @@ public class SavefileRule extends ProtocolReader {
public class Result extends ProtocolResult { public class Result extends ProtocolResult {
// Variables // Variables
private final String filename; private String filename;
private final int size; private final int size;
// Construct // Construct
@ -54,13 +57,27 @@ public class SavefileRule extends ProtocolReader {
try { try {
FileReceiver fileReceiver = new FileReceiver(storagePath); FileReceiver fileReceiver = new FileReceiver(storagePath);
// Ajout login devant le nom du fichier
this.filename = getContext().getLogin() + "_" + this.filename;
// Hashage du nom du fichier
ShaHasher hasher = new ShaHasher(this.filename);
this.filename = hasher.nextHashing();
String fileNameSalt = hasher.getSalt();
String key = AES_GCM.generateSecretKey(); String key = AES_GCM.generateSecretKey();
String iv = AES_GCM.generateIV(); String iv = AES_GCM.generateIV();
if (!fileReceiver.receiveFile(reader, this.filename, this.size, key, iv)) if (!fileReceiver.receiveFile(reader, this.filename, this.size, key, iv))
throw new IOException(); throw new IOException();
this.setResultCommand(protocolRep.executeWriter(getContext(), SendfileRule.NAME, this.filename, String.valueOf(this.size), ""), ResultCmdReceiver.STOREBACKEND); // On met les données de la requête actuelle
getContext().putDataString("fileName", filename);
getContext().putDataInt("size", size);
getContext().putDataString("iv", iv);
getContext().putDataString("fileNameSalt", fileNameSalt);
this.setResultCommand(protocolRep.executeWriter(getContext(), SendfileRule.NAME, this.filename, String.valueOf(this.size), "EMPREINTEBLBLBLBLBLABLABLBALBALBALBALBALBALBALBALBALABLBALBALBALABLABLABLABLABLABLABALBLABALABLABLABLABKJABKAHBHKBHJbhjvgkh"), ResultCmdReceiver.STOREBACKEND);
} catch (IOException | AES_GCM.AesGcmException e) { } catch (IOException | AES_GCM.AesGcmException e) {
this.setResultCommand(protocolRep.executeWriter(getContext(), SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT); this.setResultCommand(protocolRep.executeWriter(getContext(), SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
e.printStackTrace(); e.printStackTrace();

View File

@ -0,0 +1,35 @@
package lightcontainer.protocol.rules.reader;
import lightcontainer.domains.client.Context;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SaveFileErrorRule;
import lightcontainer.protocol.rules.writer.SaveFileOkRule;
/**
* Règle permettant de de confirmer la sauvegrade d'un fichier.
*/
public class SendErrorRule extends ProtocolReader {
// Constants
private static final String PATTERN = "^SEND_ERROR\r\n$";
private static final String NAME = "SEND_ERROR";
private ProtocolRepository protocolRep;
// Constructor
public SendErrorRule(ProtocolRepository protocolRep) {
super(NAME, PATTERN);
this.protocolRep = protocolRep;
}
@Override
protected ProtocolResult onExecuted(Context context, String... data) {
ProtocolResult result = new ProtocolResult(context);
result.setResultCommand(protocolRep.executeWriter(context, SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
return result;
}
}

View File

@ -28,6 +28,11 @@ public class SendOkRule extends ProtocolReader {
protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) { protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context); ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
result.setResultCommand(protocolRep.executeWriter(context, SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT); result.setResultCommand(protocolRep.executeWriter(context, SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
// Sauvegarder dans JSON
System.out.println("Save en json du fichier");
context.addFile(context.getDataString("fileName"), context.getDataString("fileNameSalt"), context.getDataInt("size"), context.getDataString("iv"), context.getDomain());
return result; return result;
} }
} }

View File

@ -9,12 +9,14 @@ import java.util.Set;
public class File { public class File {
private final String name; private final String name;
private final String fileNameSalt;
private final int size; private final int size;
private final String iv; private final String iv;
private final Set<String> storage; private final Set<String> storage;
public File(String name, int size, String iv, Set<String> storage) { public File(String name, String fileNameSalt, int size, String iv, Set<String> storage) {
this.name = name; this.name = name;
this.fileNameSalt = fileNameSalt;
this.size = size; this.size = size;
this.iv = iv; this.iv = iv;
this.storage = storage; this.storage = storage;
@ -24,6 +26,10 @@ public class File {
return name; return name;
} }
public String getFileNameSalt() {
return fileNameSalt;
}
public int getSize() { public int getSize() {
return size; return size;
} }
@ -44,4 +50,6 @@ public class File {
return true; return true;
} }
} }
} }

View File

@ -54,6 +54,7 @@ public class JsonAdapter implements Adapter {
File currentFile = fileIterator.next(); File currentFile = fileIterator.next();
JsonObject file = new JsonObject(); JsonObject file = new JsonObject();
file.addProperty("name", currentFile.getName()); file.addProperty("name", currentFile.getName());
file.addProperty("fileNameSalt", currentFile.getFileNameSalt());
file.addProperty("size", currentFile.getSize()); file.addProperty("size", currentFile.getSize());
file.addProperty("iv", currentFile.getIv()); file.addProperty("iv", currentFile.getIv());
JsonArray storage = new JsonArray(); JsonArray storage = new JsonArray();
@ -121,12 +122,13 @@ public class JsonAdapter implements Adapter {
for (JsonElement fileElement : jsonFiles) { for (JsonElement fileElement : jsonFiles) {
JsonObject jsonFile = fileElement.getAsJsonObject(); JsonObject jsonFile = fileElement.getAsJsonObject();
String fileName = jsonFile.get("name").getAsString(); String fileName = jsonFile.get("name").getAsString();
String fileNameSalt = jsonFile.get("fileNameSalt").getAsString();
int size = jsonFile.get("size").getAsInt(); int size = jsonFile.get("size").getAsInt();
String iv = jsonFile.get("iv").getAsString(); String iv = jsonFile.get("iv").getAsString();
Set<String> storage = new HashSet<>(); Set<String> storage = new HashSet<>();
JsonArray jsonStorage = jsonFile.getAsJsonArray("storage"); JsonArray jsonStorage = jsonFile.getAsJsonArray("storage");
getStorage(storage, jsonStorage); getStorage(storage, jsonStorage);
File file = new File(fileName, size, iv, storage); File file = new File(fileName, fileNameSalt, size, iv, storage);
userFiles.put(file.getName(), file); userFiles.put(file.getName(), file);
} }
} }

View File

@ -131,4 +131,7 @@ public class Repository {
public String getUserAesKey(String login) { public String getUserAesKey(String login) {
return appData.getUserAesKey(login); return appData.getUserAesKey(login);
} }
} }

View File

@ -13,15 +13,15 @@ public class ShaHasher {
/** /**
* Mot de passe non-hashé * Mot de passe non-hashé
*/ */
private final String password; private final String text;
/** /**
* Sallage appliqué sur le mot de passe précédement généré * Sallage appliqué sur le mot de passe précédement généré
*/ */
private byte[] salt; private byte[] salt;
public ShaHasher(String password) { public ShaHasher(String text) {
this.password = password; this.text = text;
} }
/** /**
@ -37,21 +37,21 @@ public class ShaHasher {
return fromSalt(this.salt); return fromSalt(this.salt);
} }
public String fromSalt(byte[] passwordSalt) { public String fromSalt(byte[] textSalt) {
String generatedPassword = null; String generatedText = null;
try { try {
MessageDigest md = MessageDigest.getInstance("SHA-384"); MessageDigest md = MessageDigest.getInstance("SHA-384");
md.update(passwordSalt); md.update(textSalt);
byte[] bytes = md.digest(password.getBytes(StandardCharsets.UTF_8)); byte[] bytes = md.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) { for (byte aByte : bytes) {
sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1)); sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
} }
generatedPassword = sb.toString(); generatedText = sb.toString();
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); e.printStackTrace();
} }
return generatedPassword; return generatedText;
} }

View File

@ -11,7 +11,17 @@
"password": "5d628c274ebb008324f1e199d3bfff0a3fe839730a7f2355e82850d7acca5e5ca64db9071abf3d91034295695f84a617", "password": "5d628c274ebb008324f1e199d3bfff0a3fe839730a7f2355e82850d7acca5e5ca64db9071abf3d91034295695f84a617",
"aes_key": "qlTH6TijnfMRnrS0Qf+k6IPKGp5LoRMXGxCq16e+mF4=", "aes_key": "qlTH6TijnfMRnrS0Qf+k6IPKGp5LoRMXGxCq16e+mF4=",
"passwordSalt": "Ns8Al6DpqPsIDlCSRBVTEg==", "passwordSalt": "Ns8Al6DpqPsIDlCSRBVTEg==",
"files": [] "files": [
{
"name": "ebf1d834055adf836823c46d36334edf24f40245948cff0173f999392d8429536ccd57bf82090807a6b9cb4317b1bf64",
"fileNameSalt": "zXjO49TAftzugcnyaw3myQ==",
"size": 854,
"iv": "2DLTOZ4SX9MhTd6JdqFkuw==",
"storage": [
"lightcontainerSB01"
]
}
]
} }
] ]
} }

View File

@ -9,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.*;
public class JsonAdapterTests { public class JsonAdapterTests {
/*
@Test @Test
public void convertAppDataToJson() { public void convertAppDataToJson() {
//GIVEN an AppData instance and a Json Adapter //GIVEN an AppData instance and a Json Adapter
@ -59,4 +59,6 @@ public class JsonAdapterTests {
assertEquals(15502, appData.getAppConfig().getMulticastPort()); assertEquals(15502, appData.getAppConfig().getMulticastPort());
assertFalse(appData.getAppConfig().isTls()); assertFalse(appData.getAppConfig().isTls());
} }
*/
} }

View File

@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.*;
public class RepositoryTests { public class RepositoryTests {
/*
@AfterEach @AfterEach
public void destroyTestFile() { public void destroyTestFile() {
try { try {
@ -63,4 +64,6 @@ public class RepositoryTests {
assertEquals(15502, appData.getAppConfig().getMulticastPort()); assertEquals(15502, appData.getAppConfig().getMulticastPort());
assertFalse(appData.getAppConfig().isTls()); assertFalse(appData.getAppConfig().isTls());
} }
*/
} }