diff --git a/README.md b/README.md index b84cddfbd8492e887f0cb28d2708752a430fde7c..2494c77f425046941ebc593d3e3171fb592eda59 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,10 @@ mvn clean package java -jar target/FlopBox.jar ``` +`python3 serveur_ftp.py` anonymous/anonymous ou user/password + +ou ftp.ubuntu.com + ### Exécuter les tests Pour exécuter uniquement les tests il faut lancer la commande suivante : @@ -61,6 +65,7 @@ Puis ouvrir le fichier `target/site/apidocs/index.html` ## Fonctionnalités +`python3 serveur_ftp.py` anonymous/anonymous ou user/password **Note < 10 si le code fourni ne compile pas et ne peut pas être exécuté en suivant les instructions:** @@ -118,4 +123,13 @@ fabio.vandewaeter.etu@b10p21:~/M1/SR2/TEMPO$ curl -X GET -H "Content-Type: appli **Note comprise entre 14 et 15 si—en plus—le proxy FlopBox, permet de créer, supprimer, renommer une ressource directement sur l'un des serveurs FTP gérés (fichier ou répertoire):** + +```shell +> curl -X DELETE -H "Authorization: Bearer valid-token-1" -H "X-FTP-User: user" -H "X-FTP-Pass: password" http://localhost:8080/ftps/mon-ftp/dir +``` + +```shell +> curl -X POST -H "Authorization: Bearer valid-token-1" -H "X-FTP-User: user" -H "X-FTP-Pass: password" -H "Content-Type: text/plain" -d "nouveau_chemin" http://localhost:8080/ftps/mon-ftp/test/rename +``` + **Note comprise entre 15 et 16 si—en plus—le proxy FlopBox, permet de chercher des fichiers/répertoires stockés dans plusieurs serveurs FTP (le proxy retourne la liste des URLs pour chaque fichier trouvé):** diff --git a/dossier_serveur_ftp/.gitkeep b/dossier_serveur_ftp/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/serveur_ftp.py b/serveur_ftp.py new file mode 100644 index 0000000000000000000000000000000000000000..fd6eeaea7a91e8033963f088948912a7522852c5 --- /dev/null +++ b/serveur_ftp.py @@ -0,0 +1,21 @@ +from pyftpdlib.authorizers import DummyAuthorizer +from pyftpdlib.handlers import FTPHandler +from pyftpdlib.servers import FTPServer + +# Créer un authorizer +authorizer = DummyAuthorizer() + +# Ajouter un utilisateur anonyme (lecture seule) +authorizer.add_anonymous("dossier_serveur_ftp", perm="elr") + +# Ajouter un utilisateur personnalisé avec des permissions d'écriture +authorizer.add_user("user", "password", + "dossier_serveur_ftp", perm="elradfmw") + +# Configurer le handler +handler = FTPHandler +handler.authorizer = authorizer + +# Démarrer le serveur FTP +server = FTPServer(("127.0.0.1", 2121), handler) +server.serve_forever() diff --git a/src/main/java/fil/sr2/flopbox/FTPResource.java b/src/main/java/fil/sr2/flopbox/FTPResource.java index 694a01bd0bbdf42b12e334c64dff2bfb61e35d4b..bfa68832520680b05312a37fa4c268b91a2e7399 100644 --- a/src/main/java/fil/sr2/flopbox/FTPResource.java +++ b/src/main/java/fil/sr2/flopbox/FTPResource.java @@ -3,10 +3,8 @@ package fil.sr2.flopbox; import jakarta.ws.rs.*; import jakarta.ws.rs.core.*; -import java.io.Closeable; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.SocketException; import java.net.URI; import java.util.List; @@ -120,8 +118,7 @@ public class FTPResource { System.out.println("addFTPServer()"); boolean created = FTPServerRepository.getInstance().addServer(config); if (!created) { - return Response.status(Response.Status.CONFLICT) - .entity("Alias déjà utilisé").build(); + return Response.status(Response.Status.CONFLICT).entity("Alias déjà utilisé").build(); } UriBuilder builder = uriInfo.getAbsolutePathBuilder(); builder.path(config.getAlias()); @@ -145,34 +142,6 @@ public class FTPResource { return updated ? Response.ok(newConfig).build() : Response.status(Response.Status.NOT_FOUND).build(); } - // Classe utilitaire pour gérer le flux et fermer les ressources - private static class InputStreamResource implements StreamingOutput { - private final InputStream inputStream; - private final FTPClient ftpClient; - - public InputStreamResource(InputStream inputStream, FTPClient ftpClient) { - this.inputStream = inputStream; - this.ftpClient = ftpClient; - } - - @Override - public void write(OutputStream output) throws IOException, WebApplicationException { - try (inputStream) { - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - output.write(buffer, 0, bytesRead); - } - } finally { - if (ftpClient.isConnected()) { - ftpClient.completePendingCommand(); - ftpClient.logout(); - ftpClient.disconnect(); - } - } - } - } - @PUT @Path("/{alias}/{path: .+}") @Consumes(MediaType.APPLICATION_OCTET_STREAM) @@ -233,22 +202,94 @@ public class FTPResource { } } + // delete the file or the content of a folder recursively @DELETE @Path("/{alias}/{path: .+}") - public Response deleteDirectory( + public Response deleteResource( @PathParam("alias") String alias, @PathParam("path") String path, @HeaderParam("X-FTP-User") String user, - @HeaderParam("X-FTP-Pass") String pass) throws SocketException, IOException { + @HeaderParam("X-FTP-Pass") String pass) { - System.out.println("deleteDirectory()"); FTPClient ftp = new FTPClient(); try { FTPServerConfig config = FTPServerRepository.getInstance().getServer(alias); ftp.connect(config.getHost(), config.getPort()); ftp.login(user, pass); - return ftp.removeDirectory(path) ? Response.noContent().build() - : Response.status(Response.Status.NOT_FOUND).build(); + + // Appel à la méthode récursive pour supprimer la ressource + boolean deleted = deleteRecursive(ftp, path); + + return deleted + ? Response.noContent().build() + : Response.status(Response.Status.NOT_FOUND).entity("Ressource non trouvée").build(); + + } catch (IOException e) { + return Response.serverError().entity("Erreur FTP : " + e.getMessage()).build(); + } finally { + try { + if (ftp.isConnected()) { + ftp.logout(); + ftp.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Méthode récursive pour supprimer un répertoire et son contenu. + */ + private boolean deleteRecursive(FTPClient ftp, String path) throws IOException { + // Vérifie si le chemin est un répertoire + FTPFile[] files = ftp.listFiles(path); + if (files != null && files.length > 0) { + // Parcours des fichiers et sous-répertoires + for (FTPFile file : files) { + String fullPath = path + "/" + file.getName(); + if (file.isDirectory()) { + // Suppression récursive des sous-répertoires + if (!deleteRecursive(ftp, fullPath)) { + return false; + } + } else { + // Suppression des fichiers + if (!ftp.deleteFile(fullPath)) { + return false; + } + } + } + } + + // Suppression du répertoire lui-même + return ftp.removeDirectory(path); + } + + @POST + @Path("/{alias}/{path: .+}/rename") + @Consumes(MediaType.TEXT_PLAIN) + public Response renameResource( + @PathParam("alias") String alias, + @PathParam("path") String oldPath, + @HeaderParam("X-FTP-User") String user, + @HeaderParam("X-FTP-Pass") String pass, + String newPath) { + + System.out.println("renameResource()"); + FTPClient ftp = new FTPClient(); + try { + FTPServerConfig config = FTPServerRepository.getInstance().getServer(alias); + ftp.connect(config.getHost(), config.getPort()); + ftp.login(user, pass); + + System.out.print(oldPath + " " + newPath); + boolean success = ftp.rename(oldPath, newPath); + return success + ? Response.ok().build() + : Response.status(Response.Status.BAD_REQUEST).entity("Échec du renommage").build(); + } catch (IOException e) { + return Response.serverError().entity("Erreur FTP : " + e.getMessage()).build(); } finally { try { if (ftp.isConnected()) {