package dev.openrs2.asm.io import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.crypto.Pkcs12KeyStore import dev.openrs2.util.io.DeterministicJarOutputStream import dev.openrs2.util.io.entries import dev.openrs2.util.io.useTempFile import org.objectweb.asm.tree.ClassNode import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream import java.io.OutputStream import java.nio.file.Files import java.util.jar.JarInputStream import java.util.jar.Manifest public class SignedJarLibraryWriter( private val manifest: Manifest, private val keyStore: Pkcs12KeyStore ) : LibraryWriter { override fun write(output: OutputStream, classPath: ClassPath, classes: Iterable) { useTempFile(TEMP_PREFIX, JAR_SUFFIX) { unsignedJar -> Files.newOutputStream(unsignedJar).use { unsignedOutput -> ManifestJarLibraryWriter(manifest).write(unsignedOutput, classPath, classes) } ByteArrayOutputStream().use { signedOutput -> keyStore.signJar(unsignedJar, signedOutput) return ByteArrayInputStream(signedOutput.toByteArray()).use { signedInput -> repack(signedInput, output) } } } } private fun repack(input: InputStream, output: OutputStream) { JarInputStream(input).use { jarInput -> DeterministicJarOutputStream(output, jarInput.manifest).use { jarOutput -> for (entry in jarInput.entries) { jarOutput.putNextEntry(entry) jarInput.copyTo(jarOutput) } } } } private companion object { private const val TEMP_PREFIX = "tmp" private const val JAR_SUFFIX = ".jar" } }