diff --git a/src/main/java/de/w665/sharepulse/db/repo/FileUploadRepository.java b/src/main/java/de/w665/sharepulse/db/repo/FileUploadRepository.java index c1e69af..3298018 100644 --- a/src/main/java/de/w665/sharepulse/db/repo/FileUploadRepository.java +++ b/src/main/java/de/w665/sharepulse/db/repo/FileUploadRepository.java @@ -4,7 +4,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.rethinkdb.RethinkDB; -import com.rethinkdb.gen.ast.Filter; import com.rethinkdb.net.Connection; import de.w665.sharepulse.db.RethinkDBConnector; import de.w665.sharepulse.db.RethinkDBService; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.lang.reflect.Type; -import java.util.Date; import java.util.Map; @Repository diff --git a/src/main/java/de/w665/sharepulse/exception/NoDownloadPermissionException.java b/src/main/java/de/w665/sharepulse/exception/NoDownloadPermissionException.java new file mode 100644 index 0000000..d2e0645 --- /dev/null +++ b/src/main/java/de/w665/sharepulse/exception/NoDownloadPermissionException.java @@ -0,0 +1,7 @@ +package de.w665.sharepulse.exception; + +public class NoDownloadPermissionException extends RuntimeException { + public NoDownloadPermissionException(String message) { + super(message); + } +} diff --git a/src/main/java/de/w665/sharepulse/model/FileUpload.java b/src/main/java/de/w665/sharepulse/model/FileUpload.java index 9055971..b6ef691 100644 --- a/src/main/java/de/w665/sharepulse/model/FileUpload.java +++ b/src/main/java/de/w665/sharepulse/model/FileUpload.java @@ -1,6 +1,7 @@ package de.w665.sharepulse.model; import com.fasterxml.jackson.annotation.JsonFormat; +import com.google.gson.annotations.SerializedName; import lombok.*; import java.util.Date; @@ -12,6 +13,7 @@ import java.util.Date; @NoArgsConstructor @ToString public class FileUpload { + private String id; private String fileId; private String fileName; private long fileSize; @@ -21,4 +23,6 @@ public class FileUpload { private String uploadedByIpAddress; private long downloadCount; private String fileDescription; + private boolean passwordProtected; + private String downloadPassword; } diff --git a/src/main/java/de/w665/sharepulse/rest/mappings/Download.java b/src/main/java/de/w665/sharepulse/rest/mappings/Download.java new file mode 100644 index 0000000..f9d776b --- /dev/null +++ b/src/main/java/de/w665/sharepulse/rest/mappings/Download.java @@ -0,0 +1,64 @@ +package de.w665.sharepulse.rest.mappings; + +import de.w665.sharepulse.model.FileUpload; +import de.w665.sharepulse.rest.ApiRestController; +import de.w665.sharepulse.service.FileSecurityService; +import de.w665.sharepulse.service.FileService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +@Slf4j +@RestController +public class Download extends ApiRestController { + + private final FileService fileService; + private final FileSecurityService fileSecurityService; + + @Autowired + public Download(FileService fileService, FileSecurityService fileSecurityService) { + this.fileService = fileService; + this.fileSecurityService = fileSecurityService; + } + + @GetMapping("/download") + public ResponseEntity download(@RequestParam String fileId, + @RequestParam(value = "password", required = false) String password) throws IOException { + + + FileUpload fileUpload = fileService.getFileUploadByFileId(fileId); + + fileSecurityService.verifyDownloadPermission(fileUpload, password); + + // TODO: Update download count in database (single download will not work without this) + + File file = fileService.getFileById(fileId); + + + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"edmbass.flac\""); + //headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getName() + "\""); + headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); + headers.add(HttpHeaders.PRAGMA, "no-cache"); + headers.add(HttpHeaders.EXPIRES, "0"); + + InputStreamResource resource = new InputStreamResource(new FileInputStream(file)); + + return ResponseEntity.ok() + .headers(headers) + .contentLength(file.length()) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(resource); + } +} diff --git a/src/main/java/de/w665/sharepulse/rest/mappings/Upload.java b/src/main/java/de/w665/sharepulse/rest/mappings/Upload.java index 23fc4fb..ee14611 100644 --- a/src/main/java/de/w665/sharepulse/rest/mappings/Upload.java +++ b/src/main/java/de/w665/sharepulse/rest/mappings/Upload.java @@ -26,13 +26,16 @@ public class Upload extends ApiRestController { // Currently testing @PostMapping("/upload") - public ResponseEntity getUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request) { + public ResponseEntity getUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request, + @RequestParam(value = "password", required = false) String password, + @RequestParam(value = "singleDownload", defaultValue = "false") boolean singleDownload, + @RequestParam(value = "fileDescription", required = false) String fileDescription) { if (file.isEmpty()) { log.debug("User tried to upload an empty file. IP: " + request.getRemoteAddr()); return new ResponseEntity<>("Please select a file to upload.", HttpStatus.NOT_ACCEPTABLE); } - String fileId = fileService.processUploadedFile(file, request.getRemoteAddr()); + String fileId = fileService.processUploadedFile(file, request.getRemoteAddr(), password, singleDownload, fileDescription); log.debug("User uploaded file " + file.getOriginalFilename() + " from IP " + request.getRemoteAddr() + " successfully."); return new ResponseEntity<>("File " + file.getOriginalFilename() + " uploaded successfully! ID(" + fileId + ")", HttpStatus.OK); } diff --git a/src/main/java/de/w665/sharepulse/service/FileSecurityService.java b/src/main/java/de/w665/sharepulse/service/FileSecurityService.java new file mode 100644 index 0000000..f55903e --- /dev/null +++ b/src/main/java/de/w665/sharepulse/service/FileSecurityService.java @@ -0,0 +1,37 @@ +package de.w665.sharepulse.service; + +import de.w665.sharepulse.exception.NoDownloadPermissionException; +import de.w665.sharepulse.model.FileUpload; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.File; + +@Slf4j +@Service +public class FileSecurityService { + + public boolean verifyDownloadPermission(FileUpload file, String password) throws NoDownloadPermissionException { + + + if (!file.isPasswordProtected() && !file.isSingleDownload()) { + return true; + } + + if (file.isSingleDownload()) { + if(file.getDownloadCount() > 0) { + throw new NoDownloadPermissionException("File has already been downloaded."); + } + if(!file.isPasswordProtected()) { + return true; + } + } + + if(file.getDownloadPassword().equals(password)) { + return true; + } + + throw new NoDownloadPermissionException("Password protected file can only be downloaded with correct password."); + + } +} diff --git a/src/main/java/de/w665/sharepulse/service/FileService.java b/src/main/java/de/w665/sharepulse/service/FileService.java index 1a008a8..262a329 100644 --- a/src/main/java/de/w665/sharepulse/service/FileService.java +++ b/src/main/java/de/w665/sharepulse/service/FileService.java @@ -53,7 +53,7 @@ public class FileService { } } - public String processUploadedFile(MultipartFile file, String uploaderIp) { + public String processUploadedFile(MultipartFile file, String uploaderIp, String password, boolean singleDownload, String fileDescription) { String fileId = fileIdService.generateNewUniqueId(); @@ -61,13 +61,17 @@ public class FileService { .fileId(fileId) .fileName(file.getOriginalFilename()) .fileSize(file.getSize()) - .singleDownload(false) + .singleDownload(singleDownload) .uploadDate(new Date()) .uploadedByIpAddress(uploaderIp) .downloadCount(0) - .fileDescription("fileDescription") + .fileDescription(fileDescription) + .passwordProtected(password != null && !password.isEmpty()) + .downloadPassword(password) .build(); + System.out.println(fileUpload.toString()); + fileUploadRepository.insertFileUpload(fileUpload); @@ -87,8 +91,14 @@ public class FileService { return new File(getTempDirPath() + File.separator + fileId); } + public FileUpload getFileUploadByFileId(String fileId) { + return fileUploadRepository.retrieveFileUploadByFileId(fileId); + } + private String getTempDirPath() { return System.getProperty("user.dir") + tempDirPath; } + + }