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);
}
}
}