package info.u_team.u_team_core.util.verify;

import java.io.InputStream;
import java.nio.file.*;
import java.util.Optional;
import java.util.jar.*;
import java.util.stream.Stream;

import org.apache.logging.log4j.*;

import com.google.common.io.ByteStreams;

import net.minecraftforge.fml.common.CertificateHelper;
import net.minecraftforge.fml.loading.*;

public class JarSignVerifier {
	
	private static final Logger LOGGER = LogManager.getLogger("JarSignVerifier");
	
	public static void checkSigned(String modid) {
		final VerifyStatus status = verify(modid);
		if (status == VerifyStatus.SIGNED) {
			LOGGER.info("Mod " + modid + " is signed with a valid certificate.");
		} else if (status == VerifyStatus.UNSIGNED) {
			LOGGER.warn("---------------------------------------------------------------------------------");
			LOGGER.warn("Mod " + modid + " is not signed with a valid certificate but should be signed.");
			LOGGER.warn("Please download the mod only from trusted sources such as curseforge.com!");
			LOGGER.warn("---------------------------------------------------------------------------------");
		} else {
			LOGGER.info("Mod " + modid + " is loaded in dev environment.");
		}
	}
	
	public static VerifyStatus verify(String modid) {
		// We don't need to check sign in dev environment
		if (FMLLoader.getNaming().equals("mcp")) {
			return VerifyStatus.DEV;
		}
		
		final Path path = LoadingModList.get().getModFileById(modid).getFile().getFilePath();
		
		if (Files.isDirectory(path)) {
			return VerifyStatus.DEV;
		}
		
		try (final JarFile jarFile = new JarFile(path.toFile())) {
			
			// Get fingerprint from manifest
			final Optional<String> fingerPrintOptional = Optional.ofNullable(jarFile.getManifest().getMainAttributes().getValue("Fingerprint"));
			
			if (!fingerPrintOptional.isPresent()) {
				return VerifyStatus.UNSIGNED;
			}
			
			// Remove dots and make all characters lowercase
			final String fingerprint = fingerPrintOptional.get().replace(":", "").toLowerCase();
			
			try (Stream<JarEntry> entryStream = jarFile.stream()) {
				// Check sign on every class and on the manifest file
				if (entryStream.filter(entry -> entry.getName().endsWith(".class") || entry.getName().endsWith(".MF")).allMatch(entry -> {
					// Read everything so the certificate gets loaded but trash the input
					try (final InputStream stream = jarFile.getInputStream(entry)) {
						ByteStreams.toByteArray(stream);
					} catch (Exception ex) {
						return false;
					}
					// Check if finger print is valid
					return CertificateHelper.getFingerprints(entry.getCertificates()).stream().filter(fingerprint::equals).findAny().isPresent();
				})) {
					return VerifyStatus.SIGNED;
				}
			}
			return VerifyStatus.UNSIGNED;
		} catch (Exception ex) {
			return VerifyStatus.UNSIGNED;
		}
	}
	
	public static enum VerifyStatus {
		SIGNED,
		UNSIGNED,
		DEV;
	}
	
}

@@ -2101,38 +2101,64 @@
 ery 
-clas
+resource excluding directorie
 s and 
-on 
 the 
-manifest
+certificate
  file
+s
 %0A%09%09%09
@@ -2185,86 +2185,42 @@
 ter(
-entry -%3E entry.getName().endsWith(%22.class%22) %7C%7C entry.getName().endsWith(%22.MF%22)
+JarSignVerifier::checkEntryForSign
 ).al
@@ -2796,32 +2796,309 @@
 IGNED;%0A%09%09%7D%0A%09%7D%0A%09%0A
+%09private static boolean checkEntryForSign(JarEntry entry) %7B%0A%09%09if (entry.isDirectory()) %7B%0A%09%09%09return false;%0A%09%09%7D%0A%09%09final String name = entry.getName().toUpperCase();%0A%09%09return !name.endsWith(%22.SF%22) && !name.endsWith(%22.DSA%22) && !name.endsWith(%22.EC%22) && !name.endsWith(%22.RSA%22);%0A%09%7D%0A%09%0A
 %09public static e

Fix #33 to check all entries now