diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java index d616d50266a6c2a1f4501fba6281bd259785aa7e..8ac12404e109ff1a7c28a495a2750c3fe213d47c 100644 --- a/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java +++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/InputNodeDto.java @@ -1,5 +1,7 @@ package fr.miage23.filestore.api.dto; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.core.MediaType; import org.jboss.resteasy.annotations.providers.multipart.PartType; @@ -10,10 +12,13 @@ public class InputNodeDto { @FormParam("name") @PartType(MediaType.TEXT_PLAIN) - private String name = null; + @Pattern(regexp = "^[^*&%/]+$") + private String name; @FormParam("data") @PartType(MediaType.APPLICATION_OCTET_STREAM) private InputStream data = null; + @Size(max=2000000, message="content size is 2Mo max, for larger content use a multipart-form-data with data parameter") + private byte[] content; public InputNodeDto() { // Default constructor needed for JAX-RS @@ -35,5 +40,13 @@ public class InputNodeDto { this.data = data; } + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + } diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTNodeDto.java index ce8e8d8e0792dcb86bc56772686d3c2faf44ceb9..3ee39708caf59c335556e03f2e5159015d691f38 100644 --- a/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTNodeDto.java +++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/POSTNodeDto.java @@ -3,6 +3,7 @@ package fr.miage23.filestore.api.dto; import fr.miage23.filestore.TypeNode; public class POSTNodeDto { + private String id = null; private String name = null; private TypeNode type = null; diff --git a/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java index ea19e4283ed2fe05eecc3fa8c037dd192f1758c1..202cb7cddb41752a8cf8ca339f55727de0546baf 100644 --- a/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java +++ b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java @@ -79,22 +79,18 @@ public class NodesResource { @Produces(MediaType.APPLICATION_JSON) public Response content(@PathParam("id") final String id, @QueryParam("limit") @DefaultValue("10") int limit, @QueryParam("offset") @DefaultValue("0") int offset) throws NodeNotFoundException, NodeTypeException, ContentException { LOGGER.log(Level.INFO, "GET /api/nodes/" + id + "/content"); - try { - Node node = service.get(id); - if (node.getType().equals(TypeNode.TREE)) { - CollectionDto<Node> dto = new CollectionDto(limit, offset); - List<Node> nodes = service.list(node.getId()); - dto.setValues(nodes.stream().skip(offset).limit(limit).collect(Collectors.toList())); - dto.setSize(nodes.size()); - return Response.ok(dto).build(); - } else { - return Response.ok(service.getContent(id)) - .header("Content-Type", node.getMimetype()) - .header("Content-Length", node.getSize()) - .header("Content-Disposition", "attachment; filename=" + node.getName()).build(); - } - } catch (NodeNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Node not found.").build(); + Node node = service.get(id); + if (node.getType().equals(TypeNode.TREE)) { + CollectionDto<Node> dto = new CollectionDto(limit, offset); + List<Node> nodes = service.list(node.getId()); + dto.setValues(nodes.stream().skip(offset).limit(limit).collect(Collectors.toList())); + dto.setSize(nodes.size()); + return Response.ok(dto).build(); + } else { + return Response.ok(service.getContent(id)) + .header("Content-Type", node.getMimetype()) + .header("Content-Length", node.getSize()) + .header("Content-Disposition", "attachment; filename=" + node.getName()).build(); } } @@ -108,20 +104,16 @@ public class NodesResource { @GET @Path("{id}") @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) - public Response getNode(@PathParam("id") String id) { + public Response getNode(@PathParam("id") String id) throws NodeNotFoundException { LOGGER.log(Level.INFO, "GET /api/nodes/" + id); - try{ - Gson gson = new GsonBuilder() - .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) - .create(); - Node node = service.get(id); - return Response.ok(gson.toJson( - (new GETNodeDto(node.getType(), node.getId(), node.getParent(), node.getName(), node.getSize(), node.getCreation(), node.getModification())), - GETNodeDto.class), - MediaType.APPLICATION_JSON).build(); - } catch (NodeNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Node not found.").build(); - } + Gson gson = new GsonBuilder() + .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) + .create(); + Node node = service.get(id); + return Response.ok(gson.toJson( + (new GETNodeDto(node.getType(), node.getId(), node.getParent(), node.getName(), node.getSize(), node.getCreation(), node.getModification())), + GETNodeDto.class), + MediaType.APPLICATION_JSON).build(); } /** @@ -135,33 +127,23 @@ public class NodesResource { @POST @Path("{id}") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - public Response createNode(@PathParam("id") String id, @FormParam("name") String name, @Context UriInfo info) { + public Response createNode(@PathParam("id") String id, @FormParam("name") String name, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException { LOGGER.log(Level.INFO, "POST /api/nodes/" + id); - try { - String newid; - if (name != null) { - newid = service.add(id, name); - } else { - throw new IllegalArgumentException("A name must be provided"); - } - Gson gson = new GsonBuilder() - .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) - .create(); - Node node = service.get(newid); - - return Response.ok(gson.toJson( - (new POSTNodeDto(node.getId(), node.getName(), node.getType())), - POSTNodeDto.class), - MediaType.APPLICATION_JSON).build(); - } catch (IllegalArgumentException e) { - // Transform the IllegalArgumentException into a 400 Bad Request response - return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); - } catch (NodeNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Node not found.").build(); - } catch (NodeTypeException | NodeAlreadyExistsException e) { - // Handle other exceptions as needed, possibly transforming them into different HTTP responses - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("An unexpected error occurred.").build(); + String newid; + if (name != null) { + newid = service.add(id, name); + } else { + throw new IllegalArgumentException("A name must be provided"); } + Gson gson = new GsonBuilder() + .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) + .create(); + Node node = service.get(newid); + + return Response.ok(gson.toJson( + (new POSTNodeDto(node.getId(), node.getName(), node.getType())), + POSTNodeDto.class), + MediaType.APPLICATION_JSON).build(); } /** @@ -176,37 +158,27 @@ public class NodesResource { @Path("{id}") @Produces(MediaType.TEXT_HTML) @Consumes(MediaType.MULTIPART_FORM_DATA) - public Response createView(@PathParam("id") final String id, @MultipartForm @Valid InputNodeDto dto, @Context UriInfo info) { + public Response createView(@PathParam("id") final String id, @MultipartForm @Valid InputNodeDto dto, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException { LOGGER.log(Level.INFO, "POST /api/nodes/" + id + " (html)"); - try { - String newid; - if (dto.getName() != null && dto.getData() != null){ - newid = service.add(id, dto.getName(), dto.getData()); - } else if (dto.getName() != null){ - newid = service.add(id, dto.getName()); - } else { - throw new IllegalArgumentException("A name must be provided"); - } - Gson gson = new GsonBuilder() - .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) - .create(); - Node node = service.get(newid); - return Response.ok(gson.toJson( - (new POSTNodeDto(node.getId(), node.getName(), node.getType())), - POSTNodeDto.class), - MediaType.APPLICATION_JSON).build(); - } catch (IllegalArgumentException e) { - // Transform the IllegalArgumentException into a 400 Bad Request response - return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); - } catch (NodeNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Node not found.").build(); - } catch (NodeTypeException | NodeAlreadyExistsException | ContentException e) { - // Handle other exceptions as needed, possibly transforming them into different HTTP responses - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("An unexpected error occurred.").build(); + String newid; + if (dto.getName() != null && dto.getData() != null){ + newid = service.add(id, dto.getName(), dto.getData()); + } else if (dto.getName() != null){ + newid = service.add(id, dto.getName()); + } else { + throw new IllegalArgumentException("A name must be provided"); } + Gson gson = new GsonBuilder() + .registerTypeAdapter(TypeNode.class, new EnumTypeAdapter()) + .create(); + Node node = service.get(newid); + return Response.ok(gson.toJson( + (new POSTNodeDto(node.getId(), node.getName(), node.getType())), + POSTNodeDto.class), + MediaType.APPLICATION_JSON).build(); } - // Classe EnumTypeAdapter pour la gestion de la sérialisation/désérialisation de l'énumération Node.Type + // Classe EnumTypeAdapter pour la gestion de la sérialisation/désérialisation de l'énumération TypeNode private static class EnumTypeAdapter extends TypeAdapter<TypeNode> { @Override public void write(JsonWriter out, TypeNode value) throws IOException { diff --git a/TD4/src/main/java/fr/miage23/filestore/api/validation/Filename.java b/TD4/src/main/java/fr/miage23/filestore/api/validation/Filename.java new file mode 100644 index 0000000000000000000000000000000000000000..c11e79e7c18c2b66681699fce14e13191560134a --- /dev/null +++ b/TD4/src/main/java/fr/miage23/filestore/api/validation/Filename.java @@ -0,0 +1,21 @@ +package fr.miage23.filestore.api.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import jakarta.validation.constraints.Pattern; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Constraint(validatedBy={}) +@Retention(RetentionPolicy.RUNTIME) +@Pattern(regexp=ValidationPattern.FILE_PATTERN) +public @interface Filename { + String message() default "{invalid.filename_FR}"; + Class<?>[] groups() default {}; + Class<? extends Payload>[] payload() default {}; +} + diff --git a/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java b/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java new file mode 100644 index 0000000000000000000000000000000000000000..96cbd79a07686e82f050c796455a5031068e0466 --- /dev/null +++ b/TD4/src/main/java/fr/miage23/filestore/api/validation/ValidationPattern.java @@ -0,0 +1,6 @@ +package fr.miage23.filestore.api.validation; + +public class ValidationPattern { + public static final String FILE_PATTERN = "^[^*&%/]+$"; +} +