Refactor file upload/download with service layer and secure encryption
- Replaced direct encryption logic in FileController with FileService delegation - Added JWT-based username extraction in file operations - Updated FileMetadata entity to include `uploadedAt` field and removed redundant getters/setters - Refactored EncryptionUtil: - Switched to AES-CBC with PBKDF2 key derivation - Removed RSA-based encryption logic - Added salt and IV generation helpers - Changed JwtAuthenticationFilter to fetch user by username (not email) - Renamed method in FileMetadataRepository to match new parameter order FILE UPLOAD NOW WORKS! TESTED USING CURL.
This commit is contained in:
@@ -1,79 +1,70 @@
|
||||
package com.skycrate.backend.skycrateBackend.controller;
|
||||
|
||||
import com.skycrate.backend.skycrateBackend.entity.FileMetadata;
|
||||
import com.skycrate.backend.skycrateBackend.repository.FileMetadataRepository;
|
||||
import com.skycrate.backend.skycrateBackend.security.EncryptionService;
|
||||
import org.apache.hadoop.fs.FSDataInputStream;
|
||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import com.skycrate.backend.skycrateBackend.services.FileService;
|
||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.OutputStream;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/files")
|
||||
public class FileController {
|
||||
|
||||
@Autowired
|
||||
private FileSystem hdfs;
|
||||
private final FileService fileService;
|
||||
private final JwtService jwtService;
|
||||
|
||||
@Autowired
|
||||
private FileMetadataRepository metadataRepo;
|
||||
public FileController(FileService fileService, JwtService jwtService) {
|
||||
this.fileService = fileService;
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
public String upload(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("password") String password,
|
||||
Authentication auth) throws Exception {
|
||||
public ResponseEntity<String> uploadFile(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
try {
|
||||
String token = extractToken(request);
|
||||
String username = jwtService.extractUsername(token);
|
||||
|
||||
byte[] fileBytes = file.getBytes();
|
||||
byte[] salt = EncryptionService.generateSalt();
|
||||
byte[] iv = new byte[12];
|
||||
new SecureRandom().nextBytes(iv);
|
||||
SecretKey key = EncryptionService.deriveKey(password, salt);
|
||||
fileService.uploadEncryptedFile(username, password, file.getBytes(), file.getOriginalFilename());
|
||||
|
||||
byte[] encrypted = EncryptionService.encrypt(fileBytes, key, iv);
|
||||
String pathStr = "/user/" + auth.getName() + "/" + file.getOriginalFilename();
|
||||
Path hdfsPath = new Path(pathStr);
|
||||
|
||||
try (FSDataOutputStream out = hdfs.create(hdfsPath, true)) {
|
||||
out.write(encrypted);
|
||||
return ResponseEntity.ok("File uploaded and encrypted successfully.");
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body("File upload failed: " + e.getMessage());
|
||||
}
|
||||
|
||||
FileMetadata metadata = new FileMetadata();
|
||||
metadata.setUsername(auth.getName());
|
||||
metadata.setFilePath(pathStr);
|
||||
metadata.setSalt(salt);
|
||||
metadata.setIv(iv);
|
||||
metadataRepo.save(metadata);
|
||||
|
||||
return "File uploaded and encrypted successfully!";
|
||||
}
|
||||
|
||||
@GetMapping("/download")
|
||||
public void download(@RequestParam("path") String path,
|
||||
@RequestParam("password") String password,
|
||||
Authentication auth,
|
||||
OutputStream responseStream) throws Exception {
|
||||
@GetMapping("/download/{filename}")
|
||||
public ResponseEntity<?> downloadFile(
|
||||
@PathVariable String filename,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
try {
|
||||
String token = extractToken(request);
|
||||
String username = jwtService.extractUsername(token);
|
||||
|
||||
Optional<FileMetadata> optional = metadataRepo.findByFilePathAndUsername(path, auth.getName());
|
||||
if (optional.isEmpty()) {
|
||||
throw new SecurityException("You are not authorized to access this file.");
|
||||
byte[] decryptedData = fileService.downloadDecryptedFile(username, password, filename);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(decryptedData);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body("File download failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
FileMetadata metadata = optional.get();
|
||||
SecretKey key = EncryptionService.deriveKey(password, metadata.getSalt());
|
||||
|
||||
try (FSDataInputStream input = hdfs.open(new Path(path))) {
|
||||
byte[] encrypted = input.readAllBytes();
|
||||
byte[] decrypted = EncryptionService.decrypt(encrypted, key, metadata.getIv());
|
||||
responseStream.write(decrypted);
|
||||
private String extractToken(HttpServletRequest request) {
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
throw new RuntimeException("Missing or invalid Authorization header");
|
||||
}
|
||||
return authHeader.substring(7);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user