package openeye.logic;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ProtocolException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.world.World;
import net.minecraft.world.storage.ISaveHandler;
import openeye.Log;
import openeye.logic.Sanitizer.ITransformer;
public class Sanitizers {
public static final int PRIORITY_SAVE_DIR = 1300;
public static final int PRIORITY_MINECRAFT_DIR = 1200;
public static final int PRIORITY_WORK_DIR = 1100;
public static final int PRIORITY_HOME = 1000;
public static final int PRIORITY_SAVE_DIR_NAME = 900;
public static final int PRIORITY_WORLD_NAME = 800;
public static final int PRIORITY_LOCAL_IP = 700;
public static final int PRIORITY_IP_PORT = 600;
public static final int PRIORITY_LOCAL_HOST = 500;
public static final int PRIORITY_LOCAL_PLAYER = 400;
public static final int PRIORITY_PLAYER_NAME = 300;
public static final int PRIORITY_PLAYER_ID = 200;
public static final int PRIORITY_SYSTEM_USER = 100;
static class SimpleReplace implements ITransformer {
private final String target;
private final String value;
public SimpleReplace(String target, String value) {
this.target = target;
this.value = value;
}
@Override
public String transform(String input) {
return input.replace(target, value);
}
@Override
public String toString() {
return String.format("'%s'->'%s'", target, value);
}
}
private static class PropertyReplace extends Sanitizers.SimpleReplace {
public PropertyReplace(String property, String value) {
super(System.getProperty(property), value);
}
}
private static class PathReplace implements ITransformer {
private final String targetNormal;
private final String targetReversed;
private final String targetDoubled;
private final String value;
public PathReplace(String target, String value) {
this.targetNormal = target;
if (File.separatorChar == '\\') {
targetReversed = targetNormal.replace('\\', '/');
targetDoubled = targetNormal.replace("\\", "\\\\");
} else if (File.separatorChar == '/') {
targetReversed = targetNormal.replace('/', '\\');
targetDoubled = targetNormal.replace("/", "\\\\");
} else {
targetReversed = null;
targetDoubled = null;
}
this.value = value;
}
@Override
public String transform(String input) {
input = input.replace(targetNormal, value);
if (targetReversed != null) input = input.replace(targetReversed, value);
if (targetDoubled != null) input = input.replace(targetDoubled, value);
return input;
}
@Override
public String toString() {
return String.format("path '%s'->'%s'", targetNormal, value);
}
}
private static class SimpleRegexReplace implements ITransformer {
private final Pattern pattern;
private final String replacement;
public SimpleRegexReplace(String pattern, String replacement) {
this.pattern = Pattern.compile(pattern);
this.replacement = replacement;
}
@Override
public String transform(String input) {
Matcher match = pattern.matcher(input);
return match.replaceAll(replacement);
}
@Override
public String toString() {
return "regex: " + replacement;
}
}
private static final Set<String> ALREADY_REPLACED = Sets.newHashSet();
private static final Set<String> DONT_REPLACE = Sets.newHashSet();
static {
DONT_REPLACE.add("player");
DONT_REPLACE.add("MpServer");
DONT_REPLACE.add("none");
DONT_REPLACE.add("null");
}
private static final Map<Class<? extends Throwable>, Sanitizer> THROWABLE_SANITIZERS = Maps.newHashMap();
public static final Sanitizer mainSanitizer = new Sanitizer();
public static void addThrowableSanitizer(Class<? extends Throwable> cls, Sanitizer sanitizer) {
THROWABLE_SANITIZERS.put(cls, sanitizer);
}
public static Sanitizer getSanitizerForThrowable(Class<? extends Throwable> cls) {
Sanitizer result = THROWABLE_SANITIZERS.get(cls);
return result != null? result : mainSanitizer;
}
public static ITransformer path(String target, String value) {
if (!Strings.isNullOrEmpty(target)) return new PathReplace(target, value);
return null;
}
public static ITransformer pathNoDuplicate(String target, String value) {
if (!Strings.isNullOrEmpty(target) && !ALREADY_REPLACED.contains(target)) {
ALREADY_REPLACED.add(target);
return new PathReplace(target, value);
}
return null;
}
public static ITransformer replace(Object target, String value) {
if (target != null) {
String s = target.toString();
if (s != null && s.length() > 2 && !DONT_REPLACE.contains(s)) return new Sanitizers.SimpleReplace(s, value);
}
return null;
}
public static ITransformer replaceNoDuplicates(Object target, String value) {
if (target != null) {
String s = target.toString();
if (s != null && s.length() > 2 && !ALREADY_REPLACED.contains(s) && !DONT_REPLACE.contains(s)) {
ALREADY_REPLACED.add(s);
return new Sanitizers.SimpleReplace(s, value);
}
}
return null;
}
private static void addLocalAddresses() {
Set<String> ips = Sets.newHashSet();
Set<String> hosts = Sets.newHashSet();
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface intf = interfaces.nextElement();
Enumeration<InetAddress> addresses = intf.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address != null) {
ips.add(address.getHostAddress());
String host = address.getHostName();
if (!ips.contains(host)) hosts.add(host);
}
}
}
} catch (Throwable t) {
Log.warn(t, "Failed to get local IP adresses for sanitization");
}
for (String ip : ips)
mainSanitizer.addPre(PRIORITY_LOCAL_IP, replace(ip, "[local ip]"));
for (String host : hosts)
mainSanitizer.addPre(PRIORITY_LOCAL_HOST, replace(host, "[host]"));
mainSanitizer.addPre(PRIORITY_IP_PORT, new SimpleRegexReplace("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}[:~]\\d+", "[ip+port]"));
}
public static void addWorldNames(World world) {
final ISaveHandler saveHandler = world.getSaveHandler();
final File worldDirectory = saveHandler.getWorldDirectory();
if (worldDirectory != null) {
final String worldDir = worldDirectory.getName();
mainSanitizer.addPre(PRIORITY_SAVE_DIR_NAME, replaceNoDuplicates(worldDir, "[save dir]"));
}
try {
File dummy = saveHandler.getMapFileFromName("dummy");
if (dummy != null) {
String parent = dummy.getParentFile().getParent();
if (parent != null) mainSanitizer.addPre(PRIORITY_SAVE_DIR, pathNoDuplicate(parent, "[save dir]"));
}
} catch (Throwable t) {
Log.warn(t, "Failed to get sanitizer name for world");
}
String worldName = world.getWorldInfo().getWorldName();
mainSanitizer.addPre(PRIORITY_WORLD_NAME, replaceNoDuplicates(worldName, "[world name]"));
}
static {
addLocalAddresses();
mainSanitizer.addPre(PRIORITY_WORK_DIR, new PathReplace(System.getProperty("user.dir"), "[workdir]"));
mainSanitizer.addPre(PRIORITY_HOME, new PathReplace(System.getProperty("user.home"), "[home]"));
mainSanitizer.addPre(PRIORITY_SYSTEM_USER, new PropertyReplace("user.name", "[user]"));
Sanitizer ipSanitizer = new Sanitizer(mainSanitizer);
ipSanitizer.addPre(1000, new SimpleRegexReplace("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", "[ip]"));
addThrowableSanitizer(ProtocolException.class, ipSanitizer);
addThrowableSanitizer(UnknownHostException.class, ipSanitizer);
}
public static void addMinecraftPath(File mcLocation) {
mainSanitizer.addPre(PRIORITY_MINECRAFT_DIR, path(mcLocation.getAbsolutePath(), "[minecraft_dir]"));
}
public static void addPlayerName(String username) {
mainSanitizer.addPre(PRIORITY_LOCAL_PLAYER, Sanitizers.replace(username, "[local player]"));
}
}