DownloadController.java (3218B)
1 package xyz.kebigon.securefiles; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.nio.file.Files; 6 import java.nio.file.Path; 7 import java.nio.file.Paths; 8 import java.sql.SQLException; 9 import java.util.HashMap; 10 import java.util.Map; 11 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 15 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Value; 17 import org.springframework.http.HttpStatus; 18 import org.springframework.stereotype.Controller; 19 import org.springframework.util.StringUtils; 20 import org.springframework.web.bind.annotation.GetMapping; 21 import org.springframework.web.bind.annotation.PathVariable; 22 import org.springframework.web.bind.annotation.RequestMapping; 23 import org.springframework.web.server.ResponseStatusException; 24 import org.springframework.web.servlet.ModelAndView; 25 26 import lombok.extern.slf4j.Slf4j; 27 import xyz.kebigon.securefiles.db.DroppedFile; 28 import xyz.kebigon.securefiles.db.DroppedFilesRepository; 29 30 @Slf4j 31 @Controller 32 @RequestMapping("download") 33 public class DownloadController 34 { 35 @Autowired 36 private DroppedFilesRepository repository; 37 @Value("${filedrop.directory}") 38 private File directory; 39 40 @GetMapping("/{id}") 41 public ModelAndView downloadPage(final HttpServletResponse response, @PathVariable final String id) throws SQLException, IOException 42 { 43 final DroppedFile droppedFile = repository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 44 final Path file = Paths.get(directory.getAbsolutePath(), droppedFile.getId()); 45 46 if (droppedFile.isDownloaded() || !Files.exists(file)) 47 throw new ResponseStatusException(HttpStatus.NOT_FOUND); 48 49 final Map<String, Object> model = new HashMap<String, Object>(); 50 model.put("file", droppedFile); 51 return new ModelAndView("download", model); 52 } 53 54 @GetMapping("/{id}/confirm") 55 public void download(@PathVariable final String id, final HttpServletRequest request, final HttpServletResponse response) throws IOException, SQLException 56 { 57 final DroppedFile droppedFile = repository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 58 final Path file = Paths.get(directory.getAbsolutePath(), droppedFile.getId()); 59 60 if (droppedFile.isDownloaded() || !Files.exists(file)) 61 throw new ResponseStatusException(HttpStatus.NOT_FOUND); 62 63 response.setContentType(droppedFile.getContentType()); 64 response.addHeader("Content-Disposition", "attachment; filename=" + droppedFile.getName()); 65 66 Files.copy(file, response.getOutputStream()); 67 response.getOutputStream().flush(); 68 69 // TODO: secure delete file 70 log.info("Deleting file {}...", file); 71 Files.delete(file); 72 73 droppedFile.setDownloaded(true); 74 droppedFile.setRemoteAddr(getRemoteAddr(request)); 75 repository.save(droppedFile); 76 } 77 78 private static String getRemoteAddr(final HttpServletRequest request) 79 { 80 final String forwardedFor = request.getHeader("X-Forwarded-For"); 81 if (StringUtils.hasText(forwardedFor)) 82 { 83 final int commaIdx = forwardedFor.indexOf(','); 84 return (commaIdx != -1 ? forwardedFor.substring(0, commaIdx) : forwardedFor).trim(); 85 } 86 87 return request.getRemoteAddr(); 88 } 89 }