/******************************************************************************* * Copyright (c) 2007, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.p2.jarprocessor.unsigner; import java.io.*; import java.util.Enumeration; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.zip.*; /** * This class removes the signature files from a jar and clean up the manifest. */ public class Unsigner { private static final String META_INF = "META-INF"; //$NON-NLS-1$ private static final String DSA_EXT = ".DSA"; //$NON-NLS-1$ private static final String RSA_EXT = ".RSA"; //$NON-NLS-1$ private static final String SF_EXT = ".SF"; //$NON-NLS-1$ private static final String META_INF_PREFIX = META_INF + '/'; private String[] signers; private File jarFile; private boolean keepManifestContent = false; private boolean isSigned(File file) { ZipFile jar = null; try { jar = new ZipFile(file); if (signers != null) { for (int i = 0; i < signers.length; i++) { if (jar.getEntry((META_INF_PREFIX + signers[i] + SF_EXT).toUpperCase()) != null) return true; } } else { Enumeration entries = jar.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); String entryName = entry.getName(); if(entryName.endsWith(SF_EXT) && entryName.startsWith(META_INF)) return true; } } return false; } catch (ZipException e) { return false; } catch (IOException e) { return false; } finally { if (jar != null) try { jar.close(); } catch (IOException e) { //Ignore } } } public void execute() { processJar(jarFile); } private void processJar(File inputFile) { if (!isSigned(inputFile)) return; try { ZipInputStream input = new ZipInputStream(new BufferedInputStream(new FileInputStream(inputFile))); File outputFile = File.createTempFile("removing.", ".signature", inputFile.getParentFile()); //$NON-NLS-1$ //$NON-NLS-2$ ZipOutputStream output = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile))); ZipEntry inputZe = input.getNextEntry(); byte[] b = new byte[8192]; while (inputZe != null) { byte remove = shouldRemove(inputZe); if (remove == 2) { inputZe = input.getNextEntry(); continue; } //copy the file or modify the manifest.mf if (remove == 1) { output.putNextEntry(new ZipEntry(inputZe.getName())); Manifest m = new Manifest(); m.read(input); m.getEntries().clear(); //This is probably not subtle enough m.write(output); } else { output.putNextEntry(inputZe); while (input.available() != 0) { int read = input.read(b); if (read != -1) output.write(b, 0, read); } } output.closeEntry(); input.closeEntry(); inputZe = input.getNextEntry(); } output.close(); input.close(); inputFile.delete(); outputFile.renameTo(inputFile); } catch (FileNotFoundException e) { //this can't happen we have checked before } catch (IOException e) { e.printStackTrace(); } } private byte shouldRemove(ZipEntry entry) { String entryName = entry.getName(); if(keepManifestContent == false && entryName.equalsIgnoreCase(JarFile.MANIFEST_NAME)) { return 1; } if (signers != null) { for (int i = 0; i < signers.length; i++) { if (entryName.equalsIgnoreCase(META_INF_PREFIX + signers[i] + SF_EXT) || entryName.equalsIgnoreCase(META_INF_PREFIX + signers[i] + RSA_EXT) || entryName.equalsIgnoreCase(META_INF_PREFIX + signers[i] + DSA_EXT)) return 2; } } else { if (entryName.startsWith(META_INF) && (entryName.endsWith(SF_EXT) || entryName.endsWith(RSA_EXT) || entryName.endsWith(DSA_EXT))) return 2; } return 0; } public void setRemoveSigners(String[] fileName) { signers = fileName; } public void setJar(File file) { jarFile = file; } public void setKeepManifestEntries(boolean keep) { keepManifestContent = keep; } }