/* 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.manifest; import org.digidoc4j.Configuration; import org.digidoc4j.DataFile; import org.digidoc4j.Signature; import org.digidoc4j.impl.bdoc.BDocSignature; import org.digidoc4j.impl.bdoc.BDocSignatureOpener; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import eu.europa.esig.dss.DSSDocument; import eu.europa.esig.dss.FileDocument; import eu.europa.esig.dss.InMemoryDocument; import eu.europa.esig.dss.MimeType; public class ManifestValidatorTest { @Test public void validateEntries() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("2", new ManifestEntry("2", "b")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("1", "a")); add(new ManifestEntry("2", "b")); }}; Assert.assertEquals(0, ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "").size()); } @Test public void validateEntriesUnOrdered() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("2", new ManifestEntry("2", "b")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("2", "b")); add(new ManifestEntry("1", "a")); }}; assertEquals(0, ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "").size()); } @Test public void validateEntriesNotEqual() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("2", new ManifestEntry("2", "b")); put("2", new ManifestEntry("2", "f")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("1", "a")); add(new ManifestEntry("2", "b")); }}; List<String> errorMessages = ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "S0"); assertEquals(1, errorMessages.size()); assertEquals("Manifest file has an entry for file 2 with mimetype f but the signature file for signature S0 " + "indicates the mimetype is b", errorMessages.get(0)); } @Test public void validateEntriesNotEqualValueSwapped() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("2", new ManifestEntry("2", "b")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("1", "b")); add(new ManifestEntry("2", "a")); }}; List<String> errorMessages = ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "S0"); assertEquals(2, errorMessages.size()); assertEquals("Manifest file has an entry for file 1 with mimetype a but the signature file for signature S0 " + "indicates the mimetype is b", errorMessages.get(0)); assertEquals("Manifest file has an entry for file 2 with mimetype b but the signature file for signature S0 " + "indicates the mimetype is a", errorMessages.get(1)); } @Test public void validateEntriesMissingEntryInSignature() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("2", new ManifestEntry("2", "b")); put("3", new ManifestEntry("3", "c")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("1", "a")); add(new ManifestEntry("3", "c")); }}; List<String> errorMessages = ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "S0"); assertEquals(1, errorMessages.size()); assertEquals("Manifest file has an entry for file 2 with mimetype b but the signature file for signature S0 does" + " not have an entry for this file", errorMessages.get(0)); } @Test public void validateEntriesMissingEntryInManifest() throws Exception { Map<String, ManifestEntry> entriesFromManifest = new HashMap<String, ManifestEntry>() {{ put("1", new ManifestEntry("1", "a")); put("3", new ManifestEntry("3", "c")); }}; Set<ManifestEntry> entriesFromSignature = new HashSet<ManifestEntry>() {{ add(new ManifestEntry("1", "a")); add(new ManifestEntry("2", "b")); add(new ManifestEntry("3", "c")); }}; List<String> errorMessages = ManifestValidator.validateEntries(entriesFromManifest, entriesFromSignature, "S1"); assertEquals(1, errorMessages.size()); assertEquals("The signature file for signature S1 has an entry for file 2 with mimetype b but the manifest file" + " does not have an entry for this file", errorMessages.get(0)); } @Test public void validateHealthyContainer() throws Exception { ManifestParser manifestParser = createManifest(dataFile("test.txt", "text/plain")); List<DSSDocument> detachedContents = Arrays.asList(detachedContent("test.txt", "text/plain")); List<Signature> signatures = openSignature("testFiles/xades/test-bdoc-ts.xml", detachedContents); List<String> errors = new ManifestValidator(manifestParser, detachedContents, signatures).validateDocument(); assertTrue(errors.isEmpty()); } @Test public void container_withDifferentDataFileName_shouldBeInvalid() throws Exception { ManifestParser manifestParser = createManifest(dataFile("test.txt", "text/plain")); List<DSSDocument> detachedContents = Arrays.asList(detachedContent("other.txt", "text/plain"), detachedContent("test.txt", "text/plain")); List<Signature> signatures = openSignature("testFiles/xades/test-bdoc-ts.xml", detachedContents); List<String> errors = new ManifestValidator(manifestParser, detachedContents, signatures).validateDocument(); assertFalse(errors.isEmpty()); assertEquals("Container contains a file named other.txt which is not found in the signature file", errors.get(0)); } @Test @Ignore("https://www.pivotaltracker.com/story/show/125469911") public void container_withSpecialDataFileCharacters_shouldBeValid() throws Exception { ManifestParser manifestParser = createManifest(dataFile("dds_JÜRIÖÖ € žŠ päev.txt", "application/octet-stream")); List<DSSDocument> detachedContents = Arrays.asList(detachedContent("dds_JÜRIÖÖ € žŠ päev.txt", "application/octet-stream")); List<Signature> signatures = openSignature("testFiles/xades/test-bdoc-specia-chars-data-file.xml", detachedContents); List<String> errors = new ManifestValidator(manifestParser, detachedContents, signatures).validateDocument(); assertTrue(errors.isEmpty()); } private List<Signature> openSignature(String signaturePath, List<DSSDocument> detachedContents) { BDocSignatureOpener signatureOpener = new BDocSignatureOpener(detachedContents, new Configuration(Configuration.Mode.TEST)); BDocSignature signature = signatureOpener.parse(new FileDocument(signaturePath)).get(0); signature.getOrigin().getDssSignature().checkSignatureIntegrity(); List<Signature> signatureList = new ArrayList<>(1); signatureList.add(signature); return signatureList; } private DataFile dataFile(String fileName, String mimeType) { return new DataFile(new byte[]{1, 2, 3}, fileName, mimeType); } private ManifestParser createManifest(DataFile... dataFile) { AsicManifest asicManifest = new AsicManifest(); asicManifest.addFileEntry(Arrays.asList(dataFile)); DSSDocument manifestFile = new InMemoryDocument(asicManifest.getBytes()); return new ManifestParser(manifestFile); } private DSSDocument detachedContent(String name, String mimeType) { return new InMemoryDocument(new byte[]{1, 2, 3}, name, MimeType.fromMimeTypeString(mimeType)); } }