package net.i2p.router.web; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.lang.ClassLoader; import java.net.URL; import java.net.URLClassLoader; import java.security.MessageDigest; import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.jar.Attributes; import java.util.jar.Manifest; import net.i2p.crypto.SHA256Generator; import net.i2p.data.DataHelper; import net.i2p.util.FileUtil; /** * Dump info on jars and wars * * @since 0.8.13 */ public class FileDumpHelper extends HelperBase { public String getFileSummary() { StringBuilder buf = new StringBuilder(16*1024); buf.append("<table><tr><th>File</th><th>Size</th><th>Date</th><th>SHA 256</th><th>Revision</th>" + "<th>JDK</th><th>Built</th><th>By</th><th>Mods</th></tr>"); // jars added in wrapper.config ClassLoader loader = ClassLoader.getSystemClassLoader(); if (loader instanceof URLClassLoader) { // through Java 8, not available in Java 9 URLClassLoader urlClassLoader = (URLClassLoader) loader; URL[] urls = urlClassLoader.getURLs(); List<File> flist = new ArrayList<File>(); for (int i = 0; i < urls.length; i++) { String p = urls[i].toString(); if (p.startsWith("file:") && p.endsWith(".jar")) { p = p.substring(5); if (!(p.startsWith(_context.getBaseDir().getAbsolutePath()) || p.startsWith(_context.getConfigDir().getAbsolutePath()))) { flist.add(new File(p)); } } } Collections.sort(flist); for (File f : flist) { dumpFile(buf, f); } } // our jars File dir = new File(_context.getBaseDir(), "lib"); dumpDir(buf, dir, ".jar"); // our wars dir = new File(_context.getBaseDir(), "webapps"); dumpDir(buf, dir, ".war"); // plugins File pluginDir = new File(_context.getConfigDir(), PluginStarter.PLUGIN_DIR); File[] files = pluginDir.listFiles(); if (files != null) { Arrays.sort(files); for (int i = 0; i < files.length; i++) { dir = new File(files[i], "lib"); dumpDir(buf, dir, ".jar"); dir = new File(files[i], "console/webapps"); dumpDir(buf, dir, ".war"); } } buf.append("</table>"); return buf.toString(); } private static void dumpDir(StringBuilder buf, File dir, String suffix) { File[] files = dir.listFiles(); if (files == null) return; Arrays.sort(files); for (int i = 0; i < files.length; i++) { if (files[i].getName().endsWith(suffix)) dumpFile(buf, files[i]); } } private static void dumpFile(StringBuilder buf, File f) { buf.append("<tr><td><b>").append(f.getAbsolutePath()).append("</b></td>" + "<td align=\"right\">").append(f.length()).append("</td>" + "<td>"); long mod = f.lastModified(); if (mod > 0) buf.append((new Date(mod)).toString()); else buf.append("<font color=\"red\">Not found</font>"); buf.append("</td><td align=\"center\">"); if (mod > 0 && !FileUtil.verifyZip(f)) buf.append("<font color=\"red\">CORRUPT</font><br>"); byte[] hash = sha256(f); if (hash != null) { byte[] hh = new byte[16]; System.arraycopy(hash, 0, hh, 0, 16); buf.append("<tt>"); String p1 = DataHelper.toHexString(hh); for (int i = p1.length(); i < 32; i++) { buf.append('0'); } buf.append(p1).append("</tt><br>"); System.arraycopy(hash, 16, hh, 0, 16); buf.append("<tt>").append(DataHelper.toHexString(hh)).append("</tt>"); } Attributes att = attributes(f); if (att == null) att = new Attributes(); buf.append("<td align=\"center\">"); String iv = getAtt(att, "Implementation-Version"); if (iv != null) buf.append("<b>").append(iv).append("</b>"); String s = getAtt(att, "Base-Revision"); if (s != null && s.length() > 20) { if (iv != null) buf.append("<br>"); // fix and uncomment if a reliable viewmtn host appears //buf.append("<a href=\"http://killyourtv.i2p/viewmtn/revision/info/").append(s) // .append("\">"); buf.append("<tt>").append(s.substring(0, 20)).append("</tt>" + "<br>" + "<tt>").append(s.substring(20)).append("</tt>"); //buf.append("</tt>"); } buf.append("</td><td>"); s = getAtt(att, "Created-By"); if (s != null) buf.append(s); buf.append("</td><td>"); s = getAtt(att, "Build-Date"); if (s != null) buf.append(s); buf.append("</td><td align=\"center\">"); s = getAtt(att, "Built-By"); if (s != null) buf.append(s); buf.append("</td><td><font color=\"red\">"); s = getAtt(att, "Workspace-Changes"); if (s != null) buf.append(s.replace(",", "<br>")); buf.append("</font></td></tr>\n"); } private static byte[] sha256(File f) { InputStream in = null; try { in = new FileInputStream(f); MessageDigest md = SHA256Generator.getDigestInstance(); byte[] b = new byte[4096]; int cnt = 0; while ((cnt = in.read(b)) >= 0) { md.update(b, 0, cnt); } return md.digest(); } catch (IOException ioe) { //ioe.printStackTrace(); return null; } finally { if (in != null) try { in.close(); } catch (IOException e) {} } } private static Attributes attributes(File f) { InputStream in = null; try { in = (new URL("jar:file:" + f.getAbsolutePath() + "!/META-INF/MANIFEST.MF")).openStream(); Manifest man = new Manifest(in); return man.getMainAttributes(); } catch (IOException ioe) { //ioe.printStackTrace(); return null; } finally { if (in != null) try { in.close(); } catch (IOException e) {} } } private static String getAtt(Attributes atts, String s) { String rv = atts.getValue(s); if (rv != null) rv = DataHelper.stripHTML(rv); return rv; } }