More work

This commit is contained in:
Christian 2012-12-17 14:30:51 -05:00
parent 289ce3339a
commit 47dfd99d4f
4 changed files with 103 additions and 10 deletions

View file

@ -0,0 +1,24 @@
package cpw.mods.fml.common;
import java.io.File;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import cpw.mods.fml.common.event.FMLEvent;
public class FMLFingerprintViolationEvent extends FMLEvent {
public final boolean isDirectory;
public final Set<String> fingerprints;
public final File source;
public FMLFingerprintViolationEvent(boolean isDirectory, File source, ImmutableSet<String> fingerprints)
{
super();
this.isDirectory = isDirectory;
this.source = source;
this.fingerprints = fingerprints;
}
}

View file

@ -18,6 +18,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.security.cert.Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,6 +35,8 @@ import com.google.common.base.Throwables;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
@ -86,10 +89,13 @@ public class FMLModContainer implements ModContainer
.put(FMLServerStartedEvent.class, Mod.ServerStarted.class) .put(FMLServerStartedEvent.class, Mod.ServerStarted.class)
.put(FMLServerStoppingEvent.class, Mod.ServerStopping.class) .put(FMLServerStoppingEvent.class, Mod.ServerStopping.class)
.put(IMCEvent.class,Mod.IMCCallback.class) .put(IMCEvent.class,Mod.IMCCallback.class)
.put(FMLFingerprintViolationEvent.class, Mod.FingerprintWarning.class)
.build(); .build();
private static final BiMap<Class<? extends Annotation>, Class<? extends FMLEvent>> modTypeAnnotations = modAnnotationTypes.inverse(); private static final BiMap<Class<? extends Annotation>, Class<? extends FMLEvent>> modTypeAnnotations = modAnnotationTypes.inverse();
private String annotationDependencies; private String annotationDependencies;
private VersionRange minecraftAccepted; private VersionRange minecraftAccepted;
private boolean fingerprintNotPresent;
private Set<String> sourceFingerprints;
public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor) public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor)
@ -335,13 +341,6 @@ public class FMLModContainer implements ModContainer
return mc.getMetadata(); return mc.getMetadata();
} }
}); });
//TODO
// for (Object o : annotations.get(Block.class))
// {
// Field f = (Field) o;
// f.set(modInstance, GameRegistry.buildBlock(this, f.getType(), f.getAnnotation(Block.class)));
// }
} }
private void parseSimpleFieldAnnotation(SetMultimap<String, ASMData> annotations, String annotationClassName, Function<ModContainer, Object> retreiver) throws IllegalAccessException private void parseSimpleFieldAnnotation(SetMultimap<String, ASMData> annotations, String annotationClassName, Function<ModContainer, Object> retreiver) throws IllegalAccessException
@ -408,12 +407,39 @@ public class FMLModContainer implements ModContainer
ModClassLoader modClassLoader = event.getModClassLoader(); ModClassLoader modClassLoader = event.getModClassLoader();
modClassLoader.addFile(source); modClassLoader.addFile(source);
Class<?> clazz = Class.forName(className, true, modClassLoader); Class<?> clazz = Class.forName(className, true, modClassLoader);
ASMDataTable asmHarvestedAnnotations = event.getASMHarvestedData();
// TODO Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
asmHarvestedAnnotations.getAnnotationsFor(this); int len = 0;
if (certificates != null)
{
len = certificates.length;
}
Builder<String> certBuilder = ImmutableSet.<String>builder();
for (int i = 0; i < len; i++)
{
certBuilder.add(CertificateHelper.getFingerprint(certificates[i]));
}
sourceFingerprints = certBuilder.build();
String expectedFingerprint = (String) descriptor.get("certificateFingerprint");
if (expectedFingerprint != "" && !sourceFingerprints.contains(expectedFingerprint))
{
Level warnLevel = Level.SEVERE;
if (source.isDirectory())
{
warnLevel = Level.FINER;
}
FMLLog.log(warnLevel, "The mod %s is expecting signature %s for source %s, however there is no signature matching that description", getModId(), expectedFingerprint, source.getName());
}
annotations = gatherAnnotations(clazz); annotations = gatherAnnotations(clazz);
isNetworkMod = FMLNetworkHandler.instance().registerNetworkMod(this, clazz, event.getASMHarvestedData()); isNetworkMod = FMLNetworkHandler.instance().registerNetworkMod(this, clazz, event.getASMHarvestedData());
modInstance = clazz.newInstance(); modInstance = clazz.newInstance();
if (fingerprintNotPresent)
{
handleModStateEvent(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints)));
}
ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide()); ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide());
processFieldAnnotations(event.getASMHarvestedData()); processFieldAnnotations(event.getASMHarvestedData());
} }

View file

@ -100,6 +100,26 @@ public @interface Mod
* @return A string listing modids to exclude from loading with this mod. * @return A string listing modids to exclude from loading with this mod.
*/ */
String modExclusionList() default ""; String modExclusionList() default "";
/**
* Specifying this field allows for a mod to expect a signed jar with a fingerprint matching this value.
* The fingerprint should be SHA-1 encoded, lowercase with ':' removed. An empty value indicates that
* the mod is not expecting to be signed.
*
* Any incorrectness of the fingerprint, be it missing or wrong, will result in the {@link FingerprintWarning}
* method firing <i>prior to any other event on the mod</i>.
*
* @return A certificate fingerprint that is expected for this mod.
*/
String certificateFingerprint() default "";
/**
* Mark the designated method as to be called at if there is something wrong with the certificate fingerprint of
* the mod's jar, or it is missing, or otherwise a problem.
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface FingerprintWarning {}
/** /**
* Mark the designated method as being called at the "pre-initialization" phase * Mark the designated method as being called at the "pre-initialization" phase
* @author cpw * @author cpw

View file

@ -1,6 +1,8 @@
package cpw.mods.fml.common.event; package cpw.mods.fml.common.event;
import java.io.File; import java.io.File;
import java.security.CodeSource;
import java.security.cert.Certificate;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -88,4 +90,25 @@ public class FMLPreInitializationEvent extends FMLStateEvent
log.setParent(FMLLog.getLogger()); log.setParent(FMLLog.getLogger());
return log; return log;
} }
/**
* Retrieve the FML signing certificates, if any. Validate these against the
* published FML certificates in your mod, if you wish.
*
* @return Certificates used to sign FML and Forge
*/
public Certificate[] getFMLSigningCertificates()
{
CodeSource codeSource = getClass().getClassLoader().getParent().getClass().getProtectionDomain().getCodeSource();
Certificate[] certs = codeSource.getCertificates();
if (certs == null)
{
return new Certificate[0];
}
else
{
return certs;
}
}
} }