    001package cpw.mods.fml.common.asm;
    002
    003import java.io.ByteArrayInputStream;
    004import java.io.InputStreamReader;
    005import java.io.ObjectInputStream.GetField;
    006import java.io.StringReader;
    007import java.net.JarURLConnection;
    008import java.nio.charset.Charset;
    009import java.security.CodeSource;
    010import java.security.cert.CertPath;
    011import java.security.cert.CertPathValidator;
    012import java.security.cert.Certificate;
    013import java.security.cert.CertificateFactory;
    014import java.security.cert.PKIXCertPathValidatorResult;
    015import java.security.cert.PKIXParameters;
    016import java.security.cert.TrustAnchor;
    017import java.security.cert.X509Certificate;
    018import java.util.Arrays;
    019import java.util.Collections;
    020import java.util.Map;
    021
    022import javax.swing.JOptionPane;
    023
    024import org.objectweb.asm.ClassReader;
    025import org.objectweb.asm.ClassVisitor;
    026import org.objectweb.asm.FieldVisitor;
    027import org.objectweb.asm.Opcodes;
    028
    029import cpw.mods.fml.common.CertificateHelper;
    030import cpw.mods.fml.common.FMLLog;
    031import cpw.mods.fml.relauncher.IFMLCallHook;
    032import cpw.mods.fml.relauncher.RelaunchClassLoader;
    033
    034public class FMLSanityChecker implements IFMLCallHook
    035{
    036    private static final String FMLFINGERPRINT = "AE:F6:54:79:96:E9:1B:D1:59:70:6C:B4:6B:F5:4A:89:C5:CE:08:1D".toLowerCase().replace(":","");
    037    private static final String FORGEFINGERPRINT = "DE:4C:F8:A3:F3:BC:15:63:58:10:04:4C:39:24:0B:F9:68:04:EA:7D".toLowerCase().replace(":", "");
    038    static class MLDetectorClassVisitor extends ClassVisitor
    039    {
    040        private boolean foundMarker = false;
    041        private MLDetectorClassVisitor()
    042        {
    043            super(Opcodes.ASM4);
    044        }
    045
    046        @Override
    047        public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4)
    048        {
    049            if ("fmlMarker".equals(arg1))
    050            {
    051                foundMarker = true;
    052            }
    053            return null;
    054        }
    055    }
    056
    057    private RelaunchClassLoader cl;
    058
    059    @Override
    060    public Void call() throws Exception
    061    {
    062        CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
    063        boolean goodFML = false;
    064        if (codeSource.getLocation().getProtocol().equals("jar"))
    065        {
    066            Certificate[] certificates = codeSource.getCertificates();
    067            if (certificates!=null)
    068            {
    069
    070                for (Certificate cert : certificates)
    071                {
    072                    String fingerprint = CertificateHelper.getFingerprint(cert);
    073                    if (fingerprint.equals(FMLFINGERPRINT))
    074                    {
    075                        FMLLog.info("Found valid fingerprint for FML. Certificate fingerprint %s", fingerprint);
    076                        goodFML = true;
    077                    }
    078                    else if (fingerprint.equals(FORGEFINGERPRINT))
    079                    {
    080                        FMLLog.info("Found valid fingerprint for Minecraft Forge. Certificate fingerprint %s", fingerprint);
    081                        goodFML = true;
    082                    }
    083                    else
    084                    {
    085                        FMLLog.severe("Found invalid fingerprint for FML: %s", fingerprint);
    086                    }
    087                }
    088            }
    089        }
    090        else
    091        {
    092            goodFML = true;
    093        }
    094        if (!goodFML)
    095        {
    096            FMLLog.severe("FML appears to be missing any signature data. This is not a good thing");
    097        }
    098        byte[] mlClass = cl.getClassBytes("ModLoader");
    099        // Only care in obfuscated env
    100        if (mlClass == null)
    101        {
    102            return null;
    103        }
    104        MLDetectorClassVisitor mlTester = new MLDetectorClassVisitor();
    105        ClassReader cr = new ClassReader(mlClass);
    106        cr.accept(mlTester, ClassReader.SKIP_CODE);
    107        if (!mlTester.foundMarker)
    108        {
    109            JOptionPane.showMessageDialog(null, "<html>CRITICAL ERROR<br/>" +
    110                    "ModLoader was detected in this environment<br/>" +
    111                        "ForgeModLoader cannot be installed alongside ModLoader<br/>" +
    112                        "All mods should work without ModLoader being installed<br/>" +
    113                        "Because ForgeModLoader is 100% compatible with ModLoader<br/>" +
    114                        "Re-install Minecraft Forge or Forge ModLoader into a clean<br/>" +
    115                        "jar and try again.",
    116                        "ForgeModLoader critical error",
    117                        JOptionPane.ERROR_MESSAGE);
    118            throw new RuntimeException("Invalid ModLoader class detected");
    119        }
    120        return null;
    121    }
    122
    123    @Override
    124    public void injectData(Map<String, Object> data)
    125    {
    126        cl = (RelaunchClassLoader) data.get("classLoader");
    127    }
    128
    129}