Skip to content
Snippets Groups Projects
Commit 6b5065ba authored by ='s avatar =
Browse files

Rendu définitif

parent 850a043c
No related branches found
No related tags found
No related merge requests found
# FlopBox
Par <ins>**Rayane Hamani**</ins>, le <ins>**17 mars 2021**</ins>
Par <ins>**Florian Dendoncker**</ins>, le <ins>**17 mars 2021**</ins>
Par <ins>**Rayane Hamani**</ins>, le <ins>**01 avril 2021**</ins>
# Pré-requis
Le programme a été réalisé sous Java 11. Pour lancer le programme, il va donc falloir cette version de JRE. Elle est trouvable sur [le site officiel d'Oracle](https://www.oracle.com/fr/java/technologies/javase-downloads.html) avec [leur documentation d'installation](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-linux-platforms.html).
Le projet a été construit à partir de Maven. Maven est installable via la ligne de commande `sudo apt install maven` sur Linux ou bien sur Windows en téléchargeant l'archive sur [le site officiel d'Apache](https://maven.apache.org/download.cgi) et en suivant [leur documentation d'installation](https://maven.apache.org/install.html).
# Utilisation
Avant de pouvoir lancer le programme, il faut le compiler avec `mvn package`.
Le programme se lance ensuite en ligne de commande sans argument.
Exemple d'utilisation : `mvn exec:java`
Au lancement du programme, `un username et un password seront demandés` afin d'authentifier l'utilisateur. Si ceux-ci ne correspondent à aucun utilisateur autorisé à utiliser la plateforme, le programme le rejectera.
Si les identifiants correspondent bien à un utilisateur autorisé à utiliser la plateforme, le programme lancera la plateforme à l'adresse `http://localhost:8080/myapp/`.
Afin d'arrêter la plateforme, vous pouvez soit faire un `Ctrl+C` sur le terminal de lancement ou soit envoyer un signal `SIGKILL` au processus. Une solution permettant simplement d'écrire `stop` sur le terminal de lancement a été implémentée mais une exception au niveau du code généré lors de l'initialisation du projet, est levée empêchant cette solution de fonctionner.
# Architecture
Le projet a été construit à partir de Maven en utilisant la commande suivante :
```sh
mvn archetype:generate -DarchetypeGroupId=org.glassfish.jersey.archetypes -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeVersion=3.0.1
```
L'archive du projet, après la compilation, est `target/flopbox-1.0-SNAPSHOT.jar`.
Le code se situe dans le dossier `src/main/java/flopbox` depuis la racine du projet.
Les tests se situent dans le dossier `src/test/java/flopbox` depuis la racine du projet.
Le projet contient les packages suivants :
- **account** -> Le package relatif aux comptes pouvant utiliser la plateforme
- **command** -> Le package relatif aux commandes utilisables par la plateforme
- **server** -> Le package relatif aux serveurs auxquels peut se connecter la plateforme
# Commandes supportées
La plateforme supporte les commandes curls suivantes :
```curl
curl -v http://localhost:8080/myapp/myresource/cdup
curl -v http://localhost:8080/myapp/myresource/connect:{String address}:{int port}
curl -v http://localhost:8080/myapp/myresource/cwd:{String pathname}
curl -v http://localhost:8080/myapp/myresource/dele:{String pathname}
curl -v http://localhost:8080/myapp/myresource/list
curl -v http://localhost:8080/myapp/myresource/login:{String username}:{String password}
curl -v http://localhost:8080/myapp/myresource/mkd:{String pathname}
curl -v http://localhost:8080/myapp/myresource/pasv
curl -v http://localhost:8080/myapp/myresource/port
curl -v http://localhost:8080/myapp/myresource/pwd
curl -v http://localhost:8080/myapp/myresource/quit
curl -v http://localhost:8080/myapp/myresource/retr:{String pathname}
curl -v http://localhost:8080/myapp/myresource/rn:{String oldfilename}:{String newfilename}
curl -v http://localhost:8080/myapp/myresource/stor:{String pathname}
curl -v http://localhost:8080/myapp/myresource/type:{int type}
```
**Les informations entre crochets sont des variables à modifier dont le type a été indiqué pour plus de clarté.**
Par exemple, pour se connecter au serveur ftp.ubuntu.com, la commande à utiliser est :
```curl
curl -v http://localhost:8080/myapp/myresource/connect:ftp.ubuntu.com:21
```
# Quelques exemples de code
```java
/**
* Return if the password tried is the password of the account's username.
*
* @param username The username registered.
* @param password The password tried.
*
* @return If the password tried is the password of the username's account.
*/
public static boolean isTheRightPassword(String username, String password)
{
if(accounts.containsKey(username))
return password.equals(accounts.get(username));
else
return username.equals("anonymous");
}
```
L'objet `accounts` est une `Map<String,String>` contenant les paires `<username,password>`. Cette fonction a un comportement similaire à celui des serveurs ftp. Elle vérifie tous les utilisateurs tentant de s'enregistrer auprès de la plateforme sauf `anonymous`.
```java
/**
* Load the unique aliases in the program.
*/
public static void loadAliases()
{
Map<String, String> aliases = Main.getAliases();
try
{
BufferedReader reader = new BufferedReader(new FileReader(aliasesTxt));
String line;
while((line = reader.readLine()) != null)
{
int cut = line.indexOf(separator);
String alias = line.substring(0, cut);
/* If a same alias has already been put, we ignore it */
if(aliases.containsKey(alias))
continue;
String server = line.substring(cut+1);
aliases.put(alias, server);
}
reader.close();
}
catch(IOException e)
{
/* Do nothing */
}
}
```
Cette méthode `enregistre tous les alias uniques` des serveurs. Pour cela, elle va lire un fichier nommé `aliases.txt` à la racine du projet. `Pour ajouter ou modifier une association, c'est dans ce fichier que ça se passe.` Un système identique a été mis en place avec le fichier `accounts.txt` pour les `comptes autorisés à se connecter` à la plateforme.
```java
/**
* List the files of the working directory.
*
* @param client The FTP client.
*
* @return How the command went.
*/
@GET
@Path("list")
@Produces(MediaType.TEXT_PLAIN)
public String list(FTPClient client)
{
return LIST.execute(client);
}
```
La gestion des commandes se fait de cette façon. `Toutes les commandes sont récupérées avec @GET mais avec un @Path différent` afin de les différencier.
```java
/**
* List the files of the working directory.
*
* @param client The FTP client.
*
* @return How the command went.
*/
public static String execute(FTPClient client)
{
String response = "";
try
{
FTPFile[] files = client.listFiles();
for(FTPFile file : files)
{
response += file.getName() + "\n";
}
}
catch(IOException e)
{
response = "The command \"" + NAME + "\" failed.";
}
return response;
}
```
`Le traitement des commandes est effectué dans des classes propres` aux commandes dans le package `command`. Ce, afin que le code soit plus clair et mieux structuré.
# Les tests
Commandes curls :
Aucun test n'a été réalisé cette fois-ci.
curl -v http://localhost:2121/myapp/myresource/login:anonymous:anonymous
curl -v http://localhost:2121/myapp/myresource/pwd
curl -v http://localhost:2121/myapp/myresource/cwd:path
curl -v http://localhost:2121/myapp/myresource/dele:path
curl -v http://localhost:2121/myapp/myresource/quit
Les efforts ont été concentrés à rendre la plateforme fonctionnel.
# Ce que j'aurai amélioré avec le temps
J'aurais `mieux designé la gestion de l'authentification` auprès de la plateforme.
mvn exec:java
J'aurais `expérimenté le multi-threading` de la plateforme.
FTP Server Address : 0.0.0.0
FTP Server Port : 2121
URI port : 8080
Username : anonymous
Password : anonymous
J'aurais `débuggé les communications plateforme-serveur` (malgré que j'y ai passé déjà plusieurs jours).
\ No newline at end of file
File moved
File moved
......@@ -51,7 +51,6 @@
<version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
......
......@@ -3,7 +3,6 @@ package flopbox;
import flopbox.account.AccountUtil;
import flopbox.server.*;
import org.apache.commons.net.ftp.FTPClient;
......@@ -13,6 +12,8 @@ import org.glassfish.jersey.server.ResourceConfig;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
......@@ -24,31 +25,18 @@ import java.util.Scanner;
public class Main
{
/* URI the Grizzly HTTP server will listen on */
private static String uri;
private static String uri = "http://localhost:8080/myapp/";
/* Client the platform will use to connect to */
private static FTPClient client;
private static FTPClient client = new FTPClient();
/* Address and port the client will connect to */
private static String ftpServerAddress;
private static int ftpServerPort;
/* Account the client will login with */
private static String username;
private static String password;
/* Aliases of the servers the platform recognizes */
private static Map<String, String> aliases = new HashMap<String, String>();
/* Getters */
public static String getUri() { return uri ; }
public static FTPClient getClient() { return client ; }
public static String getFtpServerAddress() { return ftpServerAddress ; }
public static int getFtpServerPort() { return ftpServerPort ; }
public static String getUsername() { return username ; }
public static String getPassword() { return password ; }
/* Setters */
public static void setFtpServerPort(int newPort) { ftpServerPort = FtpServerUtil.setFtpServerPort(String.valueOf(newPort)) ; }
public static void setUsername(String newUsername) { username = newUsername ; }
public static void setPassword(String newPassword) { password = newPassword ; }
public static Map<String, String> getAliases() { return aliases ; }
......@@ -63,43 +51,25 @@ public class Main
/**
* Set the arguments
* Log in the platform.
*
* @return if
*/
public static void setArguments()
public static boolean login()
{
Scanner scanner = new Scanner(System.in);
/* Set the address of the ftp server to reach */
System.out.print("FTP Server Address : ");
ftpServerAddress = FtpServerUtil.setFtpServerAddress(scanner.nextLine());
/* Set the port of the ftp server to reach */
System.out.print("FTP Server Port : ");
ftpServerPort = FtpServerUtil.setFtpServerPort(scanner.nextLine());
/* Set the URI to start the server */
System.out.print("URI port : ");
uri = UriUtil.setUri(scanner.nextLine());
/* Set the username and password which will be used to log in the platform and the ftp server */
System.out.print("Username : ");
username = scanner.nextLine();
String username = scanner.nextLine();
System.out.print("Password : ");
password = scanner.nextLine();
String password = scanner.nextLine();
System.out.println();
scanner.close();
}
public static void showInfos()
{
System.out.println("FTP Server Address : " + ftpServerAddress);
System.out.println("FTP Server Port : " + ftpServerPort );
System.out.println("URI port : " + uri );
System.out.println("Username : " + username );
System.out.println("Password : " + password );
return AccountUtil.isTheRightPassword(username, password);
}
......@@ -152,49 +122,24 @@ public class Main
*/
public static void main(String[] args) throws IOException
{
/* Set the arguments of the program */
setArguments();
/* Exit the program if the server cannot be resolved */
if(ftpServerAddress.isEmpty())
{
System.out.println("The [ftp server address] could not be resolved.");
System.out.println("[ftp server address] is necessary for the program to work.");
usage();
System.exit(1);
}
/* Exit the program if the username is unknown or the password is wrong */
AccountUtil.loadAccounts();
if(!AccountUtil.isTheRightPassword(username, password))
if(!login())
{
System.out.println("The [username] or [password] is wrong.");
System.out.println("Unknown account.");
usage();
System.exit(1);
}
/* Show the informations before the start of the server */
/* showInfos(); */
/* Connect and login the client to the ftp server */
client = new FTPClient();
client.connect(ftpServerAddress, ftpServerPort);
if(!client.login(username, password))
{
System.out.println("The login has not succeed.");
System.exit(1);
}
/* Start the server */
final HttpServer server = startServer();
// System.out.println(String.format("Jersey app started with WADL available at "
// + "%sapplication.wadl\nHit enter to stop it...", uri));
//
// System.in.read();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", uri));
System.in.read();
/* Wait a word from the user to then shutdown the server */
waitWord();
// waitWord();
server.shutdownNow();
}
......
......@@ -2,7 +2,6 @@ package flopbox;
import flopbox.account.AccountUtil;
import flopbox.command.*;
import java.net.ServerSocket;
......@@ -45,6 +44,25 @@ public class MyResource
/**
* Connect the client to a ftp server.
*
* @param client The FTP client.
* @param address The address of the ftp server.
* @param port The port of the ftp server.
*
* @return How the command went.
*/
@GET
@Path("connect:{address}:{port}")
@Produces(MediaType.TEXT_PLAIN)
public String connect(FTPClient client, @PathParam("address") String address, @PathParam("port") int port)
{
return CONNECT.execute(client, address, port);
}
/**
* Change the working directory.
*
......@@ -112,11 +130,7 @@ public class MyResource
@Produces(MediaType.TEXT_PLAIN)
public String login(FTPClient client, @PathParam("username") String username, @PathParam("password") String password)
{
if(AccountUtil.getAccounts().containsKey(username))
if(AccountUtil.isTheRightPassword(username, password))
return LOGIN.execute(client, username, password);
return "The login has not succeed.";
}
......
package flopbox;
public class UriUtil
{
public static final int BASE_PORT = 2121;
/**
* Tell if a port is between 1024 and 65535.
*
* @param port The port.
*
* @return If the port is between 1024 and 65535.
*/
public static boolean isPortValid(int port)
{
if(Math.pow(2, 10) > port || port >= Math.pow(2, 16))
return false;
return true;
}
/**
* Set the URI with the [flopbox port] argument given to Main if valid or set the URI with port 8080 if not.
*
* @param arg The [flopbox port] argument given to Main.
*
* @return The URI with the [flopbox port] argument given to Main if valid or set the URI with port 8080 if not.
*/
public static String setUri(String arg)
{
int port;
try
{
port = Integer.parseInt(arg);
}
catch(NumberFormatException e)
{
port = BASE_PORT;
}
if(!isPortValid(port))
port = BASE_PORT;
return "http://localhost:" + port + "/myapp/";
}
}
package flopbox.command;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.commons.net.ftp.FTPClient;
import flopbox.Main;
import flopbox.server.FtpServerUtil;
public class CONNECT
{
private static final String NAME = "CONNECT";
/**
* Connect the client to a ftp server.
*
* @param client The FTP client.
* @param address The address of the ftp server.
* @param port The port of the ftp server.
*
* @return How the command went.
*/
public static String execute(FTPClient client, String address, int port)
{
String response;
try
{
if(client.isConnected())
client.disconnect();
if(!FtpServerUtil.isAddressValid(address))
if(Main.getAliases().containsKey(address))
address = Main.getAliases().get(address);
if(!FtpServerUtil.isFtpServerPortValid(port))
response = "The port is wrong.";
else
{
client.connect(address, port);
response = "Connected.";
}
}
catch(UnknownHostException e)
{
response = "The address could not be resolved.";
}
catch(IOException e)
{
response = "The command \"" + NAME + "\" failed.";
}
return response;
}
}
package flopbox.command;
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
......@@ -28,7 +30,9 @@ public class LOGIN
try
{
if(client.login(username, password))
{
response = "The login has succeed.";
}
else
response = "The login has not succeed.";
......
......@@ -3,14 +3,11 @@ package flopbox.command;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import flopbox.Main;
public class PORT
......@@ -37,7 +34,7 @@ public class PORT
{
activeConnection = new ServerSocket(0);
int commandResponse = client.port(InetAddress.getByName(Main.getFtpServerAddress()), activeConnection.getLocalPort());
int commandResponse = client.port(client.getRemoteAddress(), activeConnection.getLocalPort());
if(FTPReply.isPositiveCompletion(commandResponse))
response = "The client entered in active mode.";
......
......@@ -6,9 +6,10 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import flopbox.Main;
public class AliasUtil
......@@ -16,20 +17,6 @@ public class AliasUtil
private static File aliasesTxt = new File("aliases.txt");
private static char separator = ' ';
private static Map<String, String> aliases = new HashMap<String, String>();
/**
* Let the other classes to access in read the aliases.
*
* @return The pair alias and server of the aliases.
*/
public static Map<String, String> getAliases()
{
return aliases;
}
/**
......@@ -37,6 +24,8 @@ public class AliasUtil
*/
public static void loadAliases()
{
Map<String, String> aliases = Main.getAliases();
try
{
BufferedReader reader = new BufferedReader(new FileReader(aliasesTxt));
......
......@@ -9,10 +9,6 @@ import java.net.UnknownHostException;
public class FtpServerUtil
{
public static final int BASE_PORT = 8080;
/**
* Tell if an address is resolvable.
*
......@@ -20,7 +16,7 @@ public class FtpServerUtil
*
* @return If an address is resolvable.
*/
public static boolean isFtpServerAddressValid(String ftpServer)
public static boolean isAddressValid(String ftpServer)
{
try
{
......@@ -38,38 +34,6 @@ public class FtpServerUtil
/**
* Set the address with the [ftp server address] argument given to Main if valid or set the address to an empty string if not.
*
* @param arg The [ftp server address] argument given to Main.
*
* @return The address with the [ftp server address] argument given to Main if valid or set the address to an empty string if not.
*/
public static String setFtpServerAddress(String arg)
{
String address = arg;
if(!isFtpServerAddressValid(address))
{
AliasUtil.loadAliases();
if(AliasUtil.getAliases().containsKey(address))
{
address = AliasUtil.getAliases().get(address);
if(!isFtpServerAddressValid(address))
address = "";
}
else
address = "";
}
return address;
}
/**
* Tell if a port is between 1 and 65535.
*
......@@ -84,33 +48,4 @@ public class FtpServerUtil
return true;
}
/**
* Set the port with the [ftp server port] argument given to Main if valid or set the port to 21 if not.
*
* @param arg The [ftp server port] argument given to Main.
*
* @return The port with the [ftp server port] argument given to Main if valid or set the port to 21 if not.
*/
public static int setFtpServerPort(String arg)
{
int port;
try
{
port = Integer.parseInt(arg);
}
catch(NumberFormatException e)
{
port = BASE_PORT;
}
if(!isFtpServerPortValid(port))
port = BASE_PORT;
return port;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment