/* DigiDoc4J library * * This software is released under either the GNU Library General Public * License (see LICENSE.LGPL). * * Note that the only valid version of the LGPL license as far as this * project is concerned is the original GNU Library General Public License * Version 2.1, February 1999 */ package org.digidoc4j.impl.bdoc; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.digidoc4j.Configuration; import org.digidoc4j.DataFile; import org.digidoc4j.Signature; import org.digidoc4j.SignatureProfile; import org.digidoc4j.ValidationResult; import org.digidoc4j.exceptions.RemovingDataFileException; import org.digidoc4j.impl.bdoc.asic.AsicContainerCreator; import org.digidoc4j.impl.bdoc.asic.AsicEntry; import org.digidoc4j.impl.bdoc.asic.AsicFileContainerParser; import org.digidoc4j.impl.bdoc.asic.AsicParseResult; import org.digidoc4j.impl.bdoc.asic.AsicStreamContainerParser; import org.digidoc4j.impl.bdoc.asic.BDocContainerValidator; import org.digidoc4j.impl.bdoc.manifest.AsicManifest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.esig.dss.DSSDocument; public class ExistingBDocContainer extends BDocContainer { private static final Logger logger = LoggerFactory.getLogger(ExistingBDocContainer.class); private List<Signature> newSignatures = new ArrayList<>(); private List<Signature> allSignatures = new ArrayList<>(); private List<DataFile> allDataFiles = new ArrayList<>(); private List<DataFile> newDataFiles = new ArrayList<>(); private AsicParseResult containerParseResult; private boolean dataFilesHaveChanged; public ExistingBDocContainer(String containerPath) { openContainer(containerPath); } public ExistingBDocContainer(String containerPath, Configuration configuration) { super(configuration); openContainer(containerPath); } public ExistingBDocContainer(InputStream stream) { openContainer(stream); } public ExistingBDocContainer(InputStream stream, Configuration configuration) { super(configuration); openContainer(stream); } @Override protected ValidationResult validateContainer() { BDocContainerValidator validator = new BDocContainerValidator(containerParseResult, getConfiguration()); validator.setValidateManifest(!dataFilesHaveChanged); ValidationResult validationResult = validator.validate(getSignatures()); return validationResult; } @Override public void extendSignatureProfile(SignatureProfile profile) { removeAllExistingSignaturesFromContainer(); List<Signature> signatures = extendAllSignaturesProfile(profile, allSignatures, allDataFiles); allSignatures = signatures; newSignatures = new ArrayList<>(signatures); } @Override public DataFile addDataFile(String path, String mimeType) { DataFile dataFile = new DataFile(path, mimeType); addDataFile(dataFile); return dataFile; } @Override public DataFile addDataFile(InputStream inputStream, String fileName, String mimeType) { DataFile dataFile = new DataFile(inputStream, fileName, mimeType); addDataFile(dataFile); return dataFile; } @Override public DataFile addDataFile(File file, String mimeType) { DataFile dataFile = new DataFile(file.getPath(), mimeType); addDataFile(dataFile); return dataFile; } @Override public void addDataFile(DataFile dataFile) { String fileName = dataFile.getName(); verifyIfAllowedToAddDataFile(fileName); allDataFiles.add(dataFile); newDataFiles.add(dataFile); dataFilesHaveChanged = true; removeExistingFileFromContainer(AsicManifest.XML_PATH); } @Override public void addSignature(Signature signature) { validateIncomingSignature(signature); newSignatures.add(signature); allSignatures.add(signature); } @Override public List<DataFile> getDataFiles() { return allDataFiles; } @Override public List<Signature> getSignatures() { return allSignatures; } @Override public void removeDataFile(String fileName) { logger.error("Datafiles cannot be removed from an already signed container"); throw new RemovingDataFileException(); } @Override public void removeDataFile(DataFile file) { logger.error("Datafiles cannot be removed from an already signed container"); throw new RemovingDataFileException(); } @Override public void removeSignature(Signature signature) { logger.info("Removing signature " + signature.getId()); validateIncomingSignature(signature); boolean wasNewlyAddedSignature = newSignatures.remove(signature); boolean wasIncludedInContainer = allSignatures.remove(signature); if (wasIncludedInContainer && !wasNewlyAddedSignature) { logger.debug("This signature was included in the container before the container was opened"); removeExistingSignature((BDocSignature) signature); } } @Override @Deprecated public void removeSignature(int signatureId) { logger.debug("Removing signature from index " + signatureId); Signature signature = allSignatures.get(signatureId); if (signature != null) { removeSignature(signature); } } protected void writeAsicContainer(AsicContainerCreator zipCreator) { int nextSignatureFileIndex = determineNextSignatureFileIndex(); String userAgent = createUserAgent(); zipCreator.setZipComment(userAgent); zipCreator.writeExistingEntries(containerParseResult.getAsicEntries()); if(dataFilesHaveChanged) { zipCreator.writeManifest(allDataFiles); } zipCreator.writeSignatures(newSignatures, nextSignatureFileIndex); zipCreator.writeDataFiles(newDataFiles); if (StringUtils.isNotBlank(containerParseResult.getZipFileComment())) { zipCreator.writeContainerComment(containerParseResult.getZipFileComment()); } zipCreator.finalizeZipFile(); } private void openContainer(String containerPath) { logger.debug("Opening container from " + containerPath); AsicParseResult containerParseResult = new AsicFileContainerParser(containerPath, getConfiguration()).read(); populateContainerWithParseResult(containerParseResult); } private void openContainer(InputStream inputStream) { logger.debug("Opening container from stream"); AsicParseResult containerParseResult = new AsicStreamContainerParser(inputStream, getConfiguration()).read(); populateContainerWithParseResult(containerParseResult); } private void populateContainerWithParseResult(AsicParseResult parseResult) { containerParseResult = parseResult; getDataFiles().addAll(parseResult.getDataFiles()); List<DSSDocument> signatureFiles = parseResult.getSignatures(); List<DSSDocument> detachedContents = parseResult.getDetachedContents(); List<Signature> bDocSignatures = parseSignatureFiles(signatureFiles, detachedContents); allSignatures.addAll(bDocSignatures); } private void removeExistingSignature(BDocSignature signature) { DSSDocument signatureDocument = signature.getSignatureDocument(); if (signatureDocument == null) { return; } String signatureFileName = signatureDocument.getName(); removeExistingFileFromContainer(signatureFileName); } private void removeExistingFileFromContainer(String filePath) { logger.debug("Removing file from the container: " + filePath); List<AsicEntry> asicEntries = containerParseResult.getAsicEntries(); for (AsicEntry entry : asicEntries) { String entryFileName = entry.getZipEntry().getName(); if (StringUtils.equalsIgnoreCase(filePath, entryFileName)) { asicEntries.remove(entry); logger.debug("File was successfully removed"); break; } } } private void removeAllExistingSignaturesFromContainer() { logger.debug("Removing all existing signatures"); for (Signature signature : allSignatures) { removeExistingSignature((BDocSignature) signature); } } private int determineNextSignatureFileIndex() { Integer currentUsedSignatureFileIndex = containerParseResult.getCurrentUsedSignatureFileIndex(); if (currentUsedSignatureFileIndex == null) { return 0; } return currentUsedSignatureFileIndex + 1; } }