diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index fdc392f..b3e9cbd 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -16,5 +16,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e69de29..d207fc9 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,15 @@
+# FileFrontEnd
+
+## Configuration
+
+### Technologies utilisées
+
+* Java 11 (ressources informatiques)
+* Gradle 7.1
+
+### Projet
+
+* src > main > resources > appdata.json -> Fichier de configuration à modifier
+* storagePath : indiquer le dossier où les fichiers temporaires du FFE seront stockés
+* network_interface : indiquer l'interface réseau à utiliser. Si elle n'est pas bonne, le programme demande laquelle utiliser au démarrage
+
diff --git a/app/build.gradle b/app/build.gradle
index 5345a80..0505436 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -24,6 +24,8 @@ dependencies {
implementation 'com.google.guava:guava:30.1-jre'
// Use gson to serialize/deserialize json files
implementation 'com.google.code.gson:gson:2.9.0'
+ // https://mvnrepository.com/artifact/org.mindrot/jbcrypt
+ implementation group: 'org.mindrot', name: 'jbcrypt', version: '0.4'
}
application {
@@ -35,3 +37,8 @@ tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
+
+
+run {
+ standardInput = System.in
+}
\ No newline at end of file
diff --git a/app/src/main/java/lightcontainer/App.java b/app/src/main/java/lightcontainer/App.java
index 9ac6afc..8f9fd69 100644
--- a/app/src/main/java/lightcontainer/App.java
+++ b/app/src/main/java/lightcontainer/App.java
@@ -3,6 +3,7 @@
*/
package lightcontainer;
+import lightcontainer.domains.FFETimer;
import lightcontainer.domains.server.MulticastServerListener;
import lightcontainer.domains.server.UnicastServerListener;
import lightcontainer.interfaces.ProtocolRepository;
@@ -16,14 +17,11 @@ import lightcontainer.storage.AppData;
import lightcontainer.storage.JsonAdapter;
import lightcontainer.storage.Repository;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Timer;
public class App {
-
public static void main(String[] args) {
setupVM();
Repository repositoryStorage = prepareStorage();
@@ -31,7 +29,28 @@ public class App {
// Create all repository
ClientHandlerRepository clientRep = new ClientHandlerRepository();
StoreProcessorRepository storeRep = new StoreProcessorRepository();
+
+ // Initialisation des protocoles
ProtocolRepository protocolRep = new ProtocolRepositoryImpl();
+ initProtocols(repositoryStorage, protocolRep);
+
+ // Initialisation du dispatcher et des servers
+ FileFrontEnd ffe = new FileFrontEnd(clientRep, storeRep, protocolRep);
+ new UnicastServerListener(ffe, clientRep, protocolRep, repositoryStorage, repositoryStorage.getUnicastPort());
+ new MulticastServerListener(ffe, storeRep, protocolRep, repositoryStorage.getMulticastIp(), repositoryStorage.getMulticastPort(), repositoryStorage.getNetworkInterface());
+
+ // S'occupe de distribué les timeout pour les SBE plus connecté et donc de Timeout les clients
+ Timer ffeTimer = new Timer();
+ ffeTimer.schedule(new FFETimer(storeRep), 50000, 50000);
+
+ }
+
+ private static void initProtocols(Repository repositoryStorage, ProtocolRepository protocolRep) {
+ initReadersProtocols(repositoryStorage, protocolRep);
+ initWritersProtocols(repositoryStorage, protocolRep);
+ }
+
+ private static void initReadersProtocols(Repository repositoryStorage, ProtocolRepository protocolRep) {
protocolRep.addReader(new HelloRule());
protocolRep.addReader(new SigninRule(protocolRep));
protocolRep.addReader(new SignupRule(protocolRep));
@@ -39,24 +58,28 @@ public class App {
protocolRep.addReader(new FilelistRule(protocolRep));
protocolRep.addReader(new SavefileRule(protocolRep, repositoryStorage.getStoragePath()));
protocolRep.addReader(new SendOkRule(protocolRep));
+ protocolRep.addReader(new SendErrorRule(protocolRep));
+ protocolRep.addReader(new GetFileRule(protocolRep));
+ protocolRep.addReader(new EraseErrorRule(protocolRep));
+ protocolRep.addReader(new EraseOkRule(protocolRep));
+ protocolRep.addReader(new RemoveFileRule(protocolRep));
+ protocolRep.addReader(new RetrieveErrorRule(protocolRep));
+ protocolRep.addReader(new RetrieveOkRule(protocolRep, repositoryStorage.getStoragePath()));
+ }
+ private static void initWritersProtocols(Repository repositoryStorage, ProtocolRepository protocolRep) {
protocolRep.addWriter(new SignOkRule());
protocolRep.addWriter(new SignErrorRule());
protocolRep.addWriter(new FilesRule());
- protocolRep.addWriter(new SaveFileOkRule());
- protocolRep.addWriter(new SaveFileErrorRule());
+ protocolRep.addWriter(new SaveFileOkRule(repositoryStorage.getStoragePath()));
+ protocolRep.addWriter(new SaveFileErrorRule(repositoryStorage.getStoragePath()));
protocolRep.addWriter(new SendfileRule(repositoryStorage.getStoragePath()));
-
- FileFrontEnd ffe = new FileFrontEnd(clientRep, storeRep, protocolRep);
- new UnicastServerListener(ffe, clientRep, protocolRep, repositoryStorage, repositoryStorage.getUnicastPort());
- new MulticastServerListener(ffe, storeRep, protocolRep, repositoryStorage.getMulticastIp(), repositoryStorage.getMulticastPort());
-
- // close repo et client et server.
-
- // Thread.sleep(60000);
-
- // clientRep.close();
- // storeRep.close();
+ protocolRep.addWriter(new GetFileErrorRule(repositoryStorage.getStoragePath()));
+ protocolRep.addWriter(new EraseFileRule());
+ protocolRep.addWriter(new RemoveFileErrorRule());
+ protocolRep.addWriter(new RemoveFileOkRule());
+ protocolRep.addWriter(new GetFileOkRule(repositoryStorage.getStoragePath()));
+ protocolRep.addWriter(new RetrieveFileRule());
}
private static Repository prepareStorage() {
@@ -71,9 +94,9 @@ public class App {
}
private static void setupVM() {
- System.setProperty("javax.net.ssl.keyStore","../ffe.labo.swilabus.com.p12");
- System.setProperty("javax.net.ssl.keyStorePassword","labo2022");
- System.setProperty("https.protocols","TLSv1.3");
+ System.setProperty("javax.net.ssl.keyStore", "../ffe.labo.swilabus.com.p12");
+ System.setProperty("javax.net.ssl.keyStorePassword", "labo2022");
+ System.setProperty("https.protocols", "TLSv1.3");
}
}
diff --git a/app/src/main/java/lightcontainer/domains/FFETimer.java b/app/src/main/java/lightcontainer/domains/FFETimer.java
new file mode 100644
index 0000000..3124343
--- /dev/null
+++ b/app/src/main/java/lightcontainer/domains/FFETimer.java
@@ -0,0 +1,31 @@
+package lightcontainer.domains;
+
+import lightcontainer.interfaces.MulticastSPR;
+
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.TimerTask;
+
+/**
+ * Class s'occupant de gérer les timeout des différents SBE
+ */
+public class FFETimer extends TimerTask {
+
+ private final MulticastSPR processorRepository;
+
+ public FFETimer(MulticastSPR processorRepository) {
+ this.processorRepository = processorRepository;
+ }
+
+ @Override
+ public void run() {
+ for (String domain : processorRepository.getDomains()) {
+ LocalDateTime lastAnnounce = processorRepository.getLastAnnounce(domain);
+ long secondBetween = Math.abs(ChronoUnit.SECONDS.between(lastAnnounce, LocalDateTime.now()));
+
+ if (secondBetween > 50) {
+ processorRepository.closeStore(domain);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/lightcontainer/domains/Task.java b/app/src/main/java/lightcontainer/domains/Task.java
index e5e70d3..7b61a94 100644
--- a/app/src/main/java/lightcontainer/domains/Task.java
+++ b/app/src/main/java/lightcontainer/domains/Task.java
@@ -10,33 +10,35 @@ import lightcontainer.protocol.ProtocolWriter;
public class Task {
// Variables
private TaskStatus status;
- private ProtocolWriter.ProtocolResult command;
+ private final ProtocolWriter.ProtocolResult command;
/**
- * Défini le context courrant dans laquelle la tâche opère
+ * Défini le context courant dans laquelle la tâche opère
*/
- private Context context;
+ private final Context context;
- public Task(Context context, TaskStatus status, ProtocolWriter.ProtocolResult command) {
+ public Task(Context context, TaskStatus status, ProtocolWriter.ProtocolResult command, String requestDomain) {
this.context = context;
this.status = status;
this.command = command;
+ context.setDomain(requestDomain); // Domaine requis
}
/**
* Permet de créer une instance de la class {@link Task}
+ *
* @param context Context à utiliser pour cette tâche
* @param command Commande à exécuter
* @return L'instance de la tâche créée
*/
- public static Task newInstance(Context context, ProtocolWriter.ProtocolResult command) {
- Task task = new Task(context, TaskStatus.PENDING, command);
- return task;
+ public static Task newInstance(Context context, ProtocolWriter.ProtocolResult command, String requestDomain) {
+ return new Task(context, TaskStatus.PENDING, command, requestDomain);
}
/**
* Permet de savoir si la réponse est destinée au client
+ *
* @param storeDomain Nom du store back end fournissant la réponse.
* @return TRUE si le client doit recevoir cette réponse.
*/
@@ -46,6 +48,7 @@ public class Task {
/**
* Permet de récupérer le login du client associé à la tâche
+ *
* @return Login du client
*/
public String getClient() {
@@ -54,6 +57,7 @@ public class Task {
/**
* Permet de récupérer la commande à executer
+ *
* @return Commande à exécuter
*/
public ProtocolWriter.ProtocolResult getCommand() {
@@ -62,6 +66,7 @@ public class Task {
/**
* Permet de définir le StorBackEnd à utiliser pour cette tâche
+ *
* @param storeDomain Le StorBackEnd à utiliser
*/
public void setDomain(String storeDomain) {
@@ -77,4 +82,12 @@ public class Task {
public Context getContext() {
return this.context;
}
+
+ /**
+ * Le domaine actuellement utilisé OU requis, null si aucune domaine requis/associé
+ * @return
+ */
+ public String getDomain() {
+ return context.getDomain();
+ }
}
diff --git a/app/src/main/java/lightcontainer/domains/client/ClientHandler.java b/app/src/main/java/lightcontainer/domains/client/ClientHandler.java
index 1c9922a..19e0cac 100644
--- a/app/src/main/java/lightcontainer/domains/client/ClientHandler.java
+++ b/app/src/main/java/lightcontainer/domains/client/ClientHandler.java
@@ -1,6 +1,5 @@
package lightcontainer.domains.client;
-import lightcontainer.domains.server.UnicastServerListener;
import lightcontainer.interfaces.ClientHandlerFFE;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.interfaces.UnicastCHR;
@@ -10,153 +9,107 @@ import lightcontainer.protocol.rules.reader.SigninRule;
import lightcontainer.protocol.rules.reader.SignoutRule;
import lightcontainer.protocol.rules.reader.SignupRule;
import lightcontainer.protocol.rules.writer.SignErrorRule;
-import lightcontainer.protocol.rules.writer.SignOkRule;
+import lightcontainer.utils.Log;
-import javax.crypto.BadPaddingException;
-import javax.net.ssl.SSLHandshakeException;
-import java.io.*;
+import java.io.IOException;
import java.net.Socket;
-import java.nio.charset.StandardCharsets;
/**
* ClientHandler
- *
+ *
* UNICAST CLIENT
* Class communicating with the client, and
* intercepting and sending files to the client.
*
- * @version 1.1
- * @since 1.0
- *
- * @see Runnable
- * @see AutoCloseable
- * @author Jérémi NIHART
+ * @author Jérémi NIHART
+ * @version 1.1
+ * @see Runnable
+ * @see AutoCloseable
+ * @since 1.0
*/
-public class ClientHandler implements Runnable, AutoCloseable {
+public class ClientHandler extends UnicastThread implements AutoCloseable {
// Variables
- private ClientHandlerFFE fileFrontEnd;
- private final Socket client;
- private ProtocolRepository protocolRep;
- private Context context;
- private boolean client_run;
- private UnicastCHR repository;
-
-
- private BufferedReader reader;
- private PrintWriter writer;
+ private final ClientHandlerFFE fileFrontEnd;
+ private final ProtocolRepository protocolRep;
+ private final UnicastCHR repository;
private ProtocolWriter.ProtocolResult response;
// Constructor
public ClientHandler(UnicastCHR repository, Socket client, ClientHandlerFFE ffe, ProtocolRepository protocolRep, Context context) {
+ super(client, context);
this.repository = repository;
this.fileFrontEnd = ffe;
- this.client = client;
this.protocolRep = protocolRep;
- this.context = context;
- this.client_run = false;
- initClient();
- }
-
- /**
- * Initialise the Client's Reader and Writer.
- *
- * @since 1.0
- *
- * @see BufferedReader
- * @see PrintWriter
- */
- private void initClient() {
- // Start the thread
- try {
- this.reader = new BufferedReader(new InputStreamReader(
- this.client.getInputStream(),
- StandardCharsets.UTF_8
- ));
- this.writer = new PrintWriter(new OutputStreamWriter(
- this.client.getOutputStream(),
- StandardCharsets.UTF_8
- ), true);
- } catch (IOException e) {
- e.printStackTrace();
- }
}
/**
* Thread Function
* Start the dialogue with the client.
*
- * @since 1.0
+ * @since 1.0
*/
@Override
public void run() {
- this.client_run = true;
- while (this.client_run) {
+ // Set process to true
+ this.setRunning(true);
+ // Process while
+ while (this.isRunning()) {
// Signifie le démarrage d'une nouvelle rquête
- context.newBundle();
-
+ getContext().newBundle();
try {
- String command = this.reader.readLine();
+ String command = this.readLine();
if (command != null) {
- System.out.println("Client: " + command);
+ Log.getInstance().infoln("Client: " + command);
} else {
- repository.disconnect(this);
+ this.repository.disconnect(this);
break;
}
- ProtocolReader.ProtocolResult ruleResult = protocolRep.executeReader(context, command + "\r\n");
+ ProtocolReader.ProtocolResult ruleResult = this.protocolRep.executeReader(getContext(), command + "\r\n");
if (ruleResult == null) {
- repository.disconnect(this);
+ this.repository.disconnect(this);
break;
}
if (checkAccess(ruleResult)) {
- ruleResult.read(this.client.getInputStream());
-
+ // Lecture du fichier client
+ ruleResult.read(this.getInputStream());
ProtocolWriter.ProtocolResult writerCommand = ruleResult.getResultCommand();
-
- if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND) {
- fileFrontEnd.newCommand(context, writerCommand); // Envoie dans la file de tâche FileFrontEnd en attente d'un traitement d'un StorBackEnd
-
+ // TODO : Vérifier que le StorBackEnd demandé (Pas toujours demandé) est disponible
+ if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND && !fileFrontEnd.canExecuteCommand(ruleResult.getRequestDomain())) {
+ this.print(ruleResult.onNotExecutable(getContext())); // Renvoie au client
+ } else if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND) {
+ this.fileFrontEnd.newCommand(getContext(), writerCommand, ruleResult.getRequestDomain()); // Envoie dans la file de tâche FileFrontEnd en attente d'un traitement d'un StorBackEnd
// Attend la fin de la réalisation de la tâche
waitTaskResponse();
-
- writer.write(response.getCommand()); // Renvoye au client
- writer.flush();
- response.write(this.client.getOutputStream()); // Ecrit au client si nécessaire
+ if (this.response != null) {
+ this.write(this.response.getCommand()); // Renvoie au client
+ this.response.write(this.getOutputStream()); // Ecrit au client si nécessaire
+ } else {
+ this.print(ruleResult.onNotExecutable(getContext())); // Renvoie au client
+ }
} else {
- writer.print(writerCommand.getCommand()); // Renvoye au client
- writer.flush();
+ this.print(writerCommand.getCommand()); // Renvoie au client
}
-
} else {
- System.out.println(4);
accessDenied();
}
- } catch (IOException ignore) {
- ignore.printStackTrace();
- repository.disconnect(this);
- break;
+ } catch (IOException e) {
+ this.close();
}
}
-
- try {
- this.reader.close();
- this.writer.close();
- this.client.close();
- System.out.printf("[CLIENT] %s s'est déconnecté\n", context.getLogin());
- } catch (IOException ignored) { }
}
/**
* Permet de vérifier si le client possède l'accès demandé
+ *
* @param ruleResult La règle
* @return TRUE si le client possède l'accès demandé
*/
private boolean checkAccess(ProtocolReader.ProtocolResult ruleResult) {
checkSignout(ruleResult);
- if (context.isConnected())
+ if (getContext().isConnected())
return true;
-
try {
ruleResult
.getClass()
@@ -166,9 +119,8 @@ public class ClientHandler implements Runnable, AutoCloseable {
try {
ruleResult.getClass().asSubclass(SigninRule.Result.class);
return true;
- } catch (ClassCastException e2) { }
+ } catch (ClassCastException ignored) { }
}
-
return false;
}
@@ -176,31 +128,20 @@ public class ClientHandler implements Runnable, AutoCloseable {
* Lorsque l'accès à été refusé.
*/
private void accessDenied() {
- ProtocolWriter.ProtocolResult signErrorResult = protocolRep.executeWriter(context, SignErrorRule.NAME);
- writer.write(signErrorResult.getCommand()); // Envoie SignError car echec de la connection
- writer.flush();
+ ProtocolWriter.ProtocolResult signErrorResult = this.protocolRep.executeWriter(getContext(), SignErrorRule.NAME);
+ this.write(signErrorResult.getCommand()); // Envoie SignError car echec de la connection
}
/**
* Vérifie s'il s'âgit d'une demande de déconnexion
+ *
* @param ruleResult
*/
private void checkSignout(ProtocolReader.ProtocolResult ruleResult) {
try {
ruleResult.getClass().asSubclass(SignoutRule.Result.class);
- repository.disconnect(this);
- } catch (ClassCastException e2) { }
- }
-
- /**
- * Vérifie s'il s'âgit d'une demande de déconnexion
- * @param ruleResult
- */
- private void checkSignError(ProtocolWriter.ProtocolResult ruleResult) {
- if (ruleResult.getCommand().startsWith(SignErrorRule.NAME)) {
- System.out.println("Pas pu connecter");
- repository.disconnect(this);
- }
+ this.repository.disconnect(this);
+ } catch (ClassCastException ignored) {}
}
/**
@@ -210,12 +151,15 @@ public class ClientHandler implements Runnable, AutoCloseable {
synchronized (this) {
try {
this.wait();
- } catch (InterruptedException e) { e.printStackTrace(); }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
}
}
/**
* Permet d'envoyer la réponse au client.
+ *
* @param response La réponse
*/
public void respond(ProtocolWriter.ProtocolResult response) {
@@ -229,16 +173,23 @@ public class ClientHandler implements Runnable, AutoCloseable {
* AutoClosable Function
* Close the Client thread and resources.
*
- * @since 1.0
+ * @since 1.0
*/
@Override
public void close() {
- System.out.println("Call close");
- this.client_run = false;
+ if (this.isRunning()) {
+ try {
+ super.close();
+ this.repository.disconnect(this);
+ Log.getInstance().infof("[CLIENT] %s s'est déconnecté\n", getContext().getLogin());
+ } catch (IOException e) {
+ Log.getInstance().infoln("[CH] Error while closing client.");
+ }
+ }
}
public String getLogin() {
- return this.context.getLogin();
+ return this.getContext().getLogin();
}
}
diff --git a/app/src/main/java/lightcontainer/domains/client/Context.java b/app/src/main/java/lightcontainer/domains/client/Context.java
index 31fee1a..99d5d9d 100644
--- a/app/src/main/java/lightcontainer/domains/client/Context.java
+++ b/app/src/main/java/lightcontainer/domains/client/Context.java
@@ -1,14 +1,13 @@
package lightcontainer.domains.client;
-import lightcontainer.storage.AppData;
+import lightcontainer.repository.ReadOnlyClientRepository;
import lightcontainer.storage.File;
+import lightcontainer.storage.ReadOnlyFile;
import lightcontainer.storage.Repository;
-import lightcontainer.storage.User;
import lightcontainer.utils.AES_GCM;
+import lightcontainer.utils.BCryptHasher;
import lightcontainer.utils.ShaHasher;
-import java.security.NoSuchAlgorithmException;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -17,10 +16,10 @@ import java.util.Set;
* Permet de récupérer les données à celui-ci et d'effectuer des actions sur le context courant.
*/
public class Context {
-
- private Repository repository;
-
+ // Variables
+ private final Repository repository;
private RequestBundle requestBundle;
+ private ReadOnlyClientRepository clientRepository;
/**
* Login de l'utilisateur
@@ -33,8 +32,9 @@ public class Context {
private String domain;
// Constructeur
- public Context(Repository repository) {
+ public Context(Repository repository, ReadOnlyClientRepository clientRepository) {
this.repository = repository;
+ this.clientRepository = clientRepository;
}
@@ -46,18 +46,18 @@ public class Context {
* @return TRUE si l'utilisateur a pu être créé
*/
public boolean createUser(String login, String password) {
+ if (clientRepository.hasClient(login)) { // Empêcher double connection
+ return false;
+ }
+
try {
String key = AES_GCM.generateSecretKey();
-
- ShaHasher hasher = new ShaHasher(password);
- password = hasher.nextHashing();
- String passwordSalt = hasher.getSalt();
-
- if (this.repository.addUser(login, password, key, passwordSalt)) {
+ String hashedPassword = BCryptHasher.hashPassword(password);
+ if (this.repository.addUser(login, hashedPassword, key)) {
this.login = login;
return true;
}
- } catch (AES_GCM.AesGcmException e) {
+ } catch (AES_GCM.AesGcmException ignored) {
}
return false;
}
@@ -73,21 +73,21 @@ public class Context {
/**
- * Permet de demander la connection de l'utilisateur
+ * Permet de demander la connexion de l'utilisateur
*
* @param login Login
* @param password Mot de passe
* @return TRUE si l'utilisateur a été authentifié
*/
public boolean signIn(String login, String password) {
- String passwordSalt = this.repository.getUserPasswordSalt(login);
- if (passwordSalt != null) {
- ShaHasher hasher = new ShaHasher(password);
+ if (login == null || password == null) {
+ return false;
+ }
- if (this.repository.verifyUser(login, hasher.fromSalt(hasher.saltToByte(passwordSalt)))) {
- this.login = login;
- return true;
- }
+ // Empêcher double connection
+ if (!clientRepository.hasClient(login) && this.repository.verifyUser(login, password)) {
+ this.login = login;
+ return true;
}
return false;
}
@@ -119,7 +119,7 @@ public class Context {
}
/**
- * Permet d'ajouter des données pour la requête courrante
+ * Permet d'ajouter des données pour la requête courante
*
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
@@ -129,7 +129,7 @@ public class Context {
}
/**
- * Permet d'ajouter des données pour la requête courrante
+ * Permet d'ajouter des données pour la requête courante
*
* @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
@@ -139,7 +139,15 @@ public class Context {
}
/**
- * Permet de récupérer 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 putDataLong(String key, long value) {
+ requestBundle.putLong(key, value);
+ }
+
+ /**
+ * Permet de récupérer des données pour la requête courante
*
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé ou null
@@ -149,7 +157,7 @@ public class Context {
}
/**
- * Permet de récupérer des données pour la requête courrante
+ * Permet de récupérer des données pour la requête courante
*
* @param key La clé permettant de retrouver la valeur
* @return La valeur associée à la clé
@@ -158,6 +166,14 @@ public class Context {
return requestBundle.getInt(key);
}
+ /**
+ * @param key La clé permettant de retrouver la valeur
+ * @return La valeur associée à la clé
+ */
+ public long getDataLong(String key) {
+ return requestBundle.getLong(key);
+ }
+
/**
* Permet d'ajouter un fichier à l'utilisateur
*
@@ -168,10 +184,24 @@ public class Context {
* @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) {
+ public boolean addFile(String fileName, String fileNameSalt, long size, String iv, String domain) {
return this.repository.addFileFor(new File(fileName, fileNameSalt, size, iv, Set.of(domain)), getLogin());
}
+ public String getHashedFileName(String fileName) {
+ ReadOnlyFile file = repository.getFileOf(fileName, login);
+ if (file != null) {
+ String completeFileName = login + "_" + fileName;
+ ShaHasher hasher = new ShaHasher(completeFileName);
+ return hasher.fromSalt(hasher.saltToByte(file.getFileNameSalt()));
+ }
+ return null;
+ }
+
+ public ReadOnlyFile getFile(String fileName) {
+ return this.repository.getFileOf(fileName, login);
+ }
+
public List getStringifiedFilesOf() {
return repository.getStringifiedFilesOf(login);
}
@@ -187,4 +217,8 @@ public class Context {
public void setDomain(String domain) {
this.domain = domain;
}
+
+ public void deleteFile(String deletedFileName) {
+ repository.deleteFileOf(deletedFileName, login);
+ }
}
diff --git a/app/src/main/java/lightcontainer/domains/client/RequestBundle.java b/app/src/main/java/lightcontainer/domains/client/RequestBundle.java
index 20098c0..99e0615 100644
--- a/app/src/main/java/lightcontainer/domains/client/RequestBundle.java
+++ b/app/src/main/java/lightcontainer/domains/client/RequestBundle.java
@@ -1,18 +1,20 @@
package lightcontainer.domains.client;
-
import java.util.HashMap;
import java.util.Map;
public class RequestBundle {
- private Map stringData = new HashMap<>();
+ private final Map stringData = new HashMap<>();
- private Map intData = new HashMap<>();
+ private final Map intData = new HashMap<>();
+
+ private final Map longData = new HashMap<>();
/**
* Permet d'ajouter des String
- * @param key La clé permettant de retrouver la valeur
+ *
+ * @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putString(String key, String value) {
@@ -21,7 +23,8 @@ public class RequestBundle {
/**
* Permet d'ajouter des int
- * @param key La clé permettant de retrouver la valeur
+ *
+ * @param key La clé permettant de retrouver la valeur
* @param value La valeur associée à la clé
*/
public void putInt(String key, int value) {
@@ -30,6 +33,7 @@ public class RequestBundle {
/**
* 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
*/
@@ -39,10 +43,28 @@ public class RequestBundle {
/**
* 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);
}
+
+ /**
+ * @param key La clé permettant de retrouver la valeur
+ * @param value La valeur associée à la clé
+ */
+ public void putLong(String key, long value) {
+ longData.put(key, value);
+ }
+
+ /**
+ *
+ * @param key La clé permettant de retrouver la valeur
+ * @return La valeur associée à la clé ou null
+ */
+ public long getLong(String key) {
+ return longData.get(key);
+ }
}
diff --git a/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java b/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java
index 47e2ca6..95b8ecd 100644
--- a/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java
+++ b/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java
@@ -1,75 +1,44 @@
package lightcontainer.domains.client;
-import lightcontainer.domains.Task;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.interfaces.StoreProcessorFFE;
import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.ProtocolWriter;
+import lightcontainer.utils.Log;
-import java.io.*;
+import java.io.IOException;
import java.net.Socket;
-import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
import java.util.Objects;
/**
* StoreProcessor
- *
+ *
* MULTICAST CLIENT
* Class communicating with the storebackend and
* processing the tasks in the FileFrontEnd
*
- * @version 1.1
- * @since 1.0
- *
- * @see Runnable
- * @see AutoCloseable
- * @author Jérémi NIHART
+ * @author Jérémi NIHART
+ * @version 1.1
+ * @see Runnable
+ * @see AutoCloseable
+ * @since 1.0
*/
-public class StoreProcessor extends Thread implements AutoCloseable {
+public class StoreProcessor extends UnicastThread implements AutoCloseable {
// Variables
private final StoreProcessorFFE fileFrontEnd;
- private final Socket store;
private final String domain;
- private boolean client_run;
+ private LocalDateTime lastAnnounce;
- private BufferedReader reader;
- private Context context;
- private PrintWriter writer;
private ProtocolWriter.ProtocolResult protocolResult;
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
// Constructor
public StoreProcessor(Socket socket, String domain, StoreProcessorFFE ffe, ProtocolRepository protocolRep) {
+ super(socket);
this.domain = domain;
this.fileFrontEnd = ffe;
- this.store = socket;
this.protocolRep = protocolRep;
- this.client_run = false;
- initStore();
- }
-
- /**
- * Initialise the Store's Reader and Writer.
- *
- * @see BufferedReader
- * @see PrintWriter
- * @since 1.0
- */
- private void initStore() {
- try {
- this.reader = new BufferedReader(new InputStreamReader(
- this.store.getInputStream(),
- StandardCharsets.UTF_8
- ));
- this.writer = new PrintWriter(new OutputStreamWriter(
- this.store.getOutputStream(),
- StandardCharsets.UTF_8
- ), true);
-
- this.start();
- } catch (IOException e) {
- e.printStackTrace();
- }
}
/**
@@ -80,42 +49,71 @@ public class StoreProcessor extends Thread implements AutoCloseable {
*/
@Override
public void run() {
- this.client_run = true;
- while (this.client_run) {
+ // Set process to true
+ this.setRunning(true);
+ // Process while
+ while (this.isRunning()) {
try {
- waitAction();
- System.out.println("[SBE] Envoie commande : " + protocolResult.getCommand());
+ if (protocolResult == null) { // Si on n'a pas encore la commande à envoyer
+ waitAction();
+ }
+ Log.getInstance().infoln("[SBE] Envoie commande : " + protocolResult.getCommand());
// Request
- this.writer.write(protocolResult.getCommand());
- this.writer.flush();
- protocolResult.write(this.store.getOutputStream());
-
+ this.write(protocolResult.getCommand());
+ try {
+ protocolResult.write(this.getOutputStream());
+ } catch (IOException writeException) { // Si SBE fermé
+ // Envoie au client que la requête n'a pu être traitée
+ alertAvailable(null);
+ break;
+ }
// Response
- String responseCommand = this.reader.readLine() + "\r\n";
- if (responseCommand != null)
- System.out.println("StoreBackEnd: " + responseCommand);
- ProtocolReader.ProtocolResult responseResult = protocolRep.executeReader(context, responseCommand);
- responseResult.read(
- this.store.getInputStream()
- );
- System.out.println("StoreBackEnd response to client: " + responseResult.getResultCommand());
+ String responseCommand = this.readLine();
+ if (responseCommand != null && !responseCommand.isBlank()) {
+ responseCommand += "\r\n";
+ ProtocolReader.ProtocolResult responseResult = protocolRep.executeReader(getContext(), responseCommand);
+ if (responseResult != null) {
+ Log.getInstance().infoln("StoreBackEnd (" + domain + ") response to client: " + responseResult.getResultCommand());
+ responseResult.read(
+ this.getInputStream()
+ );
- alertAvalaible(responseResult.getResultCommand());
+ alertAvailable(responseResult.getResultCommand());
+ } else {
+ Log.getInstance().infoln("StoreBackEnd result: Commande null");
+ alertAvailable(null);
+ }
+ } else {
+ Log.getInstance().infoln("StoreBackEnd: Commande null");
+ alertAvailable(null);
+ }
- } catch (IOException ignore) { }
+ } catch (IOException exception) {
+ Log.getInstance().infoln("[ERROR] Problem with SBE (" + domain + ") : " + exception.getMessage());
+ this.close();
+ }
+ }
+
+ // Closing SBE
+ try {
+ this.close();
+ this.fileFrontEnd.onStoreDisconnect(this.domain);
+ } catch (Exception e) {
+ Log.getInstance().infoln("[ERROR] Error while closing SBE (" + domain + ") : " + e.getMessage());
}
}
/**
* Permet de demander au StoreBackEnd d'effectuer une commande
+ *
* @param protocolResult La commande à effectuer
*/
public void executeCommand(Context context, ProtocolWriter.ProtocolResult protocolResult) {
synchronized (this) {
this.protocolResult = protocolResult;
- this.context = context;
+ setContext(context);
this.notify();
}
}
@@ -123,10 +121,13 @@ public class StoreProcessor extends Thread implements AutoCloseable {
/**
* Permet de déclarer le StoreBackEnd disponible
*/
- private void alertAvalaible(ProtocolWriter.ProtocolResult responseCommand) {
+ private void alertAvailable(ProtocolWriter.ProtocolResult responseCommand) {
synchronized (this) {
this.protocolResult = null;
- fileFrontEnd.onStoreAvailable(this, responseCommand);
+ if (responseCommand == null) {
+ this.setRunning(false);
+ }
+ fileFrontEnd.onStoreAvailable(this.getDomain(), responseCommand);
}
}
@@ -137,7 +138,9 @@ public class StoreProcessor extends Thread implements AutoCloseable {
synchronized (this) {
try {
this.wait();
- } catch (InterruptedException e) { e.printStackTrace(); }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
}
}
@@ -149,11 +152,9 @@ public class StoreProcessor extends Thread implements AutoCloseable {
*/
@Override
public void close() {
- if (this.client_run) {
- try {
- this.client_run = false;
- this.store.close();
- } catch (IOException ignored) { }
+ if (this.isRunning()) {
+ this.setRunning(false);
+ Log.getInstance().infoln("[SBE] Fermeture de " + domain);
}
}
@@ -176,11 +177,25 @@ public class StoreProcessor extends Thread implements AutoCloseable {
return Objects.hash(domain);
}
- public boolean canProcessTask(Task task) {
+ public boolean canProcessTask() {
return this.protocolResult == null; // Vérifier si tâche veut ce SBE
}
public String getDomain() {
return this.domain;
}
+
+ /**
+ * Permet de mettre à jours la dernière annonce de ce SBE au FFE
+ */
+ public void setLastAnnounce(LocalDateTime lastAnnounce) {
+ this.lastAnnounce = lastAnnounce;
+ }
+
+ /**
+ * Permet de mettre à jours la dernière annonce de ce SBE au FFE
+ */
+ public LocalDateTime getLastAnnounce() {
+ return lastAnnounce;
+ }
}
diff --git a/app/src/main/java/lightcontainer/domains/client/UnicastThread.java b/app/src/main/java/lightcontainer/domains/client/UnicastThread.java
new file mode 100644
index 0000000..c8d7021
--- /dev/null
+++ b/app/src/main/java/lightcontainer/domains/client/UnicastThread.java
@@ -0,0 +1,148 @@
+package lightcontainer.domains.client;
+
+import java.io.*;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+
+public abstract class UnicastThread extends Thread implements AutoCloseable {
+ // Variables
+ private final Socket socket;
+ private Context context;
+ private BufferedReader reader;
+ private PrintWriter writer;
+ private boolean isRunning = false;
+
+ /**
+ * UnicastThread Constructor
+ *
+ * @param socket Unicast Socket
+ */
+ public UnicastThread(Socket socket) {
+ this(socket, null);
+ }
+
+ /**
+ * UnicastThread Constructor
+ *
+ * @param socket Unicast Socket
+ * @param context Connection context
+ */
+ public UnicastThread(Socket socket, Context context) {
+ this.socket = socket;
+ this.context = context;
+ initSocket();
+ }
+
+ /**
+ * Initialise the Socket's Reader and Writer.
+ *
+ * @see BufferedReader
+ * @see PrintWriter
+ * @since 1.0
+ */
+ private void initSocket() {
+ // Start the thread
+ try {
+ this.reader = new BufferedReader(new InputStreamReader(
+ this.socket.getInputStream(),
+ StandardCharsets.UTF_8
+ ));
+ this.writer = new PrintWriter(new OutputStreamWriter(
+ this.socket.getOutputStream(),
+ StandardCharsets.UTF_8
+ ), true);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Read from the socket.
+ *
+ * @return Returns the line that was read
+ */
+ protected String readLine() throws IOException {
+ return this.reader.readLine();
+ }
+
+ /**
+ * Write to the socket.
+ *
+ * @param str Content to write.
+ */
+ protected void write(String str) {
+ this.writer.write(str);
+ this.writer.flush();
+ }
+
+ /**
+ * Print to the socket.
+ *
+ * @param str Content to print.
+ */
+ protected void print(String str) {
+ this.writer.print(str);
+ this.writer.flush();
+ }
+
+ /**
+ * Getter, allow to retrieve an inputstream of the socket.
+ *
+ * @return Socket inputstream.
+ */
+ protected InputStream getInputStream() throws IOException {
+ return this.socket.getInputStream();
+ }
+
+ /**
+ * Getter, allow to retrieve an outputstream of the socket.
+ *
+ * @return Socket outputstream.
+ */
+ protected OutputStream getOutputStream() throws IOException {
+ return this.socket.getOutputStream();
+ }
+
+ /**
+ * Close all connection stream and resources.
+ */
+ @Override
+ public void close() throws IOException {
+ this.reader.close();
+ this.writer.close();
+ this.socket.close();
+ setRunning(false);
+ }
+
+ /**
+ * Allow to verify if the thread is running.
+ * @return True; yes, False; no.
+ */
+ protected boolean isRunning() {
+ return this.isRunning;
+ }
+
+ /**
+ * Setter, define the running status.
+ * @param running True; is running, False; is not running.
+ */
+ protected void setRunning(boolean running) {
+ this.isRunning = running;
+ }
+
+ /**
+ * Retrieve connection context.
+ * @return Context.
+ */
+ protected Context getContext() {
+ return this.context;
+ }
+
+ /**
+ * Set connection context.
+ * @param context context.
+ */
+ protected void setContext(Context context) {
+ this.context = context;
+ }
+}
diff --git a/app/src/main/java/lightcontainer/domains/server/MulticastServerListener.java b/app/src/main/java/lightcontainer/domains/server/MulticastServerListener.java
index 96342f0..c87149a 100644
--- a/app/src/main/java/lightcontainer/domains/server/MulticastServerListener.java
+++ b/app/src/main/java/lightcontainer/domains/server/MulticastServerListener.java
@@ -3,9 +3,10 @@ package lightcontainer.domains.server;
import lightcontainer.domains.client.StoreProcessor;
import lightcontainer.interfaces.MulticastSPR;
import lightcontainer.interfaces.ProtocolRepository;
-import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.reader.HelloRule;
import lightcontainer.repository.FileFrontEnd;
+import lightcontainer.utils.Log;
+import lightcontainer.utils.NetChooser;
import java.io.IOException;
import java.net.*;
@@ -25,7 +26,8 @@ public class MulticastServerListener implements Runnable {
// Variable
private final String multicast_address;
private final int multicast_port;
- private FileFrontEnd ffe;
+ private final String network_interface;
+ private final FileFrontEnd ffe;
private final MulticastSPR repository;
private final ProtocolRepository protocolRep;
@@ -33,12 +35,13 @@ public class MulticastServerListener implements Runnable {
private MulticastSocket listener;
// Constructor
- public MulticastServerListener(FileFrontEnd ffe, MulticastSPR repository, ProtocolRepository protocolRep, String multicast_address, int multicast_port) {
+ public MulticastServerListener(FileFrontEnd ffe, MulticastSPR repository, ProtocolRepository protocolRep, String multicast_address, int multicast_port, String network_interface) {
this.ffe = ffe;
this.repository = repository;
this.protocolRep = protocolRep;
this.multicast_address = multicast_address;
this.multicast_port = multicast_port;
+ this.network_interface = network_interface;
repository.setServerListener(this);
}
@@ -54,6 +57,9 @@ public class MulticastServerListener implements Runnable {
try {
// Create a new listening socket
this.listener = new MulticastSocket(this.multicast_port);
+
+ this.selectInterface();
+
// Create an identifier for the multicast group on the specified ip
InetAddress listener_group = InetAddress.getByName(this.multicast_address);
// Creation of a packet for the information received
@@ -63,25 +69,52 @@ public class MulticastServerListener implements Runnable {
while (true) {
// Read the packet received and build a string of characters
this.listener.receive(packet);
- String data = new String(packet.getData(), 0, packet.getLength());
- // Create a new StoreBacked (try used in the case of an error to maintain the listening loop)
- try {
- // TODO Récupérer le port du message du packet et le setup (add description of the line).
- HelloRule.Result readerResult = protocolRep.executeReader(null, data);
- System.out.printf("Nouveau SBE : Domain=%s | Port=%d\n", readerResult.getDomain(), readerResult.getPort());
- Socket socket = new Socket(packet.getAddress(), readerResult.getPort());
-
- // Create the store processor
- StoreProcessor storeProcessor = new StoreProcessor(socket, readerResult.getDomain(), ffe, protocolRep); // TODO : Voir comment on procède get via repo ou ici ?!
-
- // Add the store processor to its repository
- this.repository.addStore(storeProcessor);
- } catch (IOException ignore) {
- ignore.printStackTrace();
- }
+ onNewSbe(packet);
+ }
+ } catch (IOException ioException) {
+ Log.getInstance().infoln("[ERREUR] Multicast server can't start : " + ioException.getMessage());
+ }
+ }
+
+ private void onNewSbe(DatagramPacket packet) {
+ try {
+ String data = new String(packet.getData(), 0, packet.getLength());
+
+ HelloRule.Result readerResult = protocolRep.executeReader(null, data);
+
+ Log.getInstance().infof("Nouveau SBE : Domain=%s | Port=%d\n", readerResult.getDomain(), readerResult.getPort());
+
+ if (!this.repository.hasDomain(readerResult.getDomain())){
+ Socket socket = new Socket(packet.getAddress(), readerResult.getPort());
+
+ // Create the store processor
+ StoreProcessor storeProcessor = new StoreProcessor(socket, readerResult.getDomain(), ffe, protocolRep); // TODO : Voir comment on procède get via repo ou ici ?!
+
+ // Add the store processor to its repository
+ this.repository.addStore(storeProcessor);
+ }
+ // Contient déjà le SBE donc maj de la dernière activité
+ this.repository.updateLastAnnounce(readerResult.getDomain());
+ } catch (IOException | ClassCastException exception) {
+ Log.getInstance().infoln("[ERREUR] Une SBE essaye de se connecter avec une mauvaise configuration : " + exception.getMessage());
+ }
+ }
+
+ /**
+ * Permet de choisir l'interface réseau d'écoute en Multicast
+ */
+ private void selectInterface() {
+ try {
+ this.listener.setNetworkInterface(NetworkInterface.getByName(network_interface));
+ } catch (SocketException| NullPointerException e) {
+ NetChooser netChooser = new NetChooser();
+ try {
+ this.listener.setNetworkInterface(netChooser.requestInterface());
+ } catch (SocketException socketException) {
+ socketException.printStackTrace();
+ this.stop();
}
- } catch (Exception ignore) {
}
}
@@ -92,6 +125,7 @@ public class MulticastServerListener implements Runnable {
* @since 1.0
*/
public void stop() {
+ repository.disconnectDomains();
this.listener.close();
}
}
diff --git a/app/src/main/java/lightcontainer/domains/server/UnicastServerListener.java b/app/src/main/java/lightcontainer/domains/server/UnicastServerListener.java
index e68abf1..e22124b 100644
--- a/app/src/main/java/lightcontainer/domains/server/UnicastServerListener.java
+++ b/app/src/main/java/lightcontainer/domains/server/UnicastServerListener.java
@@ -5,15 +5,12 @@ import lightcontainer.domains.client.Context;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.interfaces.UnicastCHR;
import lightcontainer.repository.FileFrontEnd;
-import lightcontainer.storage.AppData;
import lightcontainer.storage.Repository;
-import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.ServerSocket;
-import java.net.Socket;
public class UnicastServerListener implements Runnable {
// Variables
@@ -55,11 +52,11 @@ public class UnicastServerListener implements Runnable {
SSLSocket client = (SSLSocket) this.server.accept();
// Create a new Handler client by passing these dependencies to it
- ClientHandler clientHandler = new ClientHandler(this.repository, client, ffe, protocolRep, new Context(repositoryStorage));
+ ClientHandler clientHandler = new ClientHandler(this.repository, client, ffe, protocolRep, new Context(repositoryStorage, repository));
// Add the client handler to its repository (clienthandlerrepository)
this.repository.addClient(clientHandler);
// Start the thread
- (new Thread(clientHandler)).start();
+ clientHandler.start();
}
} catch (IOException e) {
e.printStackTrace();
diff --git a/app/src/main/java/lightcontainer/enumerations/TaskType.java b/app/src/main/java/lightcontainer/enumerations/TaskType.java
index 347e6ce..6a59ca3 100644
--- a/app/src/main/java/lightcontainer/enumerations/TaskType.java
+++ b/app/src/main/java/lightcontainer/enumerations/TaskType.java
@@ -3,7 +3,7 @@ package lightcontainer.enumerations;
import lightcontainer.domains.Task;
/**
- * enumeration to define the type of a {@link Task}.
+ * enumeration to define the type of {@link Task}.
*/
public enum TaskType {
SEND,
diff --git a/app/src/main/java/lightcontainer/interfaces/ClientHandlerFFE.java b/app/src/main/java/lightcontainer/interfaces/ClientHandlerFFE.java
index 2cd5c90..466649c 100644
--- a/app/src/main/java/lightcontainer/interfaces/ClientHandlerFFE.java
+++ b/app/src/main/java/lightcontainer/interfaces/ClientHandlerFFE.java
@@ -13,9 +13,11 @@ public interface ClientHandlerFFE {
/**
* Demande le traitement d'une commande
+ *
* @param context Context de la requête
* @param command Commande à traiter
*/
- void newCommand(Context context, ProtocolWriter.ProtocolResult command);
+ void newCommand(Context context, ProtocolWriter.ProtocolResult command, String requestDomain);
+ boolean canExecuteCommand(String domain);
}
diff --git a/app/src/main/java/lightcontainer/interfaces/MulticastSPR.java b/app/src/main/java/lightcontainer/interfaces/MulticastSPR.java
index 1d634c4..08fff0f 100644
--- a/app/src/main/java/lightcontainer/interfaces/MulticastSPR.java
+++ b/app/src/main/java/lightcontainer/interfaces/MulticastSPR.java
@@ -5,23 +5,63 @@ import lightcontainer.domains.client.StoreProcessor;
import lightcontainer.domains.server.MulticastServerListener;
import lightcontainer.repository.StoreProcessorRepository;
+import java.time.LocalDateTime;
+import java.util.Collection;
+
/**
* A communication interface between a {@link StoreProcessor} and the {@link StoreProcessorRepository}.
*/
public interface MulticastSPR {
/**
* Setter, allow to define the ServerListener of a repository.
+ *
* @param server ServerListener to set as default.
*/
void setServerListener(MulticastServerListener server);
/**
* Add a StorePorcessor.
+ *
* @param store Store processor to add.
*/
- void addStore(StoreProcessor store);
+ boolean addStore(StoreProcessor store);
- String findDomain(Task task);
+ String findDomain();
void assignTask(String stor, Task task);
+
+ boolean hasDomain(String domain);
+
+ int domainCount();
+
+ /**
+ * Déconnecte tous les SBE
+ */
+ void disconnectDomains();
+
+ /**
+ * Permet de déconnecter un SBE
+ *
+ * @param domain Le domaine du SBE à déconnecter
+ */
+ void closeStore(String domain);
+
+ /**
+ * Permet de mettre à jours la dernière annonce de ce SBE au FFE
+ * @param domain Le domain s'annoncant
+ */
+ void updateLastAnnounce(String domain);
+
+
+ /**
+ * Permet de récupérer les noms des domaines connectés au FFE
+ * @return Les noms des domaines connectés au FFE
+ */
+ Collection getDomains();
+
+ /**
+ * Permet de récupérer la dernière annonce d'un SBE
+ * @return La dernière annonce d'un SBE
+ */
+ LocalDateTime getLastAnnounce(String domain);
}
diff --git a/app/src/main/java/lightcontainer/interfaces/ProtocolRepository.java b/app/src/main/java/lightcontainer/interfaces/ProtocolRepository.java
index ccae2fe..d707f39 100644
--- a/app/src/main/java/lightcontainer/interfaces/ProtocolRepository.java
+++ b/app/src/main/java/lightcontainer/interfaces/ProtocolRepository.java
@@ -8,7 +8,7 @@ public interface ProtocolRepository {
T executeReader(Context context, String data);
- T executeWriter(Context context, String cmdName, String... data);
+ T executeWriter(Context context, String cmdName, String... data);
void addReader(ProtocolReader reader);
diff --git a/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java b/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java
index 26be68b..5158551 100644
--- a/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java
+++ b/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java
@@ -10,8 +10,16 @@ import lightcontainer.repository.FileFrontEnd;
public interface StoreProcessorFFE {
/**
* Allows a {@link StoreProcessor} to notify the FFE that it's available.
- * @param store The store processor that is now available.
- * @param responseCommand
+ *
+ * @param storeDomain The store processor that is now available.
+ * @param response
*/
- void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response);
+ void onStoreAvailable(String storeDomain, ProtocolWriter.ProtocolResult response);
+
+ /**
+ * Permet de déconnecter un SBE
+ *
+ * @param domain Le domaine du SBE à déconnecter
+ */
+ void onStoreDisconnect(String domain);
}
diff --git a/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java b/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java
index 53af817..fc5431c 100644
--- a/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java
+++ b/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java
@@ -1,29 +1,33 @@
package lightcontainer.interfaces;
import lightcontainer.domains.client.ClientHandler;
-import lightcontainer.domains.server.MulticastServerListener;
import lightcontainer.domains.server.UnicastServerListener;
import lightcontainer.protocol.ProtocolWriter;
import lightcontainer.repository.ClientHandlerRepository;
+import lightcontainer.repository.ReadOnlyClientRepository;
/**
* A communication interface between a {@link ClientHandler} and the {@link ClientHandlerRepository}.
*/
-public interface UnicastCHR {
+public interface UnicastCHR extends ReadOnlyClientRepository {
/**
* Setter, allow to define the ServerListener of a repository.
+ *
* @param server ServerListener to set as default.
*/
void setServerListener(UnicastServerListener server);
/**
* Add a ClientHandler.
+ *
* @param client Client Handler to add.
*/
void addClient(ClientHandler client);
+
/**
* Permet de demander la déconnection d'un client
+ *
* @param client Le client à déconnecter
*/
void disconnect(ClientHandler client);
diff --git a/app/src/main/java/lightcontainer/protocol/ProtocolReader.java b/app/src/main/java/lightcontainer/protocol/ProtocolReader.java
index ebace44..b6e4c0f 100644
--- a/app/src/main/java/lightcontainer/protocol/ProtocolReader.java
+++ b/app/src/main/java/lightcontainer/protocol/ProtocolReader.java
@@ -20,11 +20,13 @@ public abstract class ProtocolReader {
this.rulePattern = Pattern.compile(pattern);
}
+ // Receiver list
public enum ResultCmdReceiver {
CLIENT,
STOREBACKEND
}
+
/**
* Modèle utilisé par tout les résultats des règles de protocol.
* Lorsqu'il retourne son résultat, on vérifie si il y a une demande de lecture/écriture de fichier depuis le réseau. Si oui on appel ces méthodes, sinon on ne fait rien.
@@ -39,7 +41,12 @@ public abstract class ProtocolReader {
/**
* Le context courant
*/
- private Context context;
+ private final Context context;
+
+ /**
+ * Domaine demandé pour l'exécution de cette commande (NULL si aucun domaine spécifique demandé)
+ */
+ private String requestDomain;
public ProtocolResult(Context context) {
this.context = context;
@@ -52,7 +59,12 @@ public abstract class ProtocolReader {
*/
private ResultCmdReceiver receiver;
- public ResultCmdReceiver getReceiver() {
+ /**
+ * Récupérer le destinataire
+ *
+ * @return Receiver
+ */
+ public final ResultCmdReceiver getReceiver() {
return receiver;
}
@@ -61,7 +73,7 @@ public abstract class ProtocolReader {
*
* @return Commande
*/
- public ProtocolWriter.ProtocolResult getResultCommand() {
+ public final ProtocolWriter.ProtocolResult getResultCommand() {
return this.resultCommand;
}
@@ -71,11 +83,12 @@ public abstract class ProtocolReader {
* @param resultCommand Commande à envoyer
* @param receiver Le receveur de cette commande
*/
- public void setResultCommand(ProtocolWriter.ProtocolResult resultCommand, ResultCmdReceiver receiver) {
+ public final void setResultCommand(ProtocolWriter.ProtocolResult resultCommand, ResultCmdReceiver receiver) {
this.resultCommand = resultCommand;
this.receiver = receiver;
}
+
/**
* Permet de lire un fichier. Cad reçevoir le contenu d'un fichier provenant du réseau.
* Redéfinissez cette méthode pour l'utiliser
@@ -87,12 +100,35 @@ public abstract class ProtocolReader {
/**
* Permet de récupérer le context courant
+ *
* @return Context courant
*/
- protected Context getContext() {
+ protected final Context getContext() {
return context;
}
+
+ /**
+ * Cette méthode est appelée lorsque la commande à exécuter ne peut pas être exécutée
+ */
+ public final String onNotExecutable(Context context) {
+ ProtocolResult cmdResult = onError(context);
+ return cmdResult == null ? null : cmdResult.getResultCommand().getCommand();
+ }
+
+ /**
+ * Accesseur du domaine demandé pour l'exécution de cette commande (NULL si aucun domaine spécifique demandé)
+ */
+ public String getRequestDomain() {
+ return requestDomain;
+ }
+
+ /**
+ * Mutateur du domaine demandé pour l'exécution de cette commande (NULL si aucun domaine spécifique demandé)
+ */
+ public void setRequestDomain(String requestDomain) {
+ this.requestDomain = requestDomain;
+ }
}
/**
@@ -123,19 +159,18 @@ public abstract class ProtocolReader {
private String extractName(String data) {
String name;
int endIndex = data.indexOf(' ');
- if (endIndex > 0) {
- name = data.substring(0, endIndex);
- } else {
+ if (endIndex <= 0) {
endIndex = data.indexOf('\r');
- name = data.substring(0, endIndex);
}
+ name = data.substring(0, endIndex);
return name;
}
/**
* Cette méthode est appelée lors de l'exécution de la règle
*
- * @param data Paramètres pour créer la commande.
+ * @param context Utilisateur context.
+ * @param data Paramètres pour créer la commande.
*/
protected abstract T onExecuted(Context context, String... data);
diff --git a/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java b/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java
index 481cdd8..156649d 100644
--- a/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java
+++ b/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java
@@ -2,6 +2,7 @@ package lightcontainer.protocol;
import lightcontainer.domains.client.Context;
+import java.io.IOException;
import java.io.OutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -22,6 +23,7 @@ public abstract class ProtocolWriter {
/**
* Permet de récupérer le nom de la commande.
+ *
* @return Nom de la commande.
*/
public final String getCmdName() {
@@ -49,21 +51,26 @@ public abstract class ProtocolWriter {
/**
* Permet d'écrire un fichier sur le réseau. Cad envoyer le contenu d'un fichier sur le réseau.
* Redéfinissez cette méthode pour l'utiliser.
+ *
* @param writer Buffer à remplir qui sera envoyer via le réseau
*/
- public void write(OutputStream writer) {}
+ public void write(OutputStream writer) throws IOException {
+ }
/**
* Accesseur au contexte courant sur lequel opère la commande
+ *
* @return Context
*/
public Context getContext() {
return context;
}
+
}
/**
* Permet de contruire une commande selon une règle établie.
+ *
* @param data Les données à ajouter dans la commande; L'ordre défini leur position dans la commande
* @return La commande construites
*/
@@ -72,11 +79,11 @@ public abstract class ProtocolWriter {
StringBuilder builder = new StringBuilder(this.cmdName);
for (String param : data)
- builder.append(" " + param);
+ builder.append(" ").append(param);
String command = builder + "\r\n";
Matcher ruleMatcher = this.rulePattern.matcher(command); // Vérifie que tout match (cf. Matcher). Si match alors on retourne la commande build, sinon on retourne NULL
- System.out.println("Essaye : " + command);
+
if (ruleMatcher.matches()) {
ProtocolResult result = onExecuted(context, data);
result.setCommand(command);
diff --git a/app/src/main/java/lightcontainer/protocol/StandardizedDefinitions.java b/app/src/main/java/lightcontainer/protocol/StandardizedDefinitions.java
new file mode 100644
index 0000000..c1eb004
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/StandardizedDefinitions.java
@@ -0,0 +1,56 @@
+package lightcontainer.protocol;
+
+public class StandardizedDefinitions {
+
+ //Parties de regex non-utilisées en dehors de cette classe.
+ private final static String DIGIT = "[\\x30-\\x39]";
+ private final static String VISIBLECHAR = "[\\x20-\\xFF]";
+ private final static String PASSCHAR = "[\\x22-\\xFF]";
+ private final static String BINARY = "[\\x00-\\xFF]";
+ private final static String LETTER = "[\\x41-\\x5A\\x61-\\x7A]";
+ private final static String DIGIT_LETTER = "[\\x30-\\x39\\x41-\\x5A\\x61-\\x7A]";
+ private final static String PORT = "(6553[\\x30-\\x35])|(655[\\x30-\\x32][\\x30-\\x39])|(65[\\x30-\\x34][\\x30-\\x32]{2})|(6[\\x30-\\x34][\\x30-\\x39]{3})|([\\x31-\\x35][\\x30-\\x39]{4})|([\\x30-\\x35]{0,5})|([\\x30-\\x39]{1,4})";
+ private final static String SIZE = DIGIT + "{1,10}";
+ private final static String LINE = "\\x0D\\x0A";
+ private final static String PASSWORD = PASSCHAR + "{5,50}";
+ private final static String BL = "\\x20";
+ private final static String FILENAME = PASSCHAR + "{1,20}";
+ private final static String DOMAIN = "[a-z-A-Z0-9.]{5,20}";
+ private final static String HASH_FILENAME = DIGIT_LETTER + "{50,200}";
+ private final static String HASH_FILECONTENT = DIGIT_LETTER + "{50,200}";
+ private final static String FILE_INFO = "(" + HASH_FILENAME + ")" + BL + "(" + SIZE + ")" + BL + "(" + HASH_FILECONTENT + ")";
+ private final static String LOGIN = DIGIT_LETTER + "{5,20}";
+
+ //Regex à utiliser dans les différents protocoles.
+ //SBE s'annonce à FFE.
+ public final static String SBE_HELLO = "^HELLO" + BL + "(" + DOMAIN + ")" + BL + "(" + PORT + ")" + LINE + "$";
+
+ //FFE demande à SBE une tâche. SBE répond à FFE.
+ public final static String FFE_SENDFILE = "^SENDFILE" + BL + FILE_INFO + LINE + "$";
+ public final static String SBE_SEND_RESULT_OK = "^SEND_OK" + LINE + "$";
+ public final static String SBE_SEND_RESULT_ERROR = "^SEND_ERROR" + LINE + "$";
+ public final static String FFE_ERASE_FILE = "^ERASEFILE" + BL + "(" + HASH_FILENAME + ")" + LINE + "$";
+ public final static String SBE_ERASE_RESULT_OK = "^ERASE_OK" + LINE + "$";
+ public final static String SBE_ERASE_RESULT_ERROR = "^ERASE_ERROR" + LINE + "$";
+ public final static String FFE_RETRIEVE_FILE = "^RETRIEVEFILE" + BL + "(" + HASH_FILENAME + ")" + LINE + "$";
+ public final static String SBE_RETRIEVE_RESULT_OK = "^RETRIEVE_OK" + BL + FILE_INFO + LINE + "$";
+ public final static String SBE_RETRIEVE_RESULT_ERROR = "^RETRIEVE_ERROR" + LINE + "$";
+
+ //Client demande à FFE une tâche. FFE répond à client.
+ public final static String CLIENT_SIGN_IN = "^SIGNIN" + BL + "(" + LOGIN + ")" + BL + "(" + PASSWORD + ")" + LINE + "$";
+ public final static String CLIENT_SIGN_UP = "^SIGNUP" + BL + "(" + LOGIN + ")" + BL + "(" + PASSWORD + ")" + LINE + "$";
+ public final static String FFE_SIGN_OK = "^SIGN_OK" + LINE + "$";
+ public final static String FFE_SIGN_ERROR = "^SIGN_ERROR" + LINE + "$";
+ public final static String CLIENT_FILE_LIST = "^FILELIST" + LINE + "$";
+ public final static String FFE_FILE_LIST_RESULT = "^FILES" + "( (" + PASSCHAR + "{1,20})!(" + DIGIT + "{1,10})){0,50}" + LINE + "$";
+ public final static String CLIENT_SAVE_FILE = "^SAVEFILE" + BL + "(" + FILENAME + ")" + BL + "(" + SIZE + ")" + LINE + "$";
+ public final static String FFE_SAVE_FILE_OK = "^SAVEFILE_OK" + LINE + "$";
+ public final static String FFE_SAVE_FILE_ERROR = "^SAVEFILE_ERROR" + LINE + "$";
+ public final static String CLIENT_GET_FILE = "^GETFILE" + BL + "(" + FILENAME + ")" + LINE + "$";
+ public final static String FFE_GET_FILE_RESULT_OK = "^GETFILE_OK" + BL + FILENAME + BL + SIZE + LINE + "$";
+ public final static String FFE_GET_FILE_RESULT_ERROR = "^GETFILE_ERROR" + LINE + "$";
+ public final static String CLIENT_REMOVE_FILE = "^REMOVEFILE" + BL + "(" + FILENAME + ")" + LINE + "$";
+ public final static String FFE_REMOVE_OK = "^REMOVEFILE_OK" + LINE + "$";
+ public final static String FFE_REMOVE_ERROR = "^REMOVEFILE_ERROR" + LINE + "$";
+ public final static String CLIENT_SIGN_OUT = "^SIGNOUT" + LINE + "$";
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/EraseErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/EraseErrorRule.java
new file mode 100644
index 0000000..f9a4be3
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/EraseErrorRule.java
@@ -0,0 +1,30 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.RemoveFileErrorRule;
+
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_ERASE_RESULT_ERROR;
+
+public class EraseErrorRule extends ProtocolReader {
+ //"^ERASE_ERROR\r\n$"
+ private static final String PATTERN = SBE_ERASE_RESULT_ERROR;
+
+ private static final String NAME = "ERASE_ERROR";
+
+ private final ProtocolRepository protocolRep;
+
+
+ public EraseErrorRule(ProtocolRepository protocolRep) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ }
+
+ @Override
+ protected ProtocolResult onExecuted(Context context, String... data) {
+ ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
+ result.setResultCommand(protocolRep.executeWriter(context, RemoveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/EraseOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/EraseOkRule.java
new file mode 100644
index 0000000..04c9ab7
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/EraseOkRule.java
@@ -0,0 +1,33 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.RemoveFileOkRule;
+
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_ERASE_RESULT_OK;
+
+public class EraseOkRule extends ProtocolReader {
+
+ private static final String PATTERN = SBE_ERASE_RESULT_OK;
+
+ private static final String NAME = "ERASE_OK";
+
+ private final ProtocolRepository protocolRep;
+
+ public EraseOkRule(ProtocolRepository protocolRep) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ }
+
+ @Override
+ protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) {
+ ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
+ String deletedFileName = context.getDataString("fileName");
+ context.deleteFile(deletedFileName);
+ result.setResultCommand(protocolRep.executeWriter(context, RemoveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+
+
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java
index 18bfeea..7598b6c 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java
@@ -7,16 +7,18 @@ import lightcontainer.protocol.rules.writer.FilesRule;
import java.util.List;
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_FILE_LIST;
+
/**
* Règle permettant de récupérer la liste des fichiers d'un utilisateur
*/
public class FilelistRule extends ProtocolReader {
// Constants
- private static final String PATTERN = "^FILELIST\r\n$";
+ private static final String PATTERN = CLIENT_FILE_LIST;
private static final String NAME = "FILELIST";
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
// Constructor
public FilelistRule(ProtocolRepository protocolRep) {
@@ -47,7 +49,7 @@ public class FilelistRule extends ProtocolReader {
return result;
}
- @Override
+ @Override//TODO ???
protected T onError(Context context) {
return super.onError(context);
}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/GetFileRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/GetFileRule.java
new file mode 100644
index 0000000..1fe4b87
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/GetFileRule.java
@@ -0,0 +1,96 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.GetFileErrorRule;
+import lightcontainer.protocol.rules.writer.RetrieveFileRule;
+import lightcontainer.storage.ReadOnlyFile;
+
+import java.util.Iterator;
+
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_GET_FILE;
+
+public class GetFileRule extends ProtocolReader {
+ // Constants
+ //"^GETFILE ([^ !]{1,20})\r\n$"
+ private static final String PATTERN = CLIENT_GET_FILE;
+ private static final String NAME = "GETFILE";
+ // -- arguments
+ private static final int FILE_NAME = 0; // Index file name.
+
+ // Variables
+ private final ProtocolRepository protocolRep;
+
+ // Constructor
+ public GetFileRule(ProtocolRepository protocolRep) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ }
+
+ /**
+ * Rule Result
+ */
+ public class Result extends ProtocolResult {
+ // Variables
+ private final String fileName;
+
+ // Constructor
+ public Result(Context context, String fileName) {
+ super(context);
+ this.fileName = fileName;
+ }
+ }
+
+ /**
+ * Cette méthode est appelée lors de l'exécution de la règle
+ *
+ * @param context Utilisateur context.
+ * @param data Paramètres pour créer la commande.
+ */
+ @Override
+ protected GetFileRule.Result onExecuted(Context context, String... data) {
+ GetFileRule.Result result = new GetFileRule.Result(context, data[FILE_NAME]);
+
+ ReadOnlyFile file = context.getFile(data[FILE_NAME]);
+
+ if (file != null) {
+ // Précision du store back end demandé pour traiter cette commande.
+ String requestDomain = extractRequestDomain(file.getStorageIterator());
+ result.setRequestDomain(requestDomain);
+
+ // Save into bundle
+ context.putDataString("fileName", file.getName());
+ context.putDataLong("fileSize", file.getSize());
+ context.putDataString("fileIV", file.getIv());
+
+ // Create cmd for storebacked
+ result.setResultCommand(protocolRep.executeWriter(context, RetrieveFileRule.NAME, context.getHashedFileName(file.getName())), ResultCmdReceiver.STOREBACKEND);
+ } else {
+ result.setResultCommand(protocolRep.executeWriter(context, GetFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ }
+ return result;
+ }
+
+ /**
+ * Cette méthode est appelée lors d'une erreur de la règle
+ */
+ protected ProtocolReader.ProtocolResult onError(Context context) {
+ ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
+ // Make getFileErrorRule
+ result.setResultCommand(protocolRep.executeWriter(context, GetFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+
+ /**
+ * TMP
+ * TODO : But futur est de pouvoir en avoir plusieurs (sbe)
+ * Cette méthode permet de choisir le domaine voulu.
+ *
+ * @param storageIterator Les domaines
+ * @return Le domain choisi
+ */
+ private String extractRequestDomain(Iterator storageIterator) {
+ return storageIterator.next();
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/HelloRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/HelloRule.java
index b2b797d..fbed0e3 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/HelloRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/HelloRule.java
@@ -3,14 +3,16 @@ package lightcontainer.protocol.rules.reader;
import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolReader;
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_HELLO;
+
/**
* Règle permettant d'être alerter de l'annoncement d'un SBE
*/
public class HelloRule extends ProtocolReader {
+ //"^HELLO ([A-Za-z0-9.]{5,20}) ([\\d]{0,5})\r\n$"
+ private static final String PATTERN = SBE_HELLO;
- private static final String PATTERN = "^HELLO ([A-Za-z0-9]{5,20}) ([0-9]{1,5})\r\n$";
-
- private static final String NAME = "HELLO";
+ private static final String NAME = "HELLO";
// Index du domain dans le tableau de donnée
private static final int DOMAIN = 0;
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/RemoveFileRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/RemoveFileRule.java
new file mode 100644
index 0000000..c25af96
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/RemoveFileRule.java
@@ -0,0 +1,80 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.EraseFileRule;
+import lightcontainer.protocol.rules.writer.RemoveFileErrorRule;
+import lightcontainer.storage.ReadOnlyFile;
+
+import java.util.Iterator;
+
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_REMOVE_FILE;
+
+public class RemoveFileRule extends ProtocolReader {
+ //"^REMOVEFILE ([^ !]{1,20})\r\n$"
+ private static final String PATTERN = CLIENT_REMOVE_FILE;
+
+ private static final String NAME = "REMOVEFILE";
+
+ private static final int FILENAME = 0;
+
+
+ private final ProtocolRepository protocolRep;
+
+ public RemoveFileRule(ProtocolRepository protocolRep) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ }
+
+ public class Result extends ProtocolResult {
+ private final String fileName;
+
+ public Result(Context context, String fileName) {
+ super(context);
+ this.fileName = fileName;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+ }
+
+ @Override
+ protected RemoveFileRule.Result onExecuted(Context context, String... data) {
+ RemoveFileRule.Result result = new RemoveFileRule.Result(context, data[FILENAME]);
+ ReadOnlyFile file = context.getFile(result.getFileName());
+
+ if (file != null) {
+ String extendedFileName = context.getHashedFileName(result.getFileName());
+ context.putDataString("fileName", result.getFileName());
+ result.setResultCommand(protocolRep.executeWriter(context, EraseFileRule.NAME, extendedFileName), ResultCmdReceiver.STOREBACKEND);
+
+ // Précision du store back end demandé pour traiter cette commande.
+ String requestDomain = extractRequestDomain(file.getStorageIterator());
+ result.setRequestDomain(requestDomain);
+ } else {
+ result.setResultCommand(protocolRep.executeWriter(context, RemoveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ }
+
+ return result;
+ }
+
+ @Override
+ protected ProtocolReader.ProtocolResult onError(Context context) {
+ ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
+ result.setResultCommand(protocolRep.executeWriter(context, RemoveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+
+ /**
+ * TODO : But futur est de pouvoir en avoir plusieurs
+ * Cette méthode permet de choisir le domaine voulu.
+ *
+ * @param storageIterator Les domaines
+ * @return Le domain choisi
+ */
+ private String extractRequestDomain(Iterator storageIterator) {
+ return storageIterator.next();
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveErrorRule.java
new file mode 100644
index 0000000..bf89586
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveErrorRule.java
@@ -0,0 +1,37 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.GetFileErrorRule;
+
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_RETRIEVE_RESULT_ERROR;
+
+public class RetrieveErrorRule extends ProtocolReader {
+ // Constants
+ //"^RETRIEVE_ERROR\r\n$"
+ private static final String PATTERN = SBE_RETRIEVE_RESULT_ERROR;
+ private static final String NAME = "RETRIEVE_ERROR";
+
+ // Variables
+ private final ProtocolRepository protocolRep;
+
+ // Constructor
+ public RetrieveErrorRule(ProtocolRepository protocolRep) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ }
+
+ /**
+ * Cette méthode est appelée lors de l'exécution de la règle
+ *
+ * @param context Utilisateur context.
+ * @param data Paramètres pour créer la commande.
+ */
+ @Override
+ protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) {
+ ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
+ result.setResultCommand(protocolRep.executeWriter(context, GetFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveOkRule.java
new file mode 100644
index 0000000..b09f3e5
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/RetrieveOkRule.java
@@ -0,0 +1,103 @@
+package lightcontainer.protocol.rules.reader;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.interfaces.ProtocolRepository;
+import lightcontainer.protocol.ProtocolReader;
+import lightcontainer.protocol.rules.writer.GetFileErrorRule;
+import lightcontainer.protocol.rules.writer.GetFileOkRule;
+import lightcontainer.utils.FileReceiver;
+import lightcontainer.utils.SHA;
+
+import java.io.InputStream;
+
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_RETRIEVE_RESULT_OK;
+
+public class RetrieveOkRule extends ProtocolReader {
+ // Constants
+ //"^RETRIEVE_OK ([A-Za-z0-9.]{50,200}) ([0-9]{1,10}) ([A-Za-z0-9.]{50,200})\r\n$"
+ private static final String PATTERN = SBE_RETRIEVE_RESULT_OK;
+ private static final String NAME = "RETRIEVE_OK";
+ // -- arguments
+ private static final int HASHED_FILE_NAME = 0; // Index hashed filename
+ private static final int FILE_SIZE = 1; // Index file size
+ private static final int HASHED_FILE_CONTENT = 2; // Index hashed file content
+
+ // Variables
+ private final ProtocolRepository protocolRep;
+ private final String storagePath;
+
+ // Variables
+ public RetrieveOkRule(ProtocolRepository protocolRep, String storagePath) {
+ super(NAME, PATTERN);
+ this.protocolRep = protocolRep;
+ this.storagePath = storagePath;
+ }
+
+ public class Result extends ProtocolResult {
+ // Variables
+ private final String filename;
+ private final long filesize;
+ private final String hashedFileContent;
+
+ public Result(Context context, String filename, long filesize, String hashedFileContent) {
+ super(context);
+ this.filename = filename;
+ this.filesize = filesize;
+ this.hashedFileContent = hashedFileContent;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public long getFilesize() {
+ return filesize;
+ }
+
+ /**
+ * @param reader Buffer rempli du fichier
+ */
+ @Override
+ public void read(InputStream reader) {
+ super.read(reader);
+
+ try {
+ FileReceiver fileReceiver = new FileReceiver(storagePath);
+ if (!fileReceiver.receiveFile(reader, this.filename, this.filesize)) {
+ throw new IllegalStateException("Bad file reception");
+ }
+ if (!SHA.hashFile(storagePath, this.filename).equals(this.hashedFileContent)) {
+ throw new IllegalStateException("File hash content are not equals");
+ }
+ } catch (IllegalStateException|SHA.ShaException e) {
+ this.setResultCommand(protocolRep.executeWriter(getContext(), GetFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ }
+ }
+ }
+
+ /**
+ * Cette méthode est appelée lors de l'exécution de la règle
+ *
+ * @param context Utilisateur context.
+ * @param data Paramètres pour créer la commande.
+ */
+ @Override
+ protected RetrieveOkRule.Result onExecuted(Context context, String... data) {
+ RetrieveOkRule.Result result = new RetrieveOkRule.Result(context, data[HASHED_FILE_NAME], Integer.parseInt(data[FILE_SIZE]), data[HASHED_FILE_CONTENT]);
+
+ // save encrypted file size into bundle
+ context.putDataLong("encryptedFileSize", result.getFilesize()); // TODO to long ?!
+ context.putDataString("hashedFileName", result.getFilename());
+
+ // Set result command
+ result.setResultCommand(protocolRep.executeWriter(context, GetFileOkRule.NAME, context.getDataString("fileName"), String.valueOf(context.getDataLong("fileSize"))), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+
+ @Override
+ protected ProtocolReader.ProtocolResult onError(Context context) {
+ ProtocolResult result = new ProtocolResult(context);
+ result.setResultCommand(protocolRep.executeWriter(context, GetFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
+ return result;
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java
index 907b1ff..7d8ac25 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java
@@ -4,17 +4,16 @@ 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;
import lightcontainer.protocol.rules.writer.SendfileRule;
import lightcontainer.utils.AES_GCM;
import lightcontainer.utils.FileReceiver;
import lightcontainer.utils.SHA;
import lightcontainer.utils.ShaHasher;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.security.NoSuchAlgorithmException;
+
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_SAVE_FILE;
/**
* Règle permettant de sauvegarder un fichier sur le SBE.
@@ -22,15 +21,16 @@ import java.security.NoSuchAlgorithmException;
*/
public class SavefileRule extends ProtocolReader {
// Constants
- private static final String PATTERN = "^SAVEFILE ([^ !]{1,20}) ([0-9]{1,10})\r\n$";
+ //"^SAVEFILE ([^ !]{1,20}) ([0-9]{1,10})\r\n$"
+ private static final String PATTERN = CLIENT_SAVE_FILE;
private static final String NAME = "SAVEFILE";
private static final int FILE_NAME = 0; // Index file name.
private static final int FILE_SIZE = 1; // Index file size.
- private ProtocolRepository protocolRep;
- private String storagePath;
+ private final ProtocolRepository protocolRep;
+ private final String storagePath;
// Constructor
public SavefileRule(ProtocolRepository protocolRep, String storagePath) {
@@ -42,10 +42,10 @@ public class SavefileRule extends ProtocolReader {
public class Result extends ProtocolResult {
// Variables
private String filename;
- private int size;
+ private final long size;
// Construct
- public Result(Context context, String filename, int size) {
+ public Result(Context context, String filename, long size) {
super(context);
this.filename = filename;
this.size = size;
@@ -54,7 +54,6 @@ public class SavefileRule extends ProtocolReader {
@Override
public void read(InputStream reader) {
super.read(reader);
- System.out.printf("Sauvegarde du fichier : %s %d\n", filename, size);
if (getContext().canAddFile()) {
try {
@@ -73,20 +72,19 @@ public class SavefileRule extends ProtocolReader {
String iv = AES_GCM.generateIV();
// retrieve file and new size
- int encryptedFileSize = fileReceiver.receiveFile(reader, this.filename, this.size, key, iv);
+ long encryptedFileSize = fileReceiver.receiveFile(reader, this.filename, this.size, key, iv);
if (encryptedFileSize < 0) throw new IOException();
String fileHash = SHA.hashFile(storagePath, this.filename);
// On met les données de la requête actuelle
- getContext().putDataInt("size", size);
+ getContext().putDataLong("size", size);
getContext().putDataString("iv", iv);
getContext().putDataString("fileNameSalt", fileNameSalt);
this.setResultCommand(protocolRep.executeWriter(getContext(), SendfileRule.NAME, this.filename, String.valueOf(encryptedFileSize), fileHash), ResultCmdReceiver.STOREBACKEND);
} catch (IOException | SHA.ShaException e) {
this.setResultCommand(protocolRep.executeWriter(getContext(), SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
- e.printStackTrace();
}
} else {
this.setResultCommand(protocolRep.executeWriter(getContext(), SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
@@ -102,6 +100,8 @@ public class SavefileRule extends ProtocolReader {
@Override
protected SavefileRule.Result onExecuted(Context context, String... data) {
SavefileRule.Result result = new SavefileRule.Result(context, data[FILE_NAME], Integer.parseInt(data[FILE_SIZE]));
+
+
return result;
}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SendErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SendErrorRule.java
index e4a589b..5439e63 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SendErrorRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SendErrorRule.java
@@ -4,20 +4,20 @@ 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;
+
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_SEND_RESULT_ERROR;
/**
* 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$";
+ //"^SEND_ERROR\r\n$"
+ private static final String PATTERN = SBE_SEND_RESULT_ERROR;
- private static final String NAME = "SEND_ERROR";
+ private static final String NAME = "SENDERROR";
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
// Constructor
public SendErrorRule(ProtocolRepository protocolRep) {
@@ -25,7 +25,6 @@ public class SendErrorRule extends ProtocolReader {
this.protocolRep = protocolRep;
}
-
@Override
protected ProtocolResult onExecuted(Context context, String... data) {
ProtocolResult result = new ProtocolResult(context);
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SendOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SendOkRule.java
index d4c2b61..a51c9ca 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SendOkRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SendOkRule.java
@@ -5,17 +5,20 @@ import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SaveFileOkRule;
+import static lightcontainer.protocol.StandardizedDefinitions.SBE_SEND_RESULT_OK;
+
/**
* Règle permettant de de confirmer la sauvegrade d'un fichier.
*/
public class SendOkRule extends ProtocolReader {
// Constants
- private static final String PATTERN = "^SEND_OK\r\n$";
+ //"^SEND_OK\r\n$"
+ private static final String PATTERN = SBE_SEND_RESULT_OK;
private static final String NAME = "SEND_OK";
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
// Constructor
public SendOkRule(ProtocolRepository protocolRep) {
@@ -23,16 +26,10 @@ public class SendOkRule extends ProtocolReader {
this.protocolRep = protocolRep;
}
-
@Override
- protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) {
+ protected ProtocolResult onExecuted(Context context, String... data) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
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;
}
}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java
index 6f697b5..0659b43 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java
@@ -6,19 +6,22 @@ import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SignErrorRule;
import lightcontainer.protocol.rules.writer.SignOkRule;
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_SIGN_IN;
+
/**
* Règle permettant de gérer la connection d'un utilisateur
*/
public class SigninRule extends ProtocolReader {
// Constants
- private static final String PATTERN = "^SIGNIN ([A-Za-z0-9]{5,20}) ([^ !]{5,50})\r\n$";
+ //"^SIGNIN ([A-Za-z0-9]{5,20}) ([^ !]{5,50})\r\n$"
+ private static final String PATTERN = CLIENT_SIGN_IN;
private static final String NAME = "SIGNIN";
private static final int LOGIN = 0; // Index du domain dans le tableau de données
private static final int PASSWORD = 1; // Index du port dans le tableau de données
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
// Constructor
public SigninRule(ProtocolRepository protocolRep) {
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SignoutRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SignoutRule.java
index 2b7a39f..63a4f49 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SignoutRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SignoutRule.java
@@ -3,12 +3,14 @@ package lightcontainer.protocol.rules.reader;
import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolReader;
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_SIGN_OUT;
+
/**
* Règle demandant la déconnexion du client
*/
public class SignoutRule extends ProtocolReader {
-
- private static final String PATTERN = "^SIGNOUT\r\n$";
+ //"^SIGNOUT\r\n$"
+ private static final String PATTERN = CLIENT_SIGN_OUT;
public static final String NAME = "SIGNOUT";
diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SignupRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SignupRule.java
index fbb56ed..ce08172 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/reader/SignupRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SignupRule.java
@@ -6,17 +6,20 @@ import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SignErrorRule;
import lightcontainer.protocol.rules.writer.SignOkRule;
+import static lightcontainer.protocol.StandardizedDefinitions.CLIENT_SIGN_UP;
+
/**
* Règle permettant de gérer la création d'un utilisateur
*/
public class SignupRule extends ProtocolReader {
// Constants
- private static final String PATTERN = "^SIGNUP ([A-Za-z0-9]{5,20}) ([^ !]{5,50})\r\n$";
+ //"^SIGNUP ([A-Za-z0-9]{5,20}) ([^ !]{5,50})\r\n$"
+ private static final String PATTERN = CLIENT_SIGN_UP;
private static final String NAME = "SIGNUP";
private static final int LOGIN = 0;
private static final int PASSWORD = 1;
- private ProtocolRepository protocolRep;
+ private final ProtocolRepository protocolRep;
public SignupRule(ProtocolRepository protocolRep) {
super(NAME, PATTERN);
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/EraseFileRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/EraseFileRule.java
new file mode 100644
index 0000000..bf966e3
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/EraseFileRule.java
@@ -0,0 +1,18 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.protocol.ProtocolWriter;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_ERASE_FILE;
+
+public class EraseFileRule extends ProtocolWriter {
+
+ //"^ERASEFILE ([A-Za-z0-9.]{50,200})\r\n$"
+ private static final String PATTERN = FFE_ERASE_FILE;
+
+ public static String NAME = "ERASEFILE";
+
+
+ public EraseFileRule() {
+ super(NAME, PATTERN);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java
index e0f50c4..5dde723 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java
@@ -2,12 +2,14 @@ package lightcontainer.protocol.rules.writer;
import lightcontainer.protocol.ProtocolWriter;
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_FILE_LIST_RESULT;
+
/**
* Règle permettant de construire une commande contenant la liste des fichiers d'un utilisateur
*/
public class FilesRule extends ProtocolWriter {
-
- private static final String PATTERN = "^FILES( ([^ !]{1,20})!([0-9]{1,10})){0,50}\r\n$";
+ //"^FILES( ([^ !]{1,20})!([0-9]{1,10})){0,50}\r\n$"
+ private static final String PATTERN = FFE_FILE_LIST_RESULT;
public static final String NAME = "FILES";
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileErrorRule.java
new file mode 100644
index 0000000..9fe17b4
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileErrorRule.java
@@ -0,0 +1,37 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.protocol.ProtocolWriter;
+import lightcontainer.utils.DeepFileEraser;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_GET_FILE_RESULT_ERROR;
+
+/**
+ * Règle utilisé dans le cas ou une erreur survient lors
+ * de la demande de récupération d'un fichier.
+ */
+public class GetFileErrorRule extends ProtocolWriter {
+ // Constants
+ //"^GETFILE_ERROR\r\n$"
+ private static final String PATTERN = FFE_GET_FILE_RESULT_ERROR;
+ public static final String NAME = "GETFILE_ERROR";
+
+ // Variables
+ private final String storagePath;
+
+ // Constructors
+ public GetFileErrorRule(String storagePath) {
+ super(NAME, PATTERN);
+ this.storagePath = storagePath;
+ }
+
+ @Override
+ protected ProtocolResult onExecuted(Context context, String... data) {
+ // Delete the file
+ try {
+ DeepFileEraser.eraseFile(String.format("%s/%s", storagePath, context.getDataString("hashedFileName")));
+ } catch (DeepFileEraser.DeepFileEraserException ignore) { }
+ // Return new protocol result
+ return new ProtocolResult(context);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileOkRule.java
new file mode 100644
index 0000000..5eb049f
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/GetFileOkRule.java
@@ -0,0 +1,69 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.domains.client.Context;
+import lightcontainer.protocol.ProtocolWriter;
+import lightcontainer.utils.DeepFileEraser;
+import lightcontainer.utils.FileSender;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_GET_FILE_RESULT_OK;
+
+public class GetFileOkRule extends ProtocolWriter {
+ // Constants
+ //"^GETFILE_OK ([^ !]{1,20}) ([0-9]{1,10})\r\n$"
+ private static final String PATTERN = FFE_GET_FILE_RESULT_OK;
+ public static final String NAME = "GETFILE_OK";
+ // -- params
+ private static final int FILE_NAME = 0; // Index file name hashed
+ private static final int FILE_SIZE = 1; // Index file size
+
+ // Variables
+ private final String storagePath;
+
+ // Constructors
+ public GetFileOkRule(String storagePath) {
+ super(NAME, PATTERN);
+ this.storagePath = storagePath;
+ }
+
+ public class Result extends ProtocolWriter.ProtocolResult {
+ // Variables
+ private final String filename;
+ private final long filesize;
+
+ // Constructors
+ public Result(Context context, String filename, long filesize) {
+ super(context);
+ this.filename = filename;
+ this.filesize = filesize;
+ }
+
+ /**
+ * Oh yeahh baby by tonton EndMove ;-)
+ *
+ * @param writer Buffer à remplir qui sera envoyer via le réseau
+ */
+ @Override
+ public void write(OutputStream writer) throws IOException {
+ FileSender fileSender = new FileSender(storagePath);
+ fileSender.sendFile(
+ getContext().getDataString("hashedFileName"),
+ writer,
+ getContext().getDataLong("encryptedFileSize"), // Encrypted file size (because data is parsing into AES system)
+ getContext().getAesKey(),
+ getContext().getDataString("fileIV")
+ );
+
+ try {
+ DeepFileEraser.eraseFile(String.format("%s/%s", storagePath, getContext().getDataString("hashedFileName")));
+ } catch (DeepFileEraser.DeepFileEraserException ignore) { }
+ }
+ }
+
+ @Override
+ protected GetFileOkRule.Result onExecuted(Context context, String... data) {
+ return new GetFileOkRule.Result(context, data[FILE_NAME], Integer.parseInt(data[FILE_SIZE]));
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileErrorRule.java
new file mode 100644
index 0000000..5fc60f1
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileErrorRule.java
@@ -0,0 +1,17 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.protocol.ProtocolWriter;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_REMOVE_ERROR;
+
+public class RemoveFileErrorRule extends ProtocolWriter {
+
+ //"^REMOVEFILE_ERROR\r\n$"
+ private static final String PATTERN = FFE_REMOVE_ERROR;
+
+ public static String NAME = "REMOVEFILE_ERROR";
+
+ public RemoveFileErrorRule() {
+ super(NAME, PATTERN);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileOkRule.java
new file mode 100644
index 0000000..6e5ab3e
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/RemoveFileOkRule.java
@@ -0,0 +1,15 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.protocol.ProtocolWriter;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_REMOVE_OK;
+
+public class RemoveFileOkRule extends ProtocolWriter {
+ //"^REMOVEFILE_OK\r\n$"
+ private static final String PATTERN = FFE_REMOVE_OK;
+ public static String NAME = "REMOVEFILE_OK";
+
+ public RemoveFileOkRule() {
+ super(NAME, PATTERN);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/RetrieveFileRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/RetrieveFileRule.java
new file mode 100644
index 0000000..951f92d
--- /dev/null
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/RetrieveFileRule.java
@@ -0,0 +1,17 @@
+package lightcontainer.protocol.rules.writer;
+
+import lightcontainer.protocol.ProtocolWriter;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_RETRIEVE_FILE;
+
+public class RetrieveFileRule extends ProtocolWriter {
+ // Constants
+ //"^RETRIEVEFILE ([A-Za-z0-9]{50,200})\r\n$"
+ private static final String PATTERN = FFE_RETRIEVE_FILE;
+ public static final String NAME = "RETRIEVEFILE";
+
+ // Constructor
+ public RetrieveFileRule() {
+ super(NAME, PATTERN);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java
index 4d1f1f3..babce90 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java
@@ -1,18 +1,44 @@
package lightcontainer.protocol.rules.writer;
+import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolWriter;
+import lightcontainer.utils.DeepFileEraser;
+import lightcontainer.utils.ShaHasher;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_SAVE_FILE_ERROR;
/**
* Règle signifiant que la sauvegarde d'un fichier a échoué
*/
public class SaveFileErrorRule extends ProtocolWriter {
-
- private static final String PATTERN = "^SAVEFILE_ERROR\r\n$";
+ //"^SAVEFILE_ERROR\r\n$"
+ private static final String PATTERN = FFE_SAVE_FILE_ERROR;
public static final String NAME = "SAVEFILE_ERROR";
- public SaveFileErrorRule() {
+ private final String storagePath;
+
+ public SaveFileErrorRule(String storagePath) {
super(NAME, PATTERN);
+ this.storagePath = storagePath;
}
+
+ @Override
+ protected ProtocolResult onExecuted(Context context, String... data) {
+ ProtocolResult result = new ProtocolResult(context);
+ String fileName = context.getDataString("fileName");
+ String fileNameSalt = context.getDataString("fileNameSalt");
+
+ if (fileName != null && fileNameSalt != null) {
+ // Suppression du fichier temporaire dans le stockage du FFE
+ ShaHasher hasher = new ShaHasher(context.getLogin() + "_" + context.getDataString("fileName"));
+ try {
+ DeepFileEraser.eraseFile(String.format("%s/%s", this.storagePath,
+ hasher.fromSalt(hasher.saltToByte(context.getDataString("fileNameSalt")))));
+ } catch (DeepFileEraser.DeepFileEraserException ignore) {
+ }
+ }
+ return result;
+ }
}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java
index 7734605..a4f2246 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java
@@ -1,18 +1,40 @@
package lightcontainer.protocol.rules.writer;
+import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolWriter;
+import lightcontainer.utils.DeepFileEraser;
+
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_SAVE_FILE_OK;
/**
* Règle signifiant que la sauvegarde d'un fichier fût un succès
*/
public class SaveFileOkRule extends ProtocolWriter {
-
- private static final String PATTERN = "^SAVEFILE_OK\r\n$";
+ //"^SAVEFILE_OK\r\n$"
+ private static final String PATTERN = FFE_SAVE_FILE_OK;
public static final String NAME = "SAVEFILE_OK";
- public SaveFileOkRule() {
+ private final String storagePath;
+
+ public SaveFileOkRule(String storagePath) {
super(NAME, PATTERN);
+ this.storagePath = storagePath;
}
+ @Override
+ protected ProtocolWriter.ProtocolResult onExecuted(Context context, String... data) {
+ ProtocolWriter.ProtocolResult result = new ProtocolWriter.ProtocolResult(context);
+
+ // Sauvegarder dans JSON
+ context.addFile(context.getDataString("fileName"), context.getDataString("fileNameSalt"), context.getDataLong("size"), context.getDataString("iv"), context.getDomain());
+
+ // Suppression du fichier temporaire dans le stockage du FFE
+ String hashedFileName = context.getHashedFileName(context.getDataString("fileName"));
+
+ try {
+ DeepFileEraser.eraseFile(String.format("%s/%s", storagePath, hashedFileName));
+ } catch (DeepFileEraser.DeepFileEraserException ignore) { }
+ return result;
+ }
}
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SendfileRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SendfileRule.java
index 850c600..8871ce6 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/SendfileRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SendfileRule.java
@@ -4,22 +4,25 @@ import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolWriter;
import lightcontainer.utils.FileSender;
+import java.io.IOException;
import java.io.OutputStream;
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_SENDFILE;
+
/**
* Règle envoyée au SBE, demandant la sauvegarde d'un fichier.
*/
public class SendfileRule extends ProtocolWriter {
-
- private static final String PATTERN = "^SENDFILE [A-Za-z0-9.]{0,200} [0-9]{1,10} [A-Za-z0-9.]{50,200}\r\n$";
+ //"^SENDFILE [A-Za-z0-9]{50,200} [0-9]{1,10} [A-Za-z0-9]{50,200}\r\n$"
+ private static final String PATTERN = FFE_SENDFILE;
public static final String NAME = "SENDFILE";
private static final int HASHED_FILE_NAME = 0; // Index file name hashed.
private static final int FILE_SIZE = 1; // Index file size.
private static final int HASHED_FILE_CONTENT = 2; // Index file content hashed.
-
- private String storagePath;
+
+ private final String storagePath;
public SendfileRule(String storagePath) {
super(NAME, PATTERN);
@@ -29,10 +32,10 @@ public class SendfileRule extends ProtocolWriter {
public class Result extends ProtocolWriter.ProtocolResult {
private final String hashedFileName;
- private final int fileSize;
+ private final long fileSize;
private final String hashedFileContent;
- public Result(Context context, String hashedFileName, int fileSize, String hashedFileContent) {
+ public Result(Context context, String hashedFileName, long fileSize, String hashedFileContent) {
super(context);
this.hashedFileName = hashedFileName;
this.fileSize = fileSize;
@@ -40,19 +43,14 @@ public class SendfileRule extends ProtocolWriter {
}
@Override
- public void write(OutputStream writer) {
+ public void write(OutputStream writer) throws IOException {
super.write(writer);
- System.out.println("Envoie du fichier au SBE");
-
FileSender fileSender = new FileSender(storagePath);
fileSender.sendFile(hashedFileName, writer);
-
- // TODO : Supprimer le fichier du FFE
}
}
-
@Override
protected SendfileRule.Result onExecuted(Context context, String... data) {
return new SendfileRule.Result(context, data[HASHED_FILE_NAME], Integer.parseInt(data[FILE_SIZE]), data[HASHED_FILE_CONTENT]);
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java
index 096bb9a..34dfba6 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java
@@ -2,12 +2,14 @@ package lightcontainer.protocol.rules.writer;
import lightcontainer.protocol.ProtocolWriter;
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_SIGN_ERROR;
+
/**
* Règle renvoyée au client lorsque l'authentification a échoué.
*/
public class SignErrorRule extends ProtocolWriter {
-
- private static final String PATTERN = "^SIGN_ERROR\r\n$";
+ //"^SIGN_ERROR\r\n$"
+ private static final String PATTERN = FFE_SIGN_ERROR;
public static final String NAME = "SIGN_ERROR";
diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SignOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SignOkRule.java
index 6d6ef04..63b5019 100644
--- a/app/src/main/java/lightcontainer/protocol/rules/writer/SignOkRule.java
+++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SignOkRule.java
@@ -2,12 +2,14 @@ package lightcontainer.protocol.rules.writer;
import lightcontainer.protocol.ProtocolWriter;
+import static lightcontainer.protocol.StandardizedDefinitions.FFE_SIGN_OK;
+
/**
* Règle renvoyée au client lorsque l'authentification a réusie.
*/
public class SignOkRule extends ProtocolWriter {
-
- private static final String PATTERN = "^SIGN_OK\r\n$";
+ //"^SIGN_OK\r\n$"
+ private static final String PATTERN = FFE_SIGN_OK;
public static final String NAME = "SIGN_OK";
diff --git a/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java b/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java
index ff17247..b1f1731 100644
--- a/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java
+++ b/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java
@@ -8,18 +8,18 @@ import lightcontainer.protocol.ProtocolWriter;
import java.util.ArrayList;
import java.util.List;
// TODO : C'est genre un ClientHandlerManager quoi hein, normal qu'il fasse blinder de chose ;)
+
/**
* ClientHandlerRepository
- *
+ *
* Repository storing ClientHandler class.
* Contains some utility functions.
*
- * @version 1.0
- * @since 1.0
- *
- * @see ClientHandler
- * @see AutoCloseable
- * @author Jérémi NIHART
+ * @author Jérémi NIHART
+ * @version 1.0
+ * @see ClientHandler
+ * @see AutoCloseable
+ * @since 1.0
*/
public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
// Variable
@@ -34,9 +34,9 @@ public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
/**
* Setter, allow to define the ServerListener of a repository.
* & Start the server.
- * @param server ServerListener to set as default.
*
- * @since 1.0
+ * @param server ServerListener to set as default.
+ * @since 1.0
*/
@Override
public void setServerListener(UnicastServerListener server) {
@@ -46,15 +46,31 @@ public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
/**
* Add a ClientHandler.
- * @param client Client Handler to add.
*
- * @since 1.0
+ * @param client Client Handler to add.
+ * @since 1.0
*/
@Override
public void addClient(ClientHandler client) {
this.handlers.add(client);
}
+ /**
+ * Permet de savoir si un client est déjà connecté avec ce login.
+ *
+ * @param login Login du client.
+ */
+ @Override
+ public boolean hasClient(String login) {
+ for (ClientHandler client : handlers) {
+ if (client.getLogin() != null && client.getLogin().equals(login)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
@Override
public void disconnect(ClientHandler client) {
if (handlers.remove(client))
@@ -75,7 +91,7 @@ public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
* AutoClosable Function
* Closes all ClientHandlers stored in this repository and deallocates all resources.
*
- * @since 1.0
+ * @since 1.0
*/
@Override
public void close() {
diff --git a/app/src/main/java/lightcontainer/repository/FileFrontEnd.java b/app/src/main/java/lightcontainer/repository/FileFrontEnd.java
index 41c864e..dd4e516 100644
--- a/app/src/main/java/lightcontainer/repository/FileFrontEnd.java
+++ b/app/src/main/java/lightcontainer/repository/FileFrontEnd.java
@@ -1,9 +1,8 @@
package lightcontainer.repository;
+import lightcontainer.domains.Task;
import lightcontainer.domains.client.Context;
import lightcontainer.domains.client.StoreProcessor;
-import lightcontainer.domains.Task;
-import lightcontainer.enumerations.TaskStatus;
import lightcontainer.interfaces.ClientHandlerFFE;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.interfaces.StoreProcessorFFE;
@@ -15,9 +14,9 @@ import java.util.concurrent.ConcurrentLinkedDeque;
public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE {
// Variables
- private Deque tasks = new ConcurrentLinkedDeque<>();
- private ClientHandlerRepository clientRepository; // TODO -> pourquoi pas une interface ? end
- private StoreProcessorRepository storeRepository; // TODO -> pourquoi pas une interface ? end
+ private final Deque tasks = new ConcurrentLinkedDeque<>();
+ private final ClientHandlerRepository clientRepository; // TODO -> pourquoi pas une interface ? end
+ private final StoreProcessorRepository storeRepository; // TODO -> pourquoi pas une interface ? end
private ProtocolRepository protocolRepository;
// Constructor
@@ -32,7 +31,7 @@ public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE {
*/
public void alertStoreProcessors(Task task) {
// On avertit les stor processors d'une nouvelle tâche
- String stor = storeRepository.findDomain(task);
+ String stor = storeRepository.findDomain();
if (stor != null) {
storeRepository.assignTask(stor, task);
task.setDomain(stor);
@@ -42,44 +41,60 @@ public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE {
/**
* Permet à un {@link StoreProcessor} d'avertir le FFE qu'il est disponible
*
- * @param store Le SBE qui s'est occupé de la tâche
+ * @param storeDomain Le SBE qui s'est occupé de la tâche
* @param response La réponse à envoyer au client
*/
@Override
- public void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response) {
- // TODO : Chercher une tâche appropriée
- if (response != null) {
- Iterator it = tasks.iterator();
- while (it.hasNext()) {
- Task task = it.next();
- if (task.isResponseOfClient(store.getDomain())) {
- clientRepository.respondToClient(task.getClient(), response);
- it.remove(); // Suppression de la tâche
- break;
- }
- }
- }
+ public void onStoreAvailable(String storeDomain, ProtocolWriter.ProtocolResult response) {
+ responseToClient(storeDomain, response);
- assignOtherTask(store);
- }
-
- private void assignOtherTask(StoreProcessor store) {
Iterator it = tasks.iterator();
-
while (it.hasNext()) {
Task task = it.next();
- if (store.canProcessTask(task)) {
- storeRepository.assignTask(store.getDomain(), task);
- task.setDomain(store.getDomain());
+ if (task.getDomain() == null || task.getDomain().equals(storeDomain)) { // Si tâche sans domaine ou si domaine requis pour la tâche est le domaine
+ task.setDomain(storeDomain);
+ storeRepository.assignTask(storeDomain, task);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onStoreDisconnect(String domain) {
+ responseToClient(domain, null);
+ Iterator it = tasks.iterator();
+ while (it.hasNext()) {
+ Task task = it.next();
+ if (storeRepository.domainCount() == 0 || (task.getDomain() != null && task.getDomain().equals(domain))) {
+ clientRepository.respondToClient(it.next().getClient(), null);
+ it.remove(); // Suppression de la tâche
+ }
+ }
+ this.storeRepository.closeStore(domain);
+ }
+
+ private void responseToClient(String storeDomain, ProtocolWriter.ProtocolResult response) {
+ Iterator it = tasks.iterator();
+ while (it.hasNext()) {
+ Task task = it.next();
+ if (task.isResponseOfClient(storeDomain)) {
+ clientRepository.respondToClient(task.getClient(), response);
+ it.remove(); // Suppression de la tâche
+ break;
}
}
}
@Override
- public void newCommand(Context context, ProtocolWriter.ProtocolResult command) {
- Task task = Task.newInstance(context, command);
+ public void newCommand(Context context, ProtocolWriter.ProtocolResult command, String requestDomain) {
+ Task task = Task.newInstance(context, command, requestDomain);
tasks.add(task);
alertStoreProcessors(task);
}
+
+ @Override
+ public boolean canExecuteCommand(String domain) {
+ return domain == null ? storeRepository.domainCount() > 0 : storeRepository.hasDomain(domain);
+ }
}
diff --git a/app/src/main/java/lightcontainer/repository/ProtocolRepositoryImpl.java b/app/src/main/java/lightcontainer/repository/ProtocolRepositoryImpl.java
index aed6995..277636b 100644
--- a/app/src/main/java/lightcontainer/repository/ProtocolRepositoryImpl.java
+++ b/app/src/main/java/lightcontainer/repository/ProtocolRepositoryImpl.java
@@ -31,7 +31,6 @@ public class ProtocolRepositoryImpl implements ProtocolRepository {
return command;
}
}
- System.out.println("COMMANDE NULL");
return null;
}
diff --git a/app/src/main/java/lightcontainer/repository/ReadOnlyClientRepository.java b/app/src/main/java/lightcontainer/repository/ReadOnlyClientRepository.java
new file mode 100644
index 0000000..6244a2c
--- /dev/null
+++ b/app/src/main/java/lightcontainer/repository/ReadOnlyClientRepository.java
@@ -0,0 +1,12 @@
+package lightcontainer.repository;
+
+public interface ReadOnlyClientRepository {
+
+ /**
+ * Permet de savoir si un client est déjà connecté avec ce login.
+ *
+ * @param login Login du client.
+ */
+ boolean hasClient(String login);
+
+}
diff --git a/app/src/main/java/lightcontainer/repository/StoreProcessorRepository.java b/app/src/main/java/lightcontainer/repository/StoreProcessorRepository.java
index 30234e4..7c17186 100644
--- a/app/src/main/java/lightcontainer/repository/StoreProcessorRepository.java
+++ b/app/src/main/java/lightcontainer/repository/StoreProcessorRepository.java
@@ -5,20 +5,22 @@ import lightcontainer.domains.client.StoreProcessor;
import lightcontainer.domains.server.MulticastServerListener;
import lightcontainer.interfaces.MulticastSPR;
+import java.time.LocalDateTime;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
// TODO : C'est genre un ClientHandlerManager quoi hein, normal qu'il fasse blinder de chose ;)
+
/**
* StoreProcessorRepository
- *
+ *
* Repository storing StorePorcessor class.
* Contains some utility functions.
*
- * @version 1.0
- * @since 1.0
- *
- * @see StoreProcessor
- * @author Jérémi NIHART
+ * @author Jérémi NIHART
+ * @version 1.0
+ * @see StoreProcessor
+ * @since 1.0
*/
public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
// Variables
@@ -33,9 +35,9 @@ public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
/**
* Setter, allow to define the ServerListener of a repository.
* & start the server.
- * @param server ServerListener to set as default.
*
- * @since 1.0
+ * @param server ServerListener to set as default.
+ * @since 1.0
*/
@Override
public void setServerListener(MulticastServerListener server) {
@@ -45,25 +47,38 @@ public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
/**
* Add a StorePorcessor.
- * @param store Store processor to add.
*
- * @since 1.0
+ * @param store Store processor to add.
+ * @since 1.0
*/
@Override
- public void addStore(StoreProcessor store) {
- this.handlers.add(store);
-
+ public boolean addStore(StoreProcessor store) {
+ if (!this.hasDomain(store.getDomain())) {
+ store.start();
+ return this.handlers.add(store);
+ }
+ return false;
}
@Override
- public String findDomain(Task task) {
- StoreProcessor handler = findSBE(task);
+ public String findDomain() {
+ StoreProcessor handler = findSBE();
return handler == null ? null : handler.getDomain();
}
- private StoreProcessor findSBE(Task task) {
+ private StoreProcessor findSBE() {
for (StoreProcessor handler : handlers) {
- if (handler.canProcessTask(task)) {
+ if (handler.canProcessTask()) {
+ return handler;
+ }
+ }
+
+ return null;
+ }
+
+ private StoreProcessor getSBE(String stor) {
+ for (StoreProcessor handler : handlers) {
+ if (handler.getDomain().equals(stor)) {
return handler;
}
}
@@ -73,16 +88,95 @@ public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
@Override
public void assignTask(String stor, Task task) {
- StoreProcessor handler = findSBE(task);
- System.out.println("Find stor : " + handler);
- handler.executeCommand(task.getContext(), task.getCommand());
+ StoreProcessor handler = getSBE(stor);
+ if (handler != null) {
+ handler.executeCommand(task.getContext(), task.getCommand());
+ }
+ }
+
+ @Override
+ public boolean hasDomain(String domain) {
+ for (StoreProcessor handler : handlers) {
+ if (handler.getDomain().equals(domain)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int domainCount() {
+ return handlers.size();
+ }
+
+ @Override
+ public void disconnectDomains() {
+ for (StoreProcessor handler : handlers) {
+ handler.close();
+ }
+ }
+
+ /**
+ * Permet de déconnecter un SBE
+ *
+ * @param domain Le domaine du SBE à déconnecter
+ */
+ @Override
+ public void closeStore(String domain) {
+ StoreProcessor storeProcessor = getSBE(domain);
+ if (storeProcessor != null) {
+ storeProcessor.close();
+ handlers.remove(storeProcessor);
+ }
+ }
+
+ /**
+ * Permet de mettre à jours la dernière annonce de ce SBE au FFE
+ *
+ * @param domain Le domain s'annoncant
+ */
+ @Override
+ public void updateLastAnnounce(String domain) {
+ StoreProcessor storeProcessor = getSBE(domain);
+ if (storeProcessor != null) {
+ storeProcessor.setLastAnnounce(LocalDateTime.now());
+ }
+ }
+
+ /**
+ * Permet de récupérer les noms des domaines connectés au FFE
+ *
+ * @return Les noms des domaines connectés au FFE
+ */
+ @Override
+ public Collection getDomains() {
+ Set domains = new HashSet<>();
+
+ for (StoreProcessor domain : handlers) {
+ domains.add(domain.getDomain());
+ }
+
+ return domains;
+ }
+
+ /**
+ * Permet de récupérer la dernière annonce d'un SBE
+ *
+ * @param domain
+ * @return La dernière annonce d'un SBE
+ */
+ @Override
+ public LocalDateTime getLastAnnounce(String domain) {
+ StoreProcessor storeProcessor = getSBE(domain);
+ return storeProcessor == null ? null : storeProcessor.getLastAnnounce();
}
/**
* AutoClosable Function
* Closes all StoreProcessor stored in this repository and deallocates all resources.
*
- * @since 1.0
+ * @since 1.0
*/
@Override
public void close() {
@@ -91,4 +185,7 @@ public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
// Close each client.
this.handlers.forEach(StoreProcessor::close);
}
+
+
+
}
diff --git a/app/src/main/java/lightcontainer/storage/AppConfig.java b/app/src/main/java/lightcontainer/storage/AppConfig.java
index 7cc0033..9bc6945 100644
--- a/app/src/main/java/lightcontainer/storage/AppConfig.java
+++ b/app/src/main/java/lightcontainer/storage/AppConfig.java
@@ -90,6 +90,7 @@ public class AppConfig {
/**
* Méthode permettant de récupérer le chemin de sauvegarde des fichiers
+ *
* @return Chemin de sauvegarde
*/
public String getStoragePath() {
diff --git a/app/src/main/java/lightcontainer/storage/AppData.java b/app/src/main/java/lightcontainer/storage/AppData.java
index d0d188b..29f22f0 100644
--- a/app/src/main/java/lightcontainer/storage/AppData.java
+++ b/app/src/main/java/lightcontainer/storage/AppData.java
@@ -16,12 +16,11 @@ import java.util.Map;
* @since 1.0
*/
public class AppData {
-
+ // Variable
private static AppData instance = null;
private AppConfig appConfig;
private final Map users;
-
/**
* Constructs a new instance of AppData.
* Sets appConfig to null and creates a new Hashmap of users.
@@ -76,14 +75,13 @@ public class AppData {
return null;
}
-
/**
* Use this method when a user signs up.
*
* @return True if the user was added. False if a user with the same name already exists.
*/
- public boolean addUser(String login, String password, String key, String passwordSalt) {
- User user = new User(login, password, key, passwordSalt, new HashMap<>());
+ public boolean addUser(String login, String password, String key) {
+ User user = new User(login, password, key, new HashMap<>());
if (this.users.containsKey(user.getName())) {
return false;
} else {
@@ -138,6 +136,24 @@ public class AppData {
}
}
+ /**
+ * Getter, allow to retrieve a specified file object.
+ *
+ * @param fileName The name of the file to retrieve.
+ * @param userName The name of the user who wants to retrieve the file.
+ * @return The requested file matching file name and username, or null
+ * if the user or file do not exist.
+ * @author Unknown...
+ * @see User#getFile(String)
+ * @see File
+ */
+ public File getFileOf(String fileName, String userName) {
+ if (this.users.containsKey(userName)) {
+ return this.users.get(userName).getFile(fileName);
+ }
+ return null;
+ }
+
/**
* Call this method after receiving REMOVEFILE_OK from the StorBackEnd.
* Do NOT call when receiving REMOVEFILE_ERROR, or it will break the system's synchronization.
@@ -171,17 +187,16 @@ public class AppData {
}
}
+ /**
+ * @param login The login of the user to test password
+ * @param password The plain text password to try against user's hashed password
+ * @return True if password matches user's password. False if user could not be found or password didn't match
+ */
public boolean verifyUser(String login, String password) {
User user = getUser(login);
return user != null && user.verifyPassword(password);
}
- public String getUserPasswordSalt(String login) {
- User user = getUser(login);
- return user == null ? null : user.getPasswordSalt();
- }
-
-
/**
* Méthode permettant de récupérer la clé AES d'un utilisateur
*
@@ -192,5 +207,4 @@ public class AppData {
User user = getUser(login);
return user == null ? null : user.getAesKey();
}
-
}
diff --git a/app/src/main/java/lightcontainer/storage/File.java b/app/src/main/java/lightcontainer/storage/File.java
index 9429cf9..18ee90d 100644
--- a/app/src/main/java/lightcontainer/storage/File.java
+++ b/app/src/main/java/lightcontainer/storage/File.java
@@ -6,15 +6,16 @@ import java.util.Set;
/**
* File represents all information related to a file
*/
-public class File {
-
+public class File implements ReadOnlyFile {
+ // Variables
private final String name;
private final String fileNameSalt;
- private final int size;
+ private final long size;
private final String iv;
private final Set storage;
- public File(String name, String fileNameSalt, int size, String iv, Set storage) {
+ // Constructor
+ public File(String name, String fileNameSalt, long size, String iv, Set storage) {
this.name = name;
this.fileNameSalt = fileNameSalt;
this.size = size;
@@ -22,22 +23,27 @@ public class File {
this.storage = storage;
}
+ @Override
public String getName() {
return name;
}
+ @Override
public String getFileNameSalt() {
return fileNameSalt;
}
- public int getSize() {
+ @Override
+ public long getSize() {
return size;
}
+ @Override
public String getIv() {
return iv;
}
+ @Override
public Iterator getStorageIterator() {
return storage.iterator();
}
@@ -50,6 +56,5 @@ public class File {
return true;
}
}
-
}
diff --git a/app/src/main/java/lightcontainer/storage/JsonAdapter.java b/app/src/main/java/lightcontainer/storage/JsonAdapter.java
index 026dc37..aed572c 100644
--- a/app/src/main/java/lightcontainer/storage/JsonAdapter.java
+++ b/app/src/main/java/lightcontainer/storage/JsonAdapter.java
@@ -1,6 +1,7 @@
package lightcontainer.storage;
import com.google.gson.*;
+import lightcontainer.utils.Log;
import java.util.*;
@@ -40,7 +41,6 @@ public class JsonAdapter implements Adapter {
user.addProperty("name", current.getName());
user.addProperty("password", current.getPassword());
user.addProperty("aes_key", current.getAesKey());
- user.addProperty("passwordSalt", current.getPasswordSalt());
JsonArray files = new JsonArray();
Iterator fileIterator = current.fileIterator();
addFiles(fileIterator, files);
@@ -98,7 +98,7 @@ public class JsonAdapter implements Adapter {
}
return appData;
} catch (JsonParseException parseException) {
- System.out.println("[FFE] : Error while loading configuration file"); //TODO - changer en log
+ Log.getInstance().infoln("[FFE] : Error while loading configuration file"); //TODO - changer en log
return null;
}
}
@@ -109,11 +109,10 @@ public class JsonAdapter implements Adapter {
String name = jsonUser.get("name").getAsString();
String password = jsonUser.get("password").getAsString();
String aeskey = jsonUser.get("aes_key").getAsString();
- String passwordSalt = jsonUser.get("passwordSalt").getAsString();
Map userFiles = new HashMap<>();
JsonArray jsonFiles = jsonUser.getAsJsonArray("files");
getFiles(userFiles, jsonFiles);
- User user = new User(name, password, aeskey, passwordSalt, userFiles);
+ User user = new User(name, password, aeskey, userFiles);
users.add(user);
}
}
diff --git a/app/src/main/java/lightcontainer/storage/ReadOnlyFile.java b/app/src/main/java/lightcontainer/storage/ReadOnlyFile.java
new file mode 100644
index 0000000..f5f77b7
--- /dev/null
+++ b/app/src/main/java/lightcontainer/storage/ReadOnlyFile.java
@@ -0,0 +1,16 @@
+package lightcontainer.storage;
+
+import java.util.Iterator;
+
+public interface ReadOnlyFile {
+
+ String getName();
+
+ String getFileNameSalt();
+
+ long getSize();
+
+ String getIv();
+
+ Iterator getStorageIterator();
+}
diff --git a/app/src/main/java/lightcontainer/storage/Repository.java b/app/src/main/java/lightcontainer/storage/Repository.java
index 81720c5..7c2201a 100644
--- a/app/src/main/java/lightcontainer/storage/Repository.java
+++ b/app/src/main/java/lightcontainer/storage/Repository.java
@@ -1,5 +1,7 @@
package lightcontainer.storage;
+import lightcontainer.utils.Log;
+
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
@@ -10,7 +12,7 @@ import java.nio.file.StandardOpenOption;
import java.util.List;
public class Repository {
-
+ // Variables
private final String filePath;
private final Adapter adapter;
private final AppData appData;
@@ -28,20 +30,20 @@ public class Repository {
/**
* Saves configuration file
*/
- public void save() {
+ public synchronized void save() {
if (filePath != null) {
String jsonAppData = adapter.toString(appData);
try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(filePath).toAbsolutePath(), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
bufferedWriter.write(jsonAppData);
bufferedWriter.flush();
} catch (IOException e) {
- System.out.println("Error while saving configuration file !");
+ Log.getInstance().infoln("Error while saving configuration file !");
}
}
}
- public boolean addUser(String login, String password, String key, String passwordSalt) {
- if (appData.addUser(login, password, key, passwordSalt)) {
+ public boolean addUser(String login, String password, String key) {
+ if (appData.addUser(login, password, key)) {
save();
return true;
}
@@ -76,7 +78,6 @@ public class Repository {
return false;
}
-
/**
* Loads configuration file
*
@@ -94,7 +95,7 @@ public class Repository {
builder.append(reader.readLine());
}
} catch (IOException e) {
- System.out.println("Error while reading configuration file");
+ Log.getInstance().infoln("Error while reading configuration file");
builder.setLength(0);
}
return builder.toString();
@@ -112,14 +113,15 @@ public class Repository {
return appData.getAppConfig().getMulticastPort();
}
+ /**
+ * @param login The login of the user to test password
+ * @param password The plain text password to try against user's hashed password
+ * @return True if password matches user's password. False if user could not be found or password didn't match
+ */
public boolean verifyUser(String login, String password) {
return appData.verifyUser(login, password);
}
- public String getUserPasswordSalt(String login) {
- return appData.getUserPasswordSalt(login);
- }
-
/**
* Méthode permettant de récupérer le chemin de sauvegarde des fichiers
*
@@ -139,8 +141,26 @@ public class Repository {
return appData.getUserAesKey(login);
}
+ /**
+ * Getter, allow to retrieve a specified file object.
+ *
+ * @param fileName The name of the file to retrieve.
+ * @param userName The name of the user who wants to retrieve the file.
+ * @return The requested file matching file name and username, or null
+ * if the user or file do not exist.
+ * @author Unknown...
+ * @see AppData#getFileOf(String, String)
+ * @see File
+ */
+ public ReadOnlyFile getFileOf(String fileName, String userName) {
+ return this.appData.getFileOf(fileName, userName);
+ }
public List getStringifiedFilesOf(String login) {
return this.appData.getStringifiedFilesOf(login);
}
+
+ public String getNetworkInterface() {
+ return this.appData.getAppConfig().getNetworkInterface();
+ }
}
diff --git a/app/src/main/java/lightcontainer/storage/User.java b/app/src/main/java/lightcontainer/storage/User.java
index 13ccbb2..19344a9 100644
--- a/app/src/main/java/lightcontainer/storage/User.java
+++ b/app/src/main/java/lightcontainer/storage/User.java
@@ -1,5 +1,7 @@
package lightcontainer.storage;
+import lightcontainer.utils.BCryptHasher;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -13,20 +15,18 @@ import java.util.Map;
* @since 1.0
*/
public class User {
-
+ // Variables
private final String name;
private final String password;
private final String aesKey;
- private final String passwordSalt;
private final Map files;
- public User(String name, String password, String aesKey, String passwordSalt, Map files) {
+ // Constructor
+ public User(String name, String password, String aesKey, Map files) {
this.name = name;
this.password = password;
this.aesKey = aesKey;
- this.passwordSalt = passwordSalt;
this.files = files;
- System.out.println(files.size() + " fichiers trouvéssss pour " + name);
}
public String getName() {
@@ -41,10 +41,6 @@ public class User {
return aesKey;
}
- public String getPasswordSalt() {
- return this.passwordSalt;
- }
-
public Iterator fileIterator() {
return files.values().iterator();
}
@@ -106,8 +102,11 @@ public class User {
}
}
+ /**
+ * @param password The plain text password to test
+ * @return True if password matches user's hashed password. False otherwise
+ */
public boolean verifyPassword(String password) {
- return this.password.equals(password);
+ return BCryptHasher.checkPassword(password, this.password);
}
-
}
diff --git a/app/src/main/java/lightcontainer/utils/AES_GCM.java b/app/src/main/java/lightcontainer/utils/AES_GCM.java
index 4b7f09f..b1ee565 100644
--- a/app/src/main/java/lightcontainer/utils/AES_GCM.java
+++ b/app/src/main/java/lightcontainer/utils/AES_GCM.java
@@ -3,7 +3,8 @@ package lightcontainer.utils;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import java.io.*;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
@@ -11,10 +12,9 @@ import java.util.Base64;
/**
* AES GCM 256 Encryption Class [DO NOT EDIT]
*
- * @since 1.0
- * @version 1.0
- *
* @author Jérémi Nihart
+ * @version 1.0
+ * @since 1.0
*/
public class AES_GCM {
// Constants
@@ -22,65 +22,12 @@ public class AES_GCM {
public static final int GCM_IV_LENGTH = 16;
public static final int GCM_TAG_LENGTH = 16;
- // Main method for testing
- public static void main(String[] args) throws Exception
- {
- /*
- * FILE ENCRYPTION DEMO
- */
- // Init files
- File inFile = new File("D:\\HELMo.png");
- File outFile = new File("D:\\HELMoCrypted.png");
- File clearFile = new File("D:\\HELMoClear.png");
- outFile.createNewFile();
- clearFile.createNewFile();
- // Make options
- String IVFile = generateIV();
- String keyFile = generateSecretKey();
- // Show options
- System.out.println("IV : "+IVFile);
- System.out.println("Key : "+keyFile);
- // Encrypt
- encryptStream(
- new FileInputStream(inFile),
- new FileOutputStream(outFile),
- inFile.length(),
- IVFile,
- keyFile
- );
- // Decrypt
- decryptStream(
- new FileInputStream(outFile),
- new FileOutputStream(clearFile),
- outFile.length(),
- IVFile,
- keyFile
- );
-
- /*
- * TEXT ENCRYPTION DEMO
- */
- // Make option
- String plainText = "Salut sombre fils de pute, comment vas tu ?";//TODO enlever le text chelou de Jérémi (ce fou là)
- String IV = generateIV();
- String key = generateSecretKey();
- // Show options
- System.out.println("IV : "+IV);
- System.out.println("Key : "+key);
- System.out.println("Original text : " + plainText);
- // Crypt
- String cryptText = encrypt(plainText, key, IV);
- System.out.println("Encrypted text : " + cryptText);
- // Decrypt
- String decryptedText = decrypt(cryptText, key, IV);
- System.out.println("Decrypted text : " + decryptedText);
- }
/**
* Decoder to decode base64 vector to byte vector.
*
- * @param base64Vector A base64 encoded vector.
- * @return Byte vector.
+ * @param base64Vector A base64 encoded vector.
+ * @return Byte vector.
*/
private static byte[] decodeBase64Vector(String base64Vector) {
Base64.Decoder b64Decoder = Base64.getDecoder();
@@ -90,10 +37,9 @@ public class AES_GCM {
/**
* Decoder to decode base64 string to plain string.
*
- * @param base64String A base64 encoded string.
- * @return Plain string.
- *
- * @see AES_GCM#decodeBase64Vector(String)
+ * @param base64String A base64 encoded string.
+ * @return Plain string.
+ * @see AES_GCM#decodeBase64Vector(String)
*/
private static String decodeBase64String(String base64String) {
return new String(decodeBase64Vector(base64String));
@@ -101,8 +47,9 @@ public class AES_GCM {
/**
* Encoder to encode vector to base64 string.
- * @param rawVector A raw vector.
- * @return A base64 encoded vector.
+ *
+ * @param rawVector A raw vector.
+ * @return A base64 encoded vector.
*/
private static String encodeBase64(byte[] rawVector) {
Base64.Encoder b64Encoder = Base64.getEncoder();
@@ -111,10 +58,10 @@ public class AES_GCM {
/**
* Encoder to encode string to base64 string.
- * @param rawString A raw string.
- * @return A base64 encoded string.
*
- * @see AES_GCM#encodeBase64(byte[]))
+ * @param rawString A raw string.
+ * @return A base64 encoded string.
+ * @see AES_GCM#encodeBase64(byte[]))
*/
private static String encodeBase64(String rawString) {
return encodeBase64(rawString.getBytes(StandardCharsets.UTF_8));
@@ -123,14 +70,12 @@ public class AES_GCM {
/**
* FACTORY, to setting up a Java cryptographic cypher.
*
- * @param op_mode the operation mode of this cipher (this is one of the
- * following: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE)
- * @param key Base64 encoded secret key.
- * @param IV Base64 encoded vector.
- *
- * @return A Cryptography cypher.
- *
- * @throws AesGcmException Throw an exception in case of an error occur while setting up the the cypher.
+ * @param op_mode the operation mode of this cipher (this is one of the
+ * following: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE)
+ * @param key Base64 encoded secret key.
+ * @param IV Base64 encoded vector.
+ * @return A Cryptography cypher.
+ * @throws AesGcmException Throw an exception in case of an error occur while setting up the the cypher.
*/
private static Cipher createCipher(int op_mode, String key, String IV) throws AesGcmException {
try {
@@ -151,9 +96,8 @@ public class AES_GCM {
/**
* Generate a secret key base64 encoded.
*
- * @return New Secret key b64 encoded.
- *
- * @throws AesGcmException Exception if an error occur.
+ * @return New Secret key b64 encoded.
+ * @throws AesGcmException Exception if an error occur.
*/
public static String generateSecretKey() throws AesGcmException {
try {
@@ -169,7 +113,7 @@ public class AES_GCM {
/**
* Generate an IV (initialisation vector) base64 encoded.
*
- * @return New generated IV b64 encoded.
+ * @return New generated IV b64 encoded.
*/
public static String generateIV() {
byte[] IV = new byte[GCM_IV_LENGTH];
@@ -181,13 +125,11 @@ public class AES_GCM {
/**
* Encrypt text, with AES GCM.
*
- * @param plainText Plain text to encrypt.
- * @param key Base64 encoded secret key.
- * @param IV Base64 encoded vector.
- *
- * @return The encrypted plain text Base64 encoded.
- *
- * @throws AesGcmException Exception if an error occur.
+ * @param plainText Plain text to encrypt.
+ * @param key Base64 encoded secret key.
+ * @param IV Base64 encoded vector.
+ * @return The encrypted plain text Base64 encoded.
+ * @throws AesGcmException Exception if an error occur.
*/
public static String encrypt(String plainText, String key, String IV) throws AesGcmException {
try {
@@ -202,18 +144,18 @@ public class AES_GCM {
/**
* Encrypt stream, with AES GCM.
+ * The output stream is automatically closed after processing.
*
- * @param in InputStream to the input, flux to encrypt.
- * @param out OutputStream to the output, encrypted flux.
- * @param fileSize Stream/file size.
- * @param key Base64 encoded secret key.
- * @param IV Base64 encoded vector.
- *
- * @throws AesGcmException Exception if an error occur.
+ * @param in InputStream to the input, flux to encrypt.
+ * @param out OutputStream to the output, encrypted flux.
+ * @param fileSize Stream/file size (! unencrypted size !).
+ * @param key Base64 encoded secret key.
+ * @param IV Base64 encoded vector.
+ * @throws AesGcmException Exception if an error occur.
*/
public static void encryptStream(InputStream in, OutputStream out, long fileSize, String key, String IV) throws AesGcmException {
byte[] buffer = new byte[1024];
- int currentSize = 0;
+ long currentSize = 0;
int bytes;
try {
// Make the cipher for encryption
@@ -221,7 +163,7 @@ public class AES_GCM {
// Initialize a CipherOutputStream
CipherOutputStream cipherOut = new CipherOutputStream(out, cipher);
// Encryption Process
- while((currentSize < fileSize) && (bytes = in.read(buffer)) > 0) {
+ while ((currentSize < fileSize) && (bytes = in.read(buffer)) > 0) {
cipherOut.write(buffer, 0, bytes);
cipherOut.flush();
currentSize += bytes;
@@ -236,13 +178,11 @@ public class AES_GCM {
/**
* Decrypt, with AES GCM.
*
- * @param cryptText The encrypted text.
- * @param key Base64 encoded secret key.
- * @param IV Base64 encoded vector.
- *
- * @return The decrypted plain text.
- *
- * @throws AesGcmException Exception if an error occur.
+ * @param cryptText The encrypted text.
+ * @param key Base64 encoded secret key.
+ * @param IV Base64 encoded vector.
+ * @return The decrypted plain text.
+ * @throws AesGcmException Exception if an error occur.
*/
public static String decrypt(String cryptText, String key, String IV) throws AesGcmException {
try {
@@ -257,18 +197,18 @@ public class AES_GCM {
/**
* Decrypt stream, with AES GCM.
+ * The input stream is automatically closed after processing.
*
- * @param in InputStream to the input, flux to decrypt.
- * @param out OutputStream to the output, decrypted flux.
- * @param fileSize Stream/file size.
- * @param key Base64 encoded secret key.
- * @param IV Base64 encoded vector.
- *
- * @throws AesGcmException Exception if an error occur.
+ * @param in InputStream to the input, flux to decrypt.
+ * @param out OutputStream to the output, decrypted flux.
+ * @param fileSize Stream/file size (! encrypted size !).
+ * @param key Base64 encoded secret key.
+ * @param IV Base64 encoded vector.
+ * @throws AesGcmException Exception if an error occur.
*/
public static void decryptStream(InputStream in, OutputStream out, long fileSize, String key, String IV) throws AesGcmException {
byte[] buffer = new byte[1024];
- int currentSize = 0;
+ long currentSize = 0;
int bytes;
try {
// Make the cipher for decryption
@@ -276,7 +216,7 @@ public class AES_GCM {
// Initialize a CipherOutputStream
CipherInputStream cipherIn = new CipherInputStream(in, cipher);
// Encryption Process
- while((currentSize < fileSize) && (bytes = cipherIn.read(buffer)) > 0) {
+ while ((currentSize < fileSize) && (bytes = cipherIn.read(buffer)) > 0) {
out.write(buffer, 0, bytes);
out.flush();
currentSize += bytes;
@@ -299,7 +239,7 @@ public class AES_GCM {
* Constructor of AesGcmException,
* which define it's own detail message.
*
- * @param msg The detail message.
+ * @param msg The detail message.
*/
public AesGcmException(String msg) {
super(msg);
@@ -310,7 +250,7 @@ public class AES_GCM {
* which propagates the error triggering
* a crash of the encryption system.
*
- * @param e Previous exception throwable.
+ * @param e Previous exception throwable.
*/
public AesGcmException(Throwable e) {
super(e);
@@ -322,8 +262,8 @@ public class AES_GCM {
* a crash of the encryption system with
* a chosen detail message.
*
- * @param e Previous exception throwable.
- * @param msg The detail message.
+ * @param e Previous exception throwable.
+ * @param msg The detail message.
*/
public AesGcmException(GeneralSecurityException e, String msg) {
super(msg, e);
diff --git a/app/src/main/java/lightcontainer/utils/BCryptHasher.java b/app/src/main/java/lightcontainer/utils/BCryptHasher.java
new file mode 100644
index 0000000..2a4aafa
--- /dev/null
+++ b/app/src/main/java/lightcontainer/utils/BCryptHasher.java
@@ -0,0 +1,14 @@
+package lightcontainer.utils;
+
+import org.mindrot.jbcrypt.BCrypt;
+
+public class BCryptHasher {
+
+ public static String hashPassword(String plainTextPassword) {
+ return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
+ }
+
+ public static boolean checkPassword(String plainTextPassword, String hashedPassword) {
+ return BCrypt.checkpw(plainTextPassword, hashedPassword);
+ }
+}
diff --git a/app/src/main/java/lightcontainer/utils/DeepFileEraser.java b/app/src/main/java/lightcontainer/utils/DeepFileEraser.java
new file mode 100644
index 0000000..7966b37
--- /dev/null
+++ b/app/src/main/java/lightcontainer/utils/DeepFileEraser.java
@@ -0,0 +1,139 @@
+package lightcontainer.utils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * DeepFileEraser - Secure file remover
+ *
+ * @since 1.0
+ * @version 1.0
+ *
+ * @author Jérémi Nihart
+ */
+public class DeepFileEraser {
+ public static final int DFE_BUFFER_DEFAULT_SIZE = 1024; // Default buffer size
+ public static final int DFE_BUFFER_MINIMUM_SIZE = 250; // Minimum buffer size
+ public static final int DFE_BASE_DEFAULT_FILL_VALUE = 0; // Filling value of the initialisation phase
+ public static final int DFE_STEP_MIN_FILL_VALUE = 0; // Minimum filling value of a writing phase
+ public static final int DFE_STEP_MAX_FILL_VALUE = 15; // Maximum filling value of a writing phase
+
+
+ /**
+ * Generate a number randomly.
+ *
+ * @param min Minimal value (included)
+ * @param max Maximal value (included)
+ *
+ * @return Random generated number.
+ */
+ private static int random(int min, int max) {
+ return min + (int)(Math.random() * ((max - min) + 1));
+ }
+
+ /**
+ * Simple remove operation.
+ *
+ * @param target File object on which to operate.
+ * @param length File size.
+ *
+ * @throws DeepFileEraserException Exception if an error occur.
+ */
+ private static void eraseBase(File target, long length) throws DeepFileEraserException {
+ byte[] buffer = new byte[DFE_BUFFER_DEFAULT_SIZE];
+ long wroteLength = 0;
+ try (OutputStream out = new FileOutputStream(target)) {
+ Arrays.fill(buffer, (byte)DFE_BASE_DEFAULT_FILL_VALUE);
+ while (wroteLength < length) {
+ if (wroteLength + buffer.length > length) {
+ buffer = new byte[(int)(length-wroteLength)];
+ Arrays.fill(buffer, (byte)DFE_BASE_DEFAULT_FILL_VALUE);
+ }
+ out.write(buffer);
+ wroteLength += buffer.length;
+ }
+ } catch (Exception e) {
+ throw new DeepFileEraserException(e, "Error while the Base erasing step.");
+ }
+ }
+
+ /**
+ * Deep remove operation.
+ *
+ * @param target File object on which to operate.
+ * @param length File size.
+ *
+ * @throws DeepFileEraserException Exception if an error occur.
+ */
+ private static void eraseStep(File target, long length) throws DeepFileEraserException {
+ byte[] buffer = new byte[random(DFE_BUFFER_MINIMUM_SIZE, DFE_BUFFER_DEFAULT_SIZE)];
+ long wroteLength = 0;
+ try (OutputStream out = new FileOutputStream(target)) {
+ while(wroteLength < length) {
+ if (wroteLength + buffer.length > length) buffer = new byte[(int)(length-wroteLength)];
+ Arrays.fill(buffer, (byte) random(DFE_STEP_MIN_FILL_VALUE, DFE_STEP_MAX_FILL_VALUE));
+ out.write(buffer);
+ wroteLength += buffer.length;
+ }
+ } catch (Exception e) {
+ throw new DeepFileEraserException(e, "Error while the Step erasing step.");
+ }
+ }
+
+ /**
+ * Erase a file deeply.
+ * default deeply level = 7.
+ *
+ * @param filePath Path of the file.
+ *
+ * @throws DeepFileEraserException Exception if an error occur.
+ */
+ public static void eraseFile(String filePath) throws DeepFileEraserException {
+ eraseFile(filePath, 7);
+ }
+
+ /**
+ * Erase a file deeply.
+ *
+ * @param filePath Path of the file.
+ * @param depthLevel Erasure level (the higher the number, the longer and more secure the erasure).
+ *
+ * @throws DeepFileEraserException Exception if an error occur.
+ */
+ public static void eraseFile(String filePath, int depthLevel) throws DeepFileEraserException {
+ // Init
+ File target = new File(filePath);
+ if (target.exists()) {
+ long targetSize = target.length();
+ // Base write
+ eraseBase(target, targetSize);
+ // Deep write
+ for (int i = 0; i < depthLevel; i++) eraseStep(target, targetSize);
+ // Delete file
+ target.delete();
+ }
+ }
+
+ /**
+ * Internal Error from DeepFileEraser encryption Class
+ */
+ public static class DeepFileEraserException extends Exception {
+ // Constant
+ private static final long serialVersionUID = -158979547897543145L;
+
+ /**
+ * Constructor of DeepFileEraserException,
+ * which propagates the error triggering
+ * a crash of the erasing file system with
+ * a chosen detail message.
+ *
+ * @param e Previous exception throwable.
+ * @param msg The detail message.
+ */
+ public DeepFileEraserException(Throwable e, String msg) {
+ super(msg, e);
+ }
+ }
+}
diff --git a/app/src/main/java/lightcontainer/utils/FileReceiver.java b/app/src/main/java/lightcontainer/utils/FileReceiver.java
index 17b7513..3a6e4d1 100644
--- a/app/src/main/java/lightcontainer/utils/FileReceiver.java
+++ b/app/src/main/java/lightcontainer/utils/FileReceiver.java
@@ -3,28 +3,55 @@ package lightcontainer.utils;
import java.io.*;
public class FileReceiver {
- private String path;
+ private final String path;
- public FileReceiver(String path) { this.path = path; }
-
- public int receiveFile(InputStream input, String fileName, int fileSize, String key, String iv) {
- BufferedOutputStream bosFile = null;
+ public FileReceiver(String path) {
+ this.path = path;
+ }
+ public int receiveFile(InputStream input, String fileName, long fileSize, String key, String iv) {
try {
- bosFile = new BufferedOutputStream(new FileOutputStream(String.format("%s/%s", path, fileName)));
-
- AES_GCM.encryptStream(input, bosFile, fileSize, key, iv);
-
- bosFile.flush();
- bosFile.close();
-
- File f = new File(String.format("%s/%s", path, fileName));
- return (int)f.length();
- } catch(IOException | AES_GCM.AesGcmException ex) {
+ File file = new File(String.format("%s/%s", path, fileName));
+ if (file.createNewFile()) {
+ try (BufferedOutputStream bufferedStream = new BufferedOutputStream(new FileOutputStream(file))) {
+ // AES close l'outputstream mais on le try with ressources au cas ou ;)
+ AES_GCM.encryptStream(input, bufferedStream, fileSize, key, iv);
+ }
+ }
+ return (int) file.length(); // TODO change the size to LONG
+ } catch (IOException | AES_GCM.AesGcmException ex) {
ex.printStackTrace();
- if(bosFile != null) { try { bosFile.close(); } catch(Exception e) {} }
return -1;
}
}
+ public boolean receiveFile(InputStream input, String fileName, long fileSize) {
+ int bytesReceived = 0;
+ BufferedOutputStream bosFile = null;
+
+ try {
+ byte[] buffer = new byte[1024];
+ bosFile = new BufferedOutputStream(new FileOutputStream(String.format("%s/%s", path, fileName)));
+ long currentOffset = 0;
+
+ while ((currentOffset < fileSize) && ((bytesReceived = input.read(buffer)) > 0)) {
+ bosFile.write(buffer, 0, bytesReceived);
+ currentOffset += bytesReceived;
+ }
+ bosFile.flush();
+ bosFile.close();
+
+ return true;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ if (bosFile != null) {
+ try {
+ bosFile.close();
+ } catch (Exception e) {
+ }
+ }
+ return false;
+ }
+ }
+
}
diff --git a/app/src/main/java/lightcontainer/utils/FileSender.java b/app/src/main/java/lightcontainer/utils/FileSender.java
index bc58fc5..b80496d 100644
--- a/app/src/main/java/lightcontainer/utils/FileSender.java
+++ b/app/src/main/java/lightcontainer/utils/FileSender.java
@@ -3,53 +3,49 @@ package lightcontainer.utils;
import java.io.*;
public class FileSender {
- private static final int DEFAULT_BUFFER=8000;
+ private static final int DEFAULT_BUFFER = 8000;
private final String path;
- public FileSender(String path) { this.path = path; }
+ public FileSender(String path) {
+ this.path = path;
+ }
- public boolean sendFile(String filename, OutputStream out, int fileSize, String aesKey, String iv) {
+ public boolean sendFile(String filename, OutputStream out, long fileSize, String aesKey, String iv) throws IOException {
BufferedInputStream bisFile;
- System.out.printf("Envoie fichier : %s - %s - %s \n", filename, aesKey, iv);
try {
File f = new File(String.format("%s/%s", path, filename));
- if(f.exists()) {
+ if (f.exists()) {
bisFile = new BufferedInputStream(new FileInputStream(f));
-
AES_GCM.decryptStream(bisFile, out, fileSize, aesKey, iv);
-
- bisFile.close();
return true;
} else
return false;
- } catch(IOException | AES_GCM.AesGcmException ex) {
- ex.printStackTrace();
- return false;
+ } catch (IOException | AES_GCM.AesGcmException ex) {
+ throw new IOException();
}
}
- public boolean sendFile(String filename, OutputStream out) {
+ public boolean sendFile(String filename, OutputStream out) throws IOException {
BufferedInputStream bisFile;
- int bytesReaded = 0;
-
+ int bytesRead = 0;
try {
- File f = new File(String.format("%s/%s", path, filename));
- long fileSize = f.length();
- if(f.exists()) {
+ File file = new File(String.format("%s/%s", path, filename));
+ long fileSize = file.length();
+ if (file.exists()) {
byte[] buffer = new byte[DEFAULT_BUFFER];
- bisFile = new BufferedInputStream(new FileInputStream(f));
+ bisFile = new BufferedInputStream(new FileInputStream(file));
long currentOffset = 0;
- while((currentOffset < fileSize) && (bytesReaded = bisFile.read(buffer)) > 0) {
- out.write(buffer, 0, bytesReaded); out.flush();
- currentOffset+= bytesReaded;
+ while ((currentOffset < fileSize) && (bytesRead = bisFile.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesRead);
+ out.flush();
+ currentOffset += bytesRead;
}
bisFile.close();
return true;
} else
return false;
- } catch(IOException ex) {
- ex.printStackTrace();
- return false;
+ } catch (IOException ex) {// todo change
+ throw ex;
}
}
diff --git a/app/src/main/java/lightcontainer/utils/Log.java b/app/src/main/java/lightcontainer/utils/Log.java
new file mode 100644
index 0000000..2a07a05
--- /dev/null
+++ b/app/src/main/java/lightcontainer/utils/Log.java
@@ -0,0 +1,35 @@
+package lightcontainer.utils;
+
+public class Log {
+
+ public void infoln(String msg) {
+ System.out.println(msg);
+ }
+
+ public void infoln(int msg) {
+ System.out.println(msg);
+ }
+
+ public void infoln(long msg) {
+ System.out.println(msg);
+ }
+
+ public void infoln(Object msg) {
+ System.out.println(msg);
+ }
+
+
+ public void infof(String msg, Object... data) {
+ System.out.printf(msg, data);
+ }
+
+ private static Log instance;
+
+ public static Log getInstance() {
+ if (instance == null) {
+ instance = new Log();
+ }
+ return instance;
+ }
+
+}
diff --git a/app/src/main/java/lightcontainer/utils/NetChooser.java b/app/src/main/java/lightcontainer/utils/NetChooser.java
index f9ecd98..0836ccf 100644
--- a/app/src/main/java/lightcontainer/utils/NetChooser.java
+++ b/app/src/main/java/lightcontainer/utils/NetChooser.java
@@ -13,15 +13,18 @@ public class NetChooser {
public NetChooser() {
loadInterfaces();
+ }
+
+ public NetworkInterface requestInterface() {
Scanner console = new Scanner(System.in);
String[] allInterfaceNames = getInterfaces();
- for(int index=0; index < allInterfaceNames.length; ++index) {
- System.out.printf("%d. %s\n", index, allInterfaceNames[index]);
+ for (int index = 0; index < allInterfaceNames.length; ++index) {
+ Log.getInstance().infof("%d. %s\n", index, allInterfaceNames[index]);
}
- System.out.printf("Select your interface :");
+ Log.getInstance().infof("Select your interface :");
NetworkInterface selected = getInterfacesByIndex(console.nextInt());
- System.out.printf("Selected interface: %s\n", selected.getDisplayName());
-
+ Log.getInstance().infof("Selected interface: %s\n", selected.getDisplayName());
+ return selected;
}
private void loadInterfaces() {
@@ -32,38 +35,35 @@ public class NetChooser {
NetworkInterface currentInterface = discoveredInterfaces.nextElement();
Enumeration inetAddresses = currentInterface.getInetAddresses();
int ipCount = 0;
- while(inetAddresses.hasMoreElements()) {
+ while (inetAddresses.hasMoreElements()) {
InetAddress currentAddress = inetAddresses.nextElement();
ipCount++;
}
- if(ipCount > 0)
+ if (ipCount > 0)
interfaces.add(currentInterface);
}
- } catch(SocketException ex) {
+ } catch (SocketException ex) {
ex.printStackTrace();
}
}
public NetworkInterface getInterfacesByIndex(int i) {
- if(i >= 0)
+ if (i >= 0)
return interfaces.get(i);
else
return null;
}
public String[] getInterfaces() {
- if(interfaces.size() > 0) {
+ if (interfaces.size() > 0) {
String[] result = new String[interfaces.size()];
for (int i = 0; i < interfaces.size(); ++i) {
- result[i] = interfaces.get(i).getDisplayName();
+ result[i] = interfaces.get(i).getDisplayName() + " --> " + interfaces.get(i).getName();
}
return result;
} else
return null;
}
- public static void main(String[] args) {
- new NetChooser();
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/lightcontainer/utils/SHA.java b/app/src/main/java/lightcontainer/utils/SHA.java
index 4ffe472..66cbcb5 100644
--- a/app/src/main/java/lightcontainer/utils/SHA.java
+++ b/app/src/main/java/lightcontainer/utils/SHA.java
@@ -3,53 +3,29 @@ package lightcontainer.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.GeneralSecurityException;
import java.security.MessageDigest;
-import java.util.Base64;
/**
* SHA 256 Hashing and borrowing Class [DO NOT EDIT]
*
- * @since 1.0
- * @version 1.0
- *
* @author Jérémi Nihart
+ * @version 1.0
+ * @since 1.0
*/
public class SHA {
// Constants
public static final String SHA_VERSION = "SHA-256";
- // Main method for testing
- public static void main(String[] args) throws Exception {
- /*
- * BORROWING ENCRYPTION DEMO
- */
- File inFile = new File("D:\\HELMo.txt");
- System.out.println(hashStream(
- new FileInputStream(inFile),
- (int)inFile.length()
- ));
-
- System.out.println(hashFile( // caca5439dc02f2ced5094e95f1a3403d42127cda29feecd2eb1c68ff38a6fee3
- "D:\\ffe",
- "46ba86ddecd2fe80c3bdb9fb2f9480b4c92057447e9d1b43863dd1a6d540f3a316571684f9e3a7459f533a9792d4925e"
- ));
- }
/**
* Make a borrowing of the stream.
*
- * @param in InputStream to the input, flux to hash.
- * @param fileSize Stream/file size.
- *
- * @return Borrowing of the full current flux.
- *
- * @throws ShaException if an error occur.
+ * @param in InputStream to the input, flux to hash.
+ * @param fileSize Stream/file size.
+ * @return Borrowing of the full current flux.
+ * @throws ShaException if an error occur.
*/
- public static String hashStream(InputStream in, int fileSize) throws ShaException {
+ public static String hashStream(InputStream in, long fileSize) throws ShaException {
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[1024];
int currentSize = 0;
@@ -58,7 +34,7 @@ public class SHA {
// Init Digest algo
MessageDigest digest = MessageDigest.getInstance(SHA_VERSION);
// Process flux
- while ((currentSize < fileSize) && (bytes=in.read(buffer)) > 0) {
+ while ((currentSize < fileSize) && (bytes = in.read(buffer)) > 0) {
digest.update(buffer, 0, bytes);
currentSize += bytes;
}
@@ -77,17 +53,19 @@ public class SHA {
/**
* Make a borrowing of the file.
*
- * @param rootPath Root path of the file.
- * @param fileName File Name.
- *
- * @return Borrowing of the file.
- *
- * @throws ShaException if an error occur.
+ * @param rootPath Root path of the file.
+ * @param fileName File Name.
+ * @return Borrowing of the file.
+ * @throws ShaException if an error occur.
*/
public static String hashFile(String rootPath, String fileName) throws ShaException {
try {
File file = new File(String.format("%s/%s", rootPath, fileName));
- return hashStream(new FileInputStream(file), (int)file.length());
+ String hash;
+ try (InputStream inStream = new FileInputStream(file)) {
+ hash = hashStream(inStream, file.length());
+ }
+ return hash;
} catch (Exception e) {
throw new ShaException(e);
}
@@ -105,11 +83,10 @@ public class SHA {
* which propagates the error triggering
* a crash of the hash system.
*
- * @param e Previous exception throwable.
+ * @param e Previous exception throwable.
*/
public ShaException(Throwable e) {
super(e);
}
}
-
}
diff --git a/app/src/main/resources/appdata.json b/app/src/main/resources/appdata.json
index 8a76dfd..fa0b3f2 100644
--- a/app/src/main/resources/appdata.json
+++ b/app/src/main/resources/appdata.json
@@ -1 +1,10 @@
-{"unicast_port":8000,"multicast_ip":"226.66.66.1","multicast_port":15502,"network_interface":"My network interface","tls":true,"storagePath":"/home/benjamin/ffe","users":[{"name":"endmove","password":"1f82407cace28cd7d97d23f82e8235d9da97575d033a12334fc71d3517f6a90fa04af829df3c722c38d3b68842e4ca2b","aes_key":"p0G+iViPp656O6aMKgcXSDT/e9/00wQH/ztUWf4tyr4=","passwordSalt":"ItYiXkwPa84Gwb6dGHQvXQ==","files":[]},{"name":"aaaaa","password":"5d628c274ebb008324f1e199d3bfff0a3fe839730a7f2355e82850d7acca5e5ca64db9071abf3d91034295695f84a617","aes_key":"qlTH6TijnfMRnrS0Qf+k6IPKGp5LoRMXGxCq16e+mF4=","passwordSalt":"Ns8Al6DpqPsIDlCSRBVTEg==","files":[{"name":"ca.crt","fileNameSalt":"Mjo7iQeEl2PYX1RDUZbSlQ==","size":4207,"iv":"uALI+Feo1lIg1lBxbCMwIQ==","storage":["lightcontainerSB01"]},{"name":"main.py","fileNameSalt":"YRwnBiXINCJ+zyxwADgNRQ==","size":854,"iv":"9LXrJFtcgU4DeUBghc4Dgw==","storage":["lightcontainerSB01"]}]}]}
\ No newline at end of file
+{
+ "unicast_port": 8000,
+ "multicast_ip": "224.66.66.1",
+ "multicast_port": 15502,
+ "network_interface": "Mon interface réseau",
+ "tls": true,
+ "storagePath": "Chemin vers le dossier FFE",
+ "users": [
+ ]
+}
\ No newline at end of file
diff --git a/app/src/main/resources/rules.txt b/app/src/main/resources/rules.txt
index 529cae7..c3deec7 100644
--- a/app/src/main/resources/rules.txt
+++ b/app/src/main/resources/rules.txt
@@ -1,22 +1,23 @@
//Standardized definitions
-digit = [0-9]
-port = (6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})
-size = [0-9]{1,10}
-line = \r\n
-visiblechar = \p{Print}
-passchar = [^ !]
-binary = .
-password = [^ !]{5,50}
-bl = //espace
-letter = [A-Za-z]
-digit_letter = [A-Za-z0-9]
-filename = [^ !]{1,20}
-domain = [A-Za-z0-9.]{5,20}
-hash_filename = [A-Za-z0-9.]{50,200}
-hash_filecontent = [A-Za-z0-9.]{50,200}
-file_info = [A-Za-z0-9.]{50,200} [0-9]{1,10} [A-Za-z0-9.]{50,200}
-login = [A-Za-z0-9]{2,20}
+digit = [\x30-\x39] //Unicode
+port = (6553[\x30-\x35])|(655[\x30-\x32][\x30-\x39])|(65[\x30-\x34][\x30-\x32]{2})|(6[\x30-\x34][\x30-\x39]{3})|([\x31-\x35][\x30-\x39]{4})|([\x30-\x35]{0,5})|([\x30-\x39]{1,4})
+size = [\x30-\x39]{1,10}
+line = \x0D\x0A
+visiblechar = [\x20-\xFF]
+passchar = [\x22-\xFF]
+binary = [\x00-\xFF]
+password = [\x22-\xFF]{5,50}
+bl = \x20 //espace
+letter = [\x41-\x5A\x61-\x7A]
+digit_letter = [\x30-\x39]|[\x41-\x5A\x61-\x7A]
+filename = [\x22-\xFF]{1,20}
+domain = [\x30-\x39\x41-\x5A\x61-\x7A]{5,20}[.] //Le point est obligatoire
+hash_filename = [\x30-\x39\x41-\x5A\x61-\x7A]{50,200}
+hash_filecontent = [\x30-\x39\x41-\x5A\x61-\x7A]{50,200}
+file_info = [\x30-\x39\x41-\x5A\x61-\x7A]{50,200}\x20[\x30-\x39]{1,10}\x20[\x30-\x39\x41-\x5A\x61-\x7A]{50,200}
+login = [\x30-\x39\x41-\x5A\x61-\x7A]{5,20}
+//OBSOLETE
//StorBackEnd to FileFrontEnd
sbe_hello = ^HELLO ([A-Za-z0-9.]{5,20}) ([\d]{0,5})\r\n$ //TODO \r\n -> à tester pour voir si déjà dans le flux ou doit être construit
diff --git a/app/src/test/java/lightcontainer/AppTest.java b/app/src/test/java/lightcontainer/AppTest.java
index 9d64c1d..7b15e0f 100644
--- a/app/src/test/java/lightcontainer/AppTest.java
+++ b/app/src/test/java/lightcontainer/AppTest.java
@@ -3,9 +3,6 @@
*/
package lightcontainer;
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
class AppTest {
// @Test void appHasAGreeting() {
// App classUnderTest = new App();
diff --git a/app/src/test/java/lightcontainer/protocol/rules/reader/HelloRuleTest.java b/app/src/test/java/lightcontainer/protocol/rules/reader/HelloRuleTest.java
index 0f5f0fe..61aa17e 100644
--- a/app/src/test/java/lightcontainer/protocol/rules/reader/HelloRuleTest.java
+++ b/app/src/test/java/lightcontainer/protocol/rules/reader/HelloRuleTest.java
@@ -3,8 +3,6 @@ package lightcontainer.protocol.rules.reader;
import lightcontainer.protocol.ProtocolReader;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
class HelloRuleTest {
@Test
diff --git a/app/src/test/java/lightcontainer/protocol/rules/writer/SignoutRuleTest.java b/app/src/test/java/lightcontainer/protocol/rules/writer/SignoutRuleTest.java
index cb3af1e..0787cd7 100644
--- a/app/src/test/java/lightcontainer/protocol/rules/writer/SignoutRuleTest.java
+++ b/app/src/test/java/lightcontainer/protocol/rules/writer/SignoutRuleTest.java
@@ -1,11 +1,7 @@
package lightcontainer.protocol.rules.writer;
-import lightcontainer.protocol.ProtocolWriter;
-import lightcontainer.protocol.rules.reader.SignoutRule;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
class SignoutRuleTest {
@Test
diff --git a/app/src/test/java/lightcontainer/storage/JsonAdapterTests.java b/app/src/test/java/lightcontainer/storage/JsonAdapterTests.java
index 2e46763..f815608 100644
--- a/app/src/test/java/lightcontainer/storage/JsonAdapterTests.java
+++ b/app/src/test/java/lightcontainer/storage/JsonAdapterTests.java
@@ -1,13 +1,5 @@
package lightcontainer.storage;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-
public class JsonAdapterTests {
/*
@Test
diff --git a/app/src/test/java/lightcontainer/storage/RepositoryTests.java b/app/src/test/java/lightcontainer/storage/RepositoryTests.java
index 7b07bbc..0c169b9 100644
--- a/app/src/test/java/lightcontainer/storage/RepositoryTests.java
+++ b/app/src/test/java/lightcontainer/storage/RepositoryTests.java
@@ -1,17 +1,5 @@
package lightcontainer.storage;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-
public class RepositoryTests {
/*
@@ -20,7 +8,7 @@ public class RepositoryTests {
try {
Files.deleteIfExists(Paths.get("src", "test", "resources", "test.json").toAbsolutePath());
} catch (IOException e) {
- System.out.println("Error while destroying file");
+ Log.getInstance().infoln("Error while destroying file");
}
}