package com.limegroup.gnutella.malware; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; import org.limewire.bittorrent.bencoding.Token; import org.limewire.io.IOUtils; import org.limewire.util.Base32; import org.limewire.util.BEncoder; import org.limewire.util.StringUtils; /** * Encoder for the base32-encoded, deflated, bencoded string that defines * dangerous file types for the FileExtensionChecker. The bencoded data * consists of a map with two keys, "m" and "e", which point to two lists of * equal length. Each element of the "m" list is a lowercase UTF-8 string * containing the mime type of a dangerous file type. The corresponding element * in the "e" list is a list of file extensions, in lowercase UTF-8, without * leading dots. A file is misnamed if it has a mime type that indicates a * dangerous file type but does not have one of the extensions corresponding * to that type. */ class FileExtensionEncoder { /** * Encodes the dangerous file types defined in DangerousFileType and prints * the resulting string. When file types are added or modified, run this * method to generate the new setting. */ public static void main(String[] args) { try { String setting = encodeSetting(DangerousFileType.getKnownTypes()); decodeSetting(setting); System.out.println(setting); } catch(IOException e) { System.err.println("Setting could not be encoded: " + e); System.exit(1); } catch(IllegalArgumentException e) { System.err.println("Setting could not be decoded: " + e); System.exit(2); } } /** * Encodes a string defining dangerous file types. */ protected static String encodeSetting(DangerousFileType[] types) throws IOException { List<String> mime = new ArrayList<String>(); List<List<String>> ext = new ArrayList<List<String>>(); HashMap<String, List<?>> payload = new HashMap<String, List<?>>(); payload.put("m", mime); payload.put("e", ext); for(DangerousFileType d : types) { mime.add(d.mimeType); ext.add(Arrays.asList(d.extensions)); } ByteArrayOutputStream zipped = new ByteArrayOutputStream(); DeflaterOutputStream zip = new DeflaterOutputStream(zipped); try { BEncoder.getEncoder(zip, true, false, "UTF-8").encodeDict(payload); zip.flush(); } finally { IOUtils.close(zip); } return Base32.encode(zipped.toByteArray()); } /** * Decodes a string defining dangerous file types. */ protected static DangerousFileType[] decodeSetting(String setting) throws IllegalArgumentException { try { ByteArrayInputStream zipped = new ByteArrayInputStream(Base32.decode(setting)); InflaterInputStream unzip = new InflaterInputStream(zipped); ReadableByteChannel byteChannel = Channels.newChannel(unzip); Object bencoded = Token.parse(byteChannel, "UTF-8"); Map<?, ?> map = (Map<?, ?>)bencoded; List<?> m = (List<?>)map.get("m"); List<?> e = (List<?>)map.get("e"); DangerousFileType[] types = new DangerousFileType[m.size()]; for(int i = 0; i < types.length; i++) { String mime = StringUtils.getUTF8String((byte[])m.get(i)); List<?> extList = (List<?>)e.get(i); String[] ext = new String[extList.size()]; for(int j = 0; j < ext.length; j++) { ext[j] = StringUtils.getUTF8String((byte[])extList.get(j)); } types[i] = new DangerousFileType(mime, ext); } return types; } catch(Throwable t) { // The setting isn't formatted correctly throw new IllegalArgumentException(t); } } }