secure-files

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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 }