/** * Last Updated: 22/04/20221 */ package com.example.controller; import com.example.payload.UploadFileResponse; import com.example.service.FileStorageService; import com.example.usbtoken.Notary; import com.example.usbtoken.UsbToken; import com.example.usbtoken.UsbTokenMSCAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; 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.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.itextpdf.text.Image; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.security.ExternalDigest; import com.itextpdf.text.pdf.security.ExternalSignature; import com.itextpdf.text.pdf.security.MakeSignature; import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Security; import java.security.cert.Certificate; import java.util.UUID; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * * @author Tuoi-cm File Controller * @version 1.0 */ @CrossOrigin(maxAge = 3600) @RestController @RequestMapping(value = "/api/file") public class FileController { private static final Logger logger = LoggerFactory.getLogger(FileController.class); @Autowired private FileStorageService fileStorageService; /** * Upload file and Sign PDF File * * @param file * @param llx * @param ury * @param lly * @param urx * @return UploadFileResponse */ @PostMapping("/uploadFile") public UploadFileResponse uploadFile( @RequestParam("file") MultipartFile file, @RequestParam("llx") int llx, @RequestParam("lly") int lly, @RequestParam("urx") int urx, @RequestParam("ury") int ury, @RequestParam("checkUsbToken") String checkUsbToken, @RequestParam("indexAlias") int indexAlias, @RequestParam("mscapi") String mscapi) throws JsonMappingException, JsonProcessingException, IOException { UUID uuid = UUID.randomUUID(); String uuidAsString = uuid.toString(); String fileName = this.fileStorageService.storeFile(file, uuidAsString); //Location Save PDF File Signed. String fNameSign = "D:\\temp\\" + "Signed_" + fileName; String subStringFNameString = subStringFNameString = fNameSign.substring(8); if (file.getContentType().equals("application/pdf")) { if (checkUsbToken.equals("n")) { signPDF(convertMultiPartToFile(file), fNameSign, llx, lly, urx, ury); } else { if (mscapi.equals("mscapi")) { UsbTokenMSCAPI mSCAPI = new UsbTokenMSCAPI("C:\\Windows\\System32\\eps2003csp11.dll"); byte[] signValue = mSCAPI.signText("text to sign...", "12345678"); boolean valid = new Notary().verifySignature("text to sign...".getBytes(), signValue, mSCAPI.publicKey()); System.out.println("is valid?: " + valid); if (valid) { mSCAPI.multipleSignPdfUsbTokenMSCAPI(convertMultiPartToFile(file), fNameSign, llx, lly, urx, ury, checkUsbToken, indexAlias); } else { return new UploadFileResponse(fileName, file.getContentType(), file.getSize(), fileName + " ERROR", 1); } } else { UsbToken usbToken = new UsbToken("C:\\Windows\\System32\\eps2003csp11.dll"); byte[] signValue = usbToken.signText("text to sign...", "12345678"); boolean valid = new Notary().verifySignature("text to sign...".getBytes(), signValue, usbToken.publicKey("12345678")); System.out.println("is valid?: " + valid); if (valid) { usbToken.multipleSignPdfUsbToken(convertMultiPartToFile(file), fNameSign, "12345678", llx, lly, urx, ury, checkUsbToken, indexAlias); } else { return new UploadFileResponse(fileName, file.getContentType(), file.getSize(), fileName + " ERROR", 1); } } } } else { return new UploadFileResponse(fileName, file.getContentType(), file.getSize(), fileName + " is not a PDF File", 1); } String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath() .path("/api/file/downloadFile/") .path(subStringFNameString) .toUriString(); return new UploadFileResponse(subStringFNameString, fileDownloadUri, file.getContentType(), file.getSize(), "Upload File Successfully", 0); } // @PostMapping("/uploadMultipleFiles") // public List uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) { // return Arrays.asList(files) // .stream() // .map(file -> uploadFile(file)) // .collect(Collectors.toList()); // } /** * Download file and Sign PDF File * * @param fileName, request * @return ResponseEntity */ @GetMapping("/downloadFile/{fileName:.+}") public ResponseEntity downloadFile(@PathVariable String fileName, HttpServletRequest request) { // Load file as Resource Resource resource = fileStorageService.loadFileAsResource(fileName); // Try to determine file's content type String contentType = null; try { contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath()); } catch (IOException ex) { logger.info("Could not determine file type."); } // Fallback to the default content type if type could not be determined if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } /** * Sign PDF File * * @param file, fNameSign */ public static void signPDF(File file, String fNameSign, int llx, int lly, int urx, int ury) { CryptoStandard subfilter = CryptoStandard.CMS; //Field Name PDF String fiedName = ""; // Processing PDF File Here System.out.println("START"); //The access path to pkcs12 key String fileP12 = "D:\\ProjectKyPDF\\vudp.p12"; //Passhare String passFileP12 = "12345678"; try { //Create KeyStore KeyStore ks = KeyStore.getInstance("pkcs12"); //Download the p12 certificate in the store ks.load(new FileInputStream(fileP12), passFileP12.toCharArray()); String alias = (String) ks.aliases().nextElement(); //Get Private Key PrivateKey pk = (PrivateKey) ks.getKey(alias, passFileP12.toCharArray()); //Certificate chain Certificate[] chain = ks.getCertificateChain(alias); //Check PDF File Sign com.itextpdf.text.pdf.PdfReader pdfReader = new com.itextpdf.text.pdf.PdfReader(file.getAbsolutePath()); File outputFile = new File(fNameSign); //Read the source documentation // com.itextpdf.text.pdf.PdfReader pdfReader = new com.itextpdf.text.pdf.PdfReader(file.getAbsolutePath()); // File outputFile = new File(fNameSign); //Create signature seal PdfStamper pdfStamper; pdfStamper = PdfStamper.createSignature(pdfReader, null, '\0', outputFile, true); //** com.itextpdf.text.pdf.PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance(); sap.setReason("Test SignPDF"); sap.setLocation("VN"); sap.setCertificationLevel(com.itextpdf.text.pdf.PdfSignatureAppearance.NOT_CERTIFIED); //The position of the stamp on the page (lower left of page 1) com.itextpdf.text.Rectangle rectangle = new com.itextpdf.text.Rectangle(llx, lly, urx, ury); UUID uuid = UUID.randomUUID(); String uuidAsString = uuid.toString(); fiedName = file.getName().equals(fNameSign.substring(file.getName().length())) ? "EDIT_" + uuidAsString : "NEW_" + uuidAsString; //Test System.out.println("File: " + file.getName()); System.out.println("FNameSing: " + fNameSign.substring(file.getName().length())); sap.setVisibleSignature(rectangle, 1, fiedName); // //True allows to have 1 single reverse flase signature // pdfStamper.setFormFlattening(); // Set the rendering mode for this signature. sap.setRenderingMode(com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION); // Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC // or RenderingMode.GRAPHIC_AND_DESCRIPTION. String img = "D:\\ProjectKyPDF\\signature-523237_960_720.jpg"; // sap.setLayer2Font(new Font(Font.FontFamily.COURIER, 6)); sap.setSignatureGraphic(Image.getInstance(img)); sap.setImageScale(200); //Sgin //Provider BouncyCastleProvider provider = new BouncyCastleProvider(); Security.addProvider(provider); // Creating the signature ExternalSignature pks = new com.itextpdf.text.pdf.security.PrivateKeySignature(pk, "SHA512", BouncyCastleProvider.PROVIDER_NAME); ExternalDigest digest = new com.itextpdf.text.pdf.security.BouncyCastleDigest(); MakeSignature.signDetached(sap, digest, pks, chain, null, null, null, 0, subfilter); System.out.println("DONE!!!"); } catch (Exception e) { e.printStackTrace(); } } /** * Convert MultiPartFile to File * * @param file * @return File Converted */ private File convertMultiPartToFile(MultipartFile file) throws IOException { File convFile = new File(file.getOriginalFilename()); FileOutputStream fos = new FileOutputStream(convFile); fos.write(file.getBytes()); fos.close(); return convFile; } }