diff --git a/biz.aQute.bndlib/src/aQute/bnd/differ/DiffPluginImpl.java b/biz.aQute.bndlib/src/aQute/bnd/differ/DiffPluginImpl.java index 799b425792..84d09b411e 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/differ/DiffPluginImpl.java +++ b/biz.aQute.bndlib/src/aQute/bnd/differ/DiffPluginImpl.java @@ -1,5 +1,6 @@ package aQute.bnd.differ; +import static aQute.bnd.osgi.Jar.METAINF_SIGNING_P; import static aQute.bnd.service.diff.Delta.CHANGED; import java.io.File; @@ -13,7 +14,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.jar.Manifest; -import java.util.regex.Pattern; import aQute.bnd.header.Attrs; import aQute.bnd.header.OSGiHeader; @@ -129,8 +129,6 @@ private Element bundleElement(Analyzer analyzer) throws Exception { /** * Create an element representing all resources in the JAR */ - private final static Pattern META_INF_P = Pattern.compile("META-INF/([^/]+\\.(MF|SF|DSA|RSA))|(SIG-.*)"); - private Element resourcesElement(Analyzer analyzer) throws Exception { Jar jar = analyzer.getJar(); @@ -139,16 +137,20 @@ private Element resourcesElement(Analyzer analyzer) throws Exception { for (Map.Entry entry : jar.getResources() .entrySet()) { + String path = entry.getKey(); // // The manifest and other (signer) files are ignored // since they are extremely sensitive to time // - if (META_INF_P.matcher(entry.getKey()) - .matches()) + if (jar.getManifestName() + .equals(path) + || METAINF_SIGNING_P.matcher(path) + .matches()) { continue; + } - if (localIgnore != null && localIgnore.matches(entry.getKey())) + if (localIgnore != null && localIgnore.matches(path)) continue; // @@ -159,8 +161,6 @@ private Element resourcesElement(Analyzer analyzer) throws Exception { // directory with source code can be found. // - String path = entry.getKey(); - if (path.endsWith(Constants.EMPTY_HEADER)) continue; diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Jar.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Jar.java index ea35b585df..10ec3fd0f8 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Jar.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Jar.java @@ -41,6 +41,7 @@ import java.util.function.Predicate; import java.util.jar.Attributes; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.regex.Matcher; @@ -96,7 +97,6 @@ public enum Compression { STORE } - private static final String DEFAULT_MANIFEST_NAME = "META-INF/MANIFEST.MF"; private static final Pattern DEFAULT_DO_NOT_COPY = Pattern .compile(Constants.DEFAULT_DO_NOT_COPY); @@ -106,7 +106,7 @@ public enum Compression { private Optional manifest; private Optional moduleAttribute; private boolean manifestFirst; - private String manifestName = DEFAULT_MANIFEST_NAME; + private String manifestName = JarFile.MANIFEST_NAME; private String name; private File source; private ZipFile zipFile; @@ -122,6 +122,8 @@ public enum Compression { private boolean calculateFileDigest; private int fileLength = -1; private long zipEntryConstantTime = ZIP_ENTRY_CONSTANT_TIME; + public static final Pattern METAINF_SIGNING_P = Pattern + .compile("META-INF/([^/]+\\.(?:DSA|RSA|EC|SF)|SIG-[^/]+)", Pattern.CASE_INSENSITIVE); public Jar(String name) { this.name = name; @@ -590,6 +592,8 @@ public void write(OutputStream to) throws Exception { Set done = new HashSet<>(); Set directories = new HashSet<>(); + + // Write manifest first if (doNotTouchManifest) { Resource r = getResource(manifestName); if (r != null) { @@ -601,6 +605,22 @@ public void write(OutputStream to) throws Exception { done.add(manifestName); } + // Then write any signature info next since JarInputStream really cares! + Map metainf = getDirectory("META-INF"); + if (metainf != null) { + List signing = metainf.keySet() + .stream() + .filter(path -> METAINF_SIGNING_P.matcher(path) + .matches()) + .collect(toList()); + for (String path : signing) { + if (done.add(path)) { + writeResource(jout, directories, path, metainf.get(path)); + } + } + } + + // Write all remaining entries for (Map.Entry entry : getResources().entrySet()) { // Skip metainf contents if (!done.contains(entry.getKey())) @@ -1245,16 +1265,16 @@ public byte[] getTimelessDigest() throws Exception { return md.digest(); } - private final static Pattern SIGNER_FILES_P = Pattern.compile("(.+\\.(SF|DSA|RSA))|(.*/SIG-.*)", - Pattern.CASE_INSENSITIVE); - public void stripSignatures() { - Map map = getDirectory("META-INF"); - if (map != null) { - for (String file : new HashSet<>(map.keySet())) { - if (SIGNER_FILES_P.matcher(file) + Map metainf = getDirectory("META-INF"); + if (metainf != null) { + List signing = metainf.keySet() + .stream() + .filter(path -> METAINF_SIGNING_P.matcher(path) .matches()) - remove(file); + .collect(toList()); + for (String path : signing) { + remove(path); } } } diff --git a/biz.aQute.bndlib/src/aQute/bnd/signing/JartoolSigner.java b/biz.aQute.bndlib/src/aQute/bnd/signing/JartoolSigner.java index 2158ce1034..28bc8e9196 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/signing/JartoolSigner.java +++ b/biz.aQute.bndlib/src/aQute/bnd/signing/JartoolSigner.java @@ -1,11 +1,13 @@ package aQute.bnd.signing; +import static aQute.bnd.osgi.Jar.METAINF_SIGNING_P; + import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; +import java.util.jar.JarFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,8 +103,6 @@ public void setRegistry(Registry registry) { processor = registry.getPlugin(Processor.class); } - private static Pattern SIGNING_P = Pattern.compile("META-INF/([^/]*\\.(DSA|RSA|EC|SF|MF)|SIG-[^/]*)"); - @Override public void sign(Builder builder, String alias) throws Exception { File f = builder.getFile(keystore); @@ -188,7 +188,7 @@ public void sign(Builder builder, String alias) throws Exception { builder.addClose(signed); MapStream.of(signed.getDirectory("META-INF")) - .filterKey(path -> SIGNING_P.matcher(path) + .filterKey(path -> JarFile.MANIFEST_NAME.equals(path) || METAINF_SIGNING_P.matcher(path) .matches()) .forEachOrdered(jar::putResource); jar.setDoNotTouchManifest();