    001    package cpw.mods.fml.common.asm;
    002
    003    import java.io.ByteArrayInputStream;
    004    import java.io.InputStreamReader;
    005    import java.io.ObjectInputStream.GetField;
    006    import java.io.StringReader;
    007    import java.net.JarURLConnection;
    008    import java.nio.charset.Charset;
    009    import java.security.CodeSource;
    010    import java.security.cert.CertPath;
    011    import java.security.cert.CertPathValidator;
    012    import java.security.cert.Certificate;
    013    import java.security.cert.CertificateFactory;
    014    import java.security.cert.PKIXCertPathValidatorResult;
    015    import java.security.cert.PKIXParameters;
    016    import java.security.cert.TrustAnchor;
    017    import java.security.cert.X509Certificate;
    018    import java.util.Arrays;
    019    import java.util.Collections;
    020    import java.util.Map;
    021
    022    import javax.swing.JOptionPane;
    023
    024    import org.objectweb.asm.ClassReader;
    025    import org.objectweb.asm.ClassVisitor;
    026    import org.objectweb.asm.FieldVisitor;
    027    import org.objectweb.asm.Opcodes;
    028
    029    import cpw.mods.fml.common.CertificateHelper;
    030    import cpw.mods.fml.common.FMLLog;
    031    import cpw.mods.fml.relauncher.IFMLCallHook;
    032    import cpw.mods.fml.relauncher.RelaunchClassLoader;
    033
    034    public 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    }