package br.com.valid.cd.vsigner.demo; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.codec.Base64; import com.itextpdf.text.pdf.security.MakeSignature; import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard; import br.com.valid.cd.vsigner.demo.contants.PropertiesFile; import br.com.valid.cd.vsigner.demo.utils.Crypt; import br.com.valid.cd.vsigner.demo.utils.PDFFile; import br.com.valid.cd.vsigner.demo.utils.RequestSession; import br.com.valid.cd.vsigner.demo.ws.cxf.signer.BillingInfoReq; import br.com.valid.cd.vsigner.demo.ws.cxf.signer.CmsPackageType; import br.com.valid.cd.vsigner.demo.ws.cxf.signer.ServiceError; import br.com.valid.cd.vsigner.demo.ws.cxf.signer.SignerParameters; import br.com.valid.cd.vsigner.demo.ws.cxf.signer.SignerResult; /** *
 * Invoca o serviço de assinatura digital de documentos - Preparação do pacote que será assinado.
 * Nesse exemplo é utilizada a política AD-RB e o documento é um PDF
 *
 */
public class PDFPrepareToSignService extends HttpServlet {

	private static final long serialVersionUID = 6453542378086966289L;

	public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		String errors = "";
		FileInputStream pdfInputStream = null;
		
		try {
			
			// Configura canal SSL
			Crypt.configureSSLChannel();

			// Recupera o certificado selecionado pelo cliente utilizando o websocket
			String signerCertificate = req.getParameter("certificateSelected");
			
			// Recupera o thumbprint do certificado selecionado pelo cliente utilizando o websocket
			String signerCertificateThumbPrint = req.getParameter("thumbprint");
			
			boolean timeStampSignature = Boolean.parseBoolean(PropertiesFile.getKeyValue(PropertiesFile.VSIGNER_SIGN_TIMESTAMP));
			
			// Transforma o certificado no formato PEM em um X509Certificate
			X509Certificate x509SignerCertificate = Crypt.getX509SignerCertificate(signerCertificate);
			
			HttpSession session = req.getSession();

			//A partir daqui realiza a leitura do diretório com os arquivos a ser
			File dir = new File(PropertiesFile.getKeyValue(PropertiesFile.PDF_DIR_TO_SIGN_KEY));
			File[] archives = dir.listFiles();
			List list = new ArrayList();
			for(File f : archives) {
				
				// Gera um UUID para o PDF
				String uuid = UUID.randomUUID().toString();
				
				pdfInputStream = PDFFile.getMultiplePdfInputStream(f);
				PdfReader pdfReader = new PdfReader(PDFFile.getPdfContent(pdfInputStream, 64*1024));
				
				// Cria um selo (não visível) de assinatura digital
				ByteArrayOutputStream osPDF = new ByteArrayOutputStream();
				
				//PdfStamper stamper = PdfStamper.createSignature(pdfReader, osPDF, '\0');
				PdfStamper stamper = PdfStamper.createSignature(pdfReader, osPDF, '\000', null, true);
				
				stamper.getSignatureAppearance().setVisibleSignature(new Rectangle(0,0,0,0),1,uuid);
				
				// Recupera buffer que deverá ser assinado
				byte[] dataToBeSignedOut = MakeSignature.getDataTobeSigned(stamper.getSignatureAppearance(), (int) (PDFFile.getPdfLength() * 2), CryptoStandard.CMS, x509SignerCertificate);
				
				// Calcula o hash sobre o buffer a ser assinado (usando SHA-256)
				byte[] hash = Crypt.calcHash(dataToBeSignedOut);
				
				// Configura informações para bilhetagem
				BillingInfoReq billingInfoReq = new BillingInfoReq();
				
				if(timeStampSignature) {
					billingInfoReq.setContractUuid(PropertiesFile.getKeyValue(PropertiesFile.CONTRACT_SIGN_RT_UUID_KEY));
				} else {
					billingInfoReq.setContractUuid(PropertiesFile.getKeyValue(PropertiesFile.CONTRACT_SIGN_RB_UUID_KEY));
				}
				
				// Código de identificação do cliente
				billingInfoReq.setUserCode(PropertiesFile.getKeyValue(PropertiesFile.USER_CODE_KEY));

				// Parametros para preparação do pacote que será assinado 
				SignerParameters signerParameters = new SignerParameters();
				
				// Bilhetagem
				signerParameters.setBillingInfoReq(billingInfoReq);
				
				if(timeStampSignature) {
					// Tipo da política (AD-RT)
					signerParameters.setCmsPackageType(CmsPackageType.P_AD_ES_AD_RT);
				} else {
					// Tipo da política (AD-RB)
					signerParameters.setCmsPackageType(CmsPackageType.P_AD_ES_AD_RB);
				}

				// Valor do hash do dado a ser assinado
				signerParameters.setHashData(hash);
				
				// Algoritmo de hash utilizado
				signerParameters.setMdAlg("SHA-256");
				
				// Data vazio (PDF sempre é no formato detached)
				signerParameters.setData(new byte[0]);
				
				// Certificado digital do assinante
				signerParameters.setX509SigningCertificate(x509SignerCertificate.getEncoded());
				
				SignerResult sr = Crypt.getExternalSignerWS().externalPreSignCMS(signerParameters);


				String signaturePackageResult = null;
				if(sr.getSignaturePackage()!= null) {
					signaturePackageResult = Base64.encodeBytes(sr.getSignaturePackage());
				}
				
				//insere os dados de todos os arquivos em uma lista
				list.add(new RequestSession(uuid, signaturePackageResult, osPDF, hash,sr,f.getName()));
				
			}
			
			List errorsList = new ArrayList<>();
			
			//iteração para verificar se obteve sucesso em todos os arquivos
			for(RequestSession reqSession : list) {
				
				// Verifica status de retorno
				if(!reqSession.getSignerResult().isSuccess()) {
					errorsList.add((ServiceError) reqSession.getSignerResult().getErrorList());
					if (errorsList != null) {
						for (ServiceError serviceError : errorsList) {
							errors += serviceError.getErrorCode() + ": " + serviceError.getErrorMessage() + "\n";
						}
						res.getWriter().println(errors);
					}

					System.out.println(errors);
				}
				
			}
			
			//se nao possuir erros nos dados da lista
			if(errorsList.isEmpty()) {
				session.setAttribute("certificateSelected", signerCertificate);
				session.setAttribute("thumbprint", signerCertificateThumbPrint);
				session.setAttribute("signatureAlg", "SHA256WithRSA");
				session.setAttribute("listRequestSession", list);
				session.setAttribute("length", list.size());
				res.sendRedirect("pdfSignerStep2.jsp");
			}
			
		} 
		catch (Exception e) {
			e.printStackTrace();
		} 
		
	}

}