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}