From eb3b4d9b3fa3892c838a6182632019ec8ac142ae Mon Sep 17 00:00:00 2001 From: Carl Wilson Date: Wed, 8 Nov 2023 14:35:33 +0000 Subject: [PATCH] FIX: Issue parsing not well formed manifest XML - added null manifest tests to `PackageParserImpl`; - same for `ValidatingParserImpl`; - added test file and unit test for diagnosis and regression protection; - bumped Maven version to `0.9.1`; and - updated docs with the new version. --- README.md | 2 ++ docs/DEVELOPER.md | 2 +- odf-apps/pom.xml | 2 +- odf-core/pom.xml | 2 +- .../odf/pkg/PackageParserImpl.java | 17 +++++++++-------- .../odf/validation/ValidatingParserImpl.java | 10 ++++++---- .../openpreservation/odf/fmt/TestFiles.java | 2 ++ .../odf/pkg/PackageParserTest.java | 11 +++++++++++ .../odf/fmt/pkg/invalid/manifest_not_wf.ods | Bin 0 -> 8073 bytes pom.xml | 2 +- 10 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 odf-core/src/test/resources/org/openpreservation/odf/fmt/pkg/invalid/manifest_not_wf.ods diff --git a/README.md b/README.md index ec929ca4..ef2b76c4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ODF Validator +Latest version is 0.9.1 + ## About [Open Preservation Foundation](https://openpreservation.org/)'s OpenDocument Format Validator (OPF ODF Validator) enables your organisation to validate the file format standard and a set of file format policy rules created for improving the preservation effort of any files saved in the OpenDocument Format. diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index f8c5822c..3ec77447 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -44,7 +44,7 @@ To include the core validation library in your project, add the following depend org.openpreservation.odf odf-core - 0.9.0 + 0.9.1 ``` diff --git a/odf-apps/pom.xml b/odf-apps/pom.xml index dcf6a81b..7da1f38f 100644 --- a/odf-apps/pom.xml +++ b/odf-apps/pom.xml @@ -5,7 +5,7 @@ org.openpreservation.odf odf-validator - 0.9.0 + 0.9.1 odf-apps diff --git a/odf-core/pom.xml b/odf-core/pom.xml index 71603664..49be51e4 100644 --- a/odf-core/pom.xml +++ b/odf-core/pom.xml @@ -5,7 +5,7 @@ org.openpreservation.odf odf-validator - 0.9.0 + 0.9.1 org.openpreservation.odf diff --git a/odf-core/src/main/java/org/openpreservation/odf/pkg/PackageParserImpl.java b/odf-core/src/main/java/org/openpreservation/odf/pkg/PackageParserImpl.java index e949aca9..306a832a 100644 --- a/odf-core/src/main/java/org/openpreservation/odf/pkg/PackageParserImpl.java +++ b/odf-core/src/main/java/org/openpreservation/odf/pkg/PackageParserImpl.java @@ -77,13 +77,12 @@ private final OdfPackage parsePackage(final Path toParse, final String name) thr private final OdfPackage makePackage(final String name, final Formats format) throws ParserConfigurationException, IOException, SAXException { OdfPackageImpl.Builder builder = OdfPackageImpl.Builder.builder().name(name).archive(this.cache).format(format) - .mimetype(mimetype) - .manifest(manifest); - if (this.manifest == null) { - return builder.build(); - } - for (FileEntry docEntry : manifest.getDocumentEntries()) { - builder.document(docEntry.getFullPath(), makeDocument(docEntry)); + .mimetype(mimetype); + if (this.manifest != null) { + builder.manifest(manifest); + for (FileEntry docEntry : manifest.getDocumentEntries()) { + builder.document(docEntry.getFullPath(), makeDocument(docEntry)); + } } for (Entry docEntry : this.xmlDocumentMap.entrySet()) { if (isMetaInf(docEntry.getKey())) { @@ -147,9 +146,11 @@ private final void processEntry(final ZipEntry entry) OdfXmlDocument xmlDoc = OdfXmlDocuments.xmlDocumentFrom(is); if (xmlDoc != null) { this.xmlDocumentMap.put(path, xmlDoc); + if (xmlDoc.getParseResult().isWellFormed()) { + this.parseOdfXml(path); + } } } - this.parseOdfXml(path); } private final boolean isOdfXml(final String entrypath) { diff --git a/odf-core/src/main/java/org/openpreservation/odf/validation/ValidatingParserImpl.java b/odf-core/src/main/java/org/openpreservation/odf/validation/ValidatingParserImpl.java index 71de7e54..0e6c9b05 100644 --- a/odf-core/src/main/java/org/openpreservation/odf/validation/ValidatingParserImpl.java +++ b/odf-core/src/main/java/org/openpreservation/odf/validation/ValidatingParserImpl.java @@ -185,22 +185,24 @@ private final List validateMimeEntry(final ZipEntry mimeEntry, final bo private List validateManifest(final OdfPackage odfPackage) { final List messages = new ArrayList<>(); Manifest manifest = odfPackage.getManifest(); - if (manifest.getEntry("/") == null) { + if (manifest != null && manifest.getEntry("/") == null) { if (!odfPackage.hasMimeEntry()) { messages.add(FACTORY.getWarning("PKG-19")); } else { messages.add(FACTORY.getError("PKG-11")); } - } else if (!hasManifestRootMime(manifest) || (odfPackage.hasMimeEntry() + } else if (hasManifestRootMime(manifest) && (odfPackage.hasMimeEntry() && !manifest.getRootMediaType().equals(odfPackage.getMimeType()))) { messages.add(FACTORY.getError("PKG-12", manifest.getRootMediaType(), odfPackage.getMimeType())); } - messages.addAll(checkManifestEntries(odfPackage)); + if (manifest != null) { + messages.addAll(checkManifestEntries(odfPackage)); + } return messages; } private boolean hasManifestRootMime(final Manifest manifest) { - return manifest.getRootMediaType() != null; + return manifest != null && manifest.getRootMediaType() != null; } private List checkManifestEntries(final OdfPackage odfPackage) { diff --git a/odf-core/src/test/java/org/openpreservation/odf/fmt/TestFiles.java b/odf-core/src/test/java/org/openpreservation/odf/fmt/TestFiles.java index 240b8ec8..5102266d 100644 --- a/odf-core/src/test/java/org/openpreservation/odf/fmt/TestFiles.java +++ b/odf-core/src/test/java/org/openpreservation/odf/fmt/TestFiles.java @@ -13,6 +13,7 @@ public class TestFiles { final static String EMBEDDED_TEST_ROOT = PKG_TEST_ROOT + "embedded/"; final static String ENCRYPTED_TEST_ROOT = PKG_TEST_ROOT + "encrypted/"; final static String DSIG_TEST_ROOT = PKG_TEST_ROOT + "dsigs/"; + final static String INVALID_PKG_ROOT = PKG_TEST_ROOT + "invalid/"; final static String XML_TEST_ROOT = TEST_ROOT + "xml/"; final static String FILE_TEST_ROOT = TEST_ROOT + "files/"; public final static URL EMPTY_ODS = ClassLoader.getSystemResource(ZIP_TEST_ROOT + "empty.ods"); @@ -56,4 +57,5 @@ public class TestFiles { public final static URL DSIG_INVALID = ClassLoader.getSystemResource(DSIG_TEST_ROOT + "dsigs.odt"); public final static URL DSIG_VALID = ClassLoader.getSystemResource(DSIG_TEST_ROOT + "dsigs-valid.ods"); public final static URL DSIG_BADNAME = ClassLoader.getSystemResource(DSIG_TEST_ROOT + "bad_dsig_name.ods"); + public final static URL MANIFEST_NOT_WF = ClassLoader.getSystemResource(INVALID_PKG_ROOT + "manifest_not_wf.ods"); } diff --git a/odf-core/src/test/java/org/openpreservation/odf/pkg/PackageParserTest.java b/odf-core/src/test/java/org/openpreservation/odf/pkg/PackageParserTest.java index 45111d91..657eb1ad 100644 --- a/odf-core/src/test/java/org/openpreservation/odf/pkg/PackageParserTest.java +++ b/odf-core/src/test/java/org/openpreservation/odf/pkg/PackageParserTest.java @@ -1,6 +1,7 @@ package org.openpreservation.odf.pkg; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -103,4 +104,14 @@ public void testDsigParsing() throws ParserConfigurationException, SAXException, assertNotNull("Dsig file META-INF/documentsignatures.xml result should not be null" , result); assertTrue("Package should have a well formed dsig for META-INF/documentsignatures.xml" , result.isWellFormed()); } + + @Test + public void testManifestNotWF() throws IOException { + PackageParser parser = OdfPackages.getPackageParser(); + InputStream is = TestFiles.MANIFEST_NOT_WF.openStream(); + OdfPackage pkg = parser.parsePackage(is, TestFiles.MANIFEST_NOT_WF.toString()); + ParseResult result = pkg.getEntryXmlParseResult("META-INF/manifest.xml"); + assertNotNull("Dsig file META-INF/documentsignatures.xml result should not be null" , result); + assertFalse("Package should NOT have a well formed META-INF/manifest.xml" , result.isWellFormed()); + } } diff --git a/odf-core/src/test/resources/org/openpreservation/odf/fmt/pkg/invalid/manifest_not_wf.ods b/odf-core/src/test/resources/org/openpreservation/odf/fmt/pkg/invalid/manifest_not_wf.ods new file mode 100644 index 0000000000000000000000000000000000000000..a97b702433e39e853203fb50a68744f252f5f1cd GIT binary patch literal 8073 zcmcgxbzD?i*B(k51nCy(mhKLb?q(ReYldzR>F`oYhqQDf9R?jD4bsvL0>XU5eLt^y zU-kR%Tjw|D>^Z-)p1t?l=d8WfdQ=q<5b*#2019AE-&zNBMqE0>k<7z z?^eYW^M)`|z+Bkr$EWqrN zHV_ApGx!ga{MAq`?VUgni$9s>S3|v>pfkwP!u}7v{mP^uGcyZ&3)p%(ed`eg1?9h% z9s@Q>2auzUr3Dzm=4x&^m@w!V!g2S>zHq3;(3Chk5|S%JUz2TC2hUSoB=)0J+=aH- z1Z}mKC0kh^R?20$7GrDEc0pwCqN$s%NH5B|o$c z$+>jOCm6|jB2T) z2HDPz_d2H%iJBKI&aOrS)vLFL)l)qS5|2Su?0W(UA!}Av=;ca2RukyV*X8ftOa?dbi(KpH3d(X_N0+#_J~qTu0mA-8Kw5zdJG8;00=<<0RHm@{K|Z2F!O;SUiKDXHctop zd3^_`S>C%hZ9q^_Mt#Opb7aI!`N3YRSX^3)V z6qo3vnhu&8AB4xfbRHrk#{D!lTj?tS_ty7W2*zP(Ai93`Tm*~zR4B!pInrLK{4!$v ziziq~t!q6hMc6jlfFPZh1y9wBtyrb2P~d6p?vQ9C-$~#|M_OOVaY7vuOZl?vF0`P` z!<#z15wzzvLX_NS+8r+2%OQ@)IPQ5jCa(j;Q!F(<`l$pRem*j%3(X)YhIk4qNlW(y zx!a+Qu%R!Bj>UzN;M7`LExoTZ=9I|>Pb1SHS{3~lD>x}6i`-S>S5M{SLrTro((FU0 zOsWF`W#avY^Lt7kS-at@(8%^erNlp#lZB<^*4iwua#DR1L2{vJNy@mKoaK96Z81Ia z46i=P*b1i0bavAqFrNd#(PX!DhPV#oT)dM zva?ne3$CL0M!1v#kvF`k>Pot#N^>!UvL3UADV1g)RGpU*!RVPJqZ1#!hJ6cy+%UE{5V zgI<*RMhR5hM`Otzs3h&EWMX7*d|Qjz^RV&lD{{+lc@M+vork=wz42Di^;4>K}GVf?Cb;0pp-a$RSc=g zoJl~;j?q&vh6j6h%^nQIC8A7h^<>1DFu6yDD&0h5AIg@;GDqcJqOh zjqG}mRn#QAtr}IJATh*~|Arc0(K58C_Jxu*8zH{9`=G&-@w)U#oy49bhB>Lo)9rDZ zuXqB4=E;PJa~C{441(`G-p+Qm$!%aC%-2&cUz@j|C(s}HyGrkiJ+h-n8u8g$OGSgk zJ345-*I^traX|XCk@$X-{){{*qJ?Ts2InO=at{y($kD45tM4c2p5phI*`jJ@=IIJy z^|EX_E?Hb=M%dQ4*rZM{|AY>6_!3UYmq_(z0p!(J*VT9!hv?|y9ADA$z36v2hI8Z~ ziW6j#*l4;kg^FSh4_t{d9*V@X#!lS3Glen}@|kN(6>YI!>G&ySX%{q`Tl7%_&vraX znCj%0cy)~KjbWknakJ!Qo*9&Sg=ZSiOzGS1zZ}@0r(e@?K4MXWV9+3T4QZV}fASSm z*Z;F}wR|7n+LXc@2BGWd>}xXIZE0X!?kdP<8%ULyDLVL|dvt#0xW@#5EXtufhV>q) zzbC?VDQB%JuWUoDd(3?*;mreUpN^X|d7HGod!= zt-P~gA&C|4;e`?xPAZNQqp%fbnKnh_W}MURKI*6zEY+*$%B>FZ%+*<=x_vn7Q4{4P zACGX_yz0$oaW6j8wr>TghH2St1Nk!th6|?1_ACPPtK+hzPd|{p=$$ms(L`|@qm1po zxELVgyK}9r2hQwLmxxm4+NMJ))5Qp1S`8rR-V*3G7f#zBB4*N351eXgPc~hOdKckl zA0T7FoOBmAV04Q^pXAg@!lj7Cq<2nV zm*BrEj_s1+HS`IB`rmzYW{4{AB7G;1ojRt%*wD}! z>{#bUks?#vns_`=%e2~?Fg|7KE?iC#+BS(q^#cRzF4PG1K5ar-qaJGSb2-eF?fIMgD(5!1 zhI(gKcA4UyEHz4ht)&^_roNLV8>b$2^~%<}ua{1Nq~LmoCNAZ!)9LzU%JAex4$?*v z3f=r<7=a{6a5wB(wjSO{J)r~sAZVbf4{@oaXTKoK>6&pu>~?7lm{TqCVWEZ9A43at z*wUIgIYKNPA-Ai$tE*J8%!@aFu9K~~HAF;FhDL0{t2NQVtv)LGScW?!+U|bM3ftv&|Gqi7-vYF9 zLY`WnNAj3DbO5KED-1dmpE1pk^wwPsRISU!?2ulCXTRh53j9uAdCqL5PvzRkAhXXA zg7{ThWzF~%b%gAu%}}~y+E3wxaq<0?1N)#zVZgI+;n&Z@bLMCgF~Xy9-mFcGh;9px{46= zn>_+XY@Q^cG@bdT`>r0l(D;4r8CdPs`4sQqdQNrGu8PpaTOP$Fq&TdOgym-;;|<^v z&>g69!i}lZ7iIZ4_6V6S@HotQ2ycJZ#hW>|ASF44(}Tn&oX4+waBE|?&dDG_`E<1^ zByvf1J)y=Z4|$?w+(-Q(fkGq-yw&0hqY9sM_a_IE+q+oyy+xbti^hu=sOld>*4~;> zb8YK>9H!XcA0um1u)GJ?xN7oJOjzT&M*tBkE_cvc_VF`kV`Vn2mF|K4`jI@GWi~vX z3I;4*79H1Q)tf1vf;wi8xWhG-t@H3KX>KwpZ2Ci236X+c=J{b^@J@N5G$HZhPUc-l z!>w>6f;$O_X-i^6r?s9YAdb{)JWtjsWPlwhBN}nf<*M4L%8IW7?l;P0RE|wY>#<;`%n3JH}3ialiM)^OxHo_ zE)JH8X`^c~9EPY`69)c=h)15T3l~R|Jc0o%jg{h%J@Y<1)afBS4xl#x}-| z_;m8157CQMpio!7Ff=U9cC#n7O{SBwDrST2yaytW)LBRV;_M-BOL{Dao;S^J?Xqiy zIz&OYgW9p%P-iEmg|6i$TJ@>rt+tjE*RvN?k>uh_p&1+&YUVMAK|IdV=uba=?HOH{ zn-bAvO!_o{GAq}*@XDXmguKp!-Ff=2QiNxs2nfa+O&-}=2;56$HRAjXGLnjEnK=Z& z`yLpVC9Q`sXU$84ns7ZvU}?I?T!fhJ&P6`e?d?a`t_o>Tht0CqG}^?Y4`=@zydMb4 zYtdThaEyC9OI@9>$2$>nuA8qFR&V~^Fi?vX!pRWH?$9OiFsf46z5 zrnQ@csUyh79?TB;)?{;bw2Dwwmcv9Nxy@-X(-r02}}X=BEIHKZQ5D*X-;uRn2n-m$48WZ?DKE5z7 zJEyYgb$L#EdwWk?)BB$GiIKsvv9W=v<>|ePg;VJI{P^1T!TLFL?-F`^e0=s5`t{=E z=H>?0AruPrvmJMXjYCRaT0+xvW_MN&t4kbDTH>B!l;#N+}C*%Kg{)pUEUW?=Z8YazM*lBMiN~Y?w{Zf>SuWuCtK?W=Av@3eUe&Me&<@a@O)i&kx*R z5TW;em@L~)93z|eqB9F>c(rO9nm3i#X_S8^QDnH(Q4mYm=z%YlQX!^w(*k{KC79*I z>nQL+*^i87@}V-WEH1EWQ(|rgYf)>A!CDQ^$Awv3G}a(uKKDMB`?!8Zv4KEM3dQ4n zrYIUzg9)ar%KR_l4;u6dpUAphwdEP#W7qZ18?N4wa!(llm^x_5LplF!hWokCURAI| zaYJw`%Ee6%^=>D%D&iQs*U5?#|)LvN8TJpf=jpChwvr)5N*PtcH4yx)#{ z@|JN0>5cp@%9UNAnqnSKOzV>u(3AM;xMV2nYGKH`)A4K{?xRebcq&e;h!l*Xkn_{_ z>``KZ*u0*ae#ylI|H2%F%#q2Xlt66vF6`T_ z9!1njxLd%xp0dRiT!~To+{ipQ^5<#|VTSx#$nSdRn%W}#eW<^9O4K;6?p`@WsRyg6 zHmT&|WqI<$r!n3W5;UflBG4W{9i*s=+EK!(5TJH}t3k-9*e}Rk`id)XMz%4j(0N_g zDmQcnc9%x2Qq?45|FA{h9OV&m<2aHY^bWpojiF2Uh`;kwEQqTcXK*c!J;0m4O){Z6 zyIDm0VuNo@x)(P@m?~< z^5L5XhKRSGQ2%z6gt=uO7H=xyV3P$kw8j+{?m{jsJuwPoh7ZM0ml5|#CuoW6gQipK z-)q~Dag%YaFb%P61*Cu8JzGK_i#q=Fws_5xnZ3=~^yJV@3sPDNb5P=F86Kyo?!~9OlM<4 zSVBrCtwd895HAWwQhH_PuR0vvd2Nb7RyQ7^{D4bBC^jn|!FS`l5p7fvcm)qJG^YZ&1B1|qN7Nej9pDn@oQSf`;}86M@!KT} zvExdn)=wgt`qCZW4N;!6KYlY8d4gzrhcc&Tb>Ao+~ij^l-uIEk*5hClap4p=){8i5gx z5L|r0W|NpB&6XKg#;weSHKgE&W`0j!Vz7Wa-lPIE|OG(Y30~CMKDE^b7`{ z53l-@(v(?xOd^Kxe+Z4^eAL&sRZfUSNl4Q1#j<8IB(~r_oDFMQH63X=f3;ti3o*H# zUU|`09dfsBA2wb1%5);AvMyUbp)76QOr$~7qj%XL`4lU>vhv|QYCo}v7nD!T%~rrC-Pu{@lDpr2|XPs zN+|zd54I?y;n>uszC{}8Yqu2LU?mr zh>81nr`HT}%*0q2!)c#bUJQw;md3!7rc~0#;R%o^l-h_ZGfrO%=6!DQb>p%00Y1(U z9-d!RoEk==yyL~G#+K0XSi=$3@g9w}$PgDE<}fy8b1-`ennLMBmgrxl1b(8P(7)rM z-EtlAVpswl$nZ}*1fx}kV6@7RBQ-W1qS(g2uLO3knDogBl z?54UabAEvqXmJGNRH~Ri-7OF>vZ*l^d%I1i8R;5qEl?7T*ddKKRnB;yz6D# zbR0NVHw{mB(~x!kvVW(q16@FY6gfhl8OGE zWxxKT<-J_mKFt!3$@#tNYuOwna~mS{xOvR*`dkFs%u-~KH zQcK@O@E0gQa$>*7xn;$^i|a3N{);2~J=o7vtM~=jch2nhC_hha?H4FNa%jKD`FY96 z;s4vvKXYpTLHb4u{YV(y2F~9_2Zr>IYk_fW-(KQxnm?BMZj-O?k_^kdzSB$p*88!J zbXy4gE(9=`Z)L%MYyFrf-qx7D%OUKq+4qXmH^pz?+P~At?}~DFf1gx-L-{t@AKmiL zW`f}UoNe4{e)A&#?Y4jPB09vsapFI^l+epe&tJO~B-kzi0N}umGT4sr=I__(e*ku} BA)WvL literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml index d68ae3b6..98796659 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ org.openpreservation.odf odf-validator - 0.9.0 + 0.9.1 pom