mirror of
https://github.com/sparrowwallet/signpackage.git
synced 2024-12-25 13:26:45 +00:00
Initial checkin
This commit is contained in:
commit
e8028654ff
3 changed files with 200 additions and 0 deletions
3
build.sh
Normal file
3
build.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
mvn clean compile assembly:single
|
||||
cp target/SignPackage-1.0-jar-with-dependencies.jar ./SignPackage.jar
|
72
pom.xml
Normal file
72
pom.xml
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.dgunia</groupId>
|
||||
<artifactId>SignPackage</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.3.61</kotlin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.zeroturnaround</groupId>
|
||||
<artifactId>zt-zip</artifactId>
|
||||
<version>1.11</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.dgunia.signpackage.MainKt</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
125
src/main/java/com/dgunia/signpackage/Main.kt
Normal file
125
src/main/java/com/dgunia/signpackage/Main.kt
Normal file
|
@ -0,0 +1,125 @@
|
|||
package com.dgunia.signpackage
|
||||
|
||||
import org.apache.commons.cli.CommandLine
|
||||
import org.apache.commons.cli.DefaultParser
|
||||
import org.apache.commons.cli.Option
|
||||
import org.apache.commons.cli.Options
|
||||
import org.zeroturnaround.zip.ZipUtil
|
||||
import java.io.File
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
SignPackage(args).run()
|
||||
}
|
||||
|
||||
class SignPackage(val args: Array<String>) {
|
||||
val tmpDir = File("tmpdir${System.currentTimeMillis()}")
|
||||
val threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
|
||||
|
||||
private val OPTION_DIR = "d"
|
||||
private val OPTION_SIGN_KEY = "k"
|
||||
private val OPTION_ENTITLEMENTS = "e"
|
||||
private val OPTION_RUNTIME = "r"
|
||||
private val OPTION_TIMESTAMP = "t"
|
||||
private val OPTION_EXCLUDE = "x"
|
||||
private var excludedFiles: Array<String> = emptyArray()
|
||||
|
||||
fun run() {
|
||||
val options = Options()
|
||||
options.addOption(Option.builder(OPTION_DIR).longOpt("dir").desc("Directory to scan recursively").hasArg().required().build())
|
||||
options.addOption(Option.builder(OPTION_SIGN_KEY).longOpt("signing-key").desc("Key name (e.g. Developer ID Application: John Public (xxxxxxxxxxx))").hasArg().required().build())
|
||||
options.addOption(Option.builder(OPTION_ENTITLEMENTS).longOpt("entitlements").desc("Entitlements file").hasArg().build())
|
||||
options.addOption(Option.builder(OPTION_RUNTIME).longOpt("runtime").desc("Harden using runtime parameter").build())
|
||||
options.addOption(Option.builder(OPTION_TIMESTAMP).longOpt("timestamp").desc("Set secure timestamp using timestamp parameter").build())
|
||||
options.addOption(Option.builder(OPTION_EXCLUDE).longOpt("exclude").hasArgs().desc("Set secure timestamp using timestamp parameter").build())
|
||||
|
||||
val parser = DefaultParser()
|
||||
try {
|
||||
val cmd = parser.parse(options, args)
|
||||
|
||||
// Create a temporary directory
|
||||
if (!tmpDir.mkdirs()) {
|
||||
System.err.println("Could not create directory ${tmpDir.name}.")
|
||||
return
|
||||
}
|
||||
tmpDir.deleteOnExit()
|
||||
|
||||
// Excluded files
|
||||
|
||||
if (cmd.hasOption(OPTION_EXCLUDE)) {
|
||||
excludedFiles = cmd.getOptionValues(OPTION_EXCLUDE)
|
||||
}
|
||||
|
||||
// Start scanning and signing the jar files
|
||||
scanRecursive(File(cmd.getOptionValue(OPTION_DIR)), cmd)
|
||||
threadPool.shutdown()
|
||||
threadPool.awaitTermination(1, TimeUnit.DAYS)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
tmpDir.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all files and subdirectories for files that have to be signed.
|
||||
*/
|
||||
private fun scanRecursive(dir: File, cmd: CommandLine) {
|
||||
dir.listFiles()?.forEach { file ->
|
||||
if (!excludedFiles.contains(file.path)) {
|
||||
if (file.isDirectory) {
|
||||
scanRecursive(file, cmd)
|
||||
} else if (file.name.endsWith(".jar")) {
|
||||
threadPool.submit {
|
||||
ZipFile(file).entries().asSequence().forEach { zipEntry ->
|
||||
if (zipEntry.name.endsWith(".dylib")) {
|
||||
// Extract, sign and compress the dylib file.
|
||||
println("${file.absolutePath}: ${zipEntry.name}")
|
||||
val dylibFile = File(tmpDir, File(zipEntry.name).name)
|
||||
ZipUtil.unpackEntry(file, zipEntry.name, dylibFile)
|
||||
signFile(dylibFile, cmd)
|
||||
ZipUtil.replaceEntry(file, zipEntry.name, dylibFile)
|
||||
}
|
||||
}
|
||||
|
||||
// Sign the jar file
|
||||
println(file.absolutePath)
|
||||
signFile(file, cmd)
|
||||
}
|
||||
} else if (file.name.endsWith(".dylib") || file.canExecute()) {
|
||||
println(file.absolutePath)
|
||||
threadPool.submit { signFile(file, cmd) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the file using codesign
|
||||
*/
|
||||
private fun signFile(dylibFile: File, cmd: CommandLine) {
|
||||
val command = ArrayList<String>()
|
||||
command.add("codesign")
|
||||
if (cmd.hasOption(OPTION_TIMESTAMP)) command.add("--timestamp")
|
||||
if (cmd.hasOption(OPTION_RUNTIME)) command.addAll(listOf("--options", "runtime"))
|
||||
if (cmd.hasOption(OPTION_ENTITLEMENTS)) command.addAll(listOf("--entitlements", File(cmd.getOptionValue(OPTION_ENTITLEMENTS)).absolutePath))
|
||||
command.addAll(listOf("--deep", "-vvv", "-f"))
|
||||
command.add("--sign")
|
||||
command.add(cmd.getOptionValue(OPTION_SIGN_KEY))
|
||||
command.add(dylibFile.absolutePath)
|
||||
|
||||
println(command.joinToString(" "))
|
||||
|
||||
val resultCode = ProcessBuilder()
|
||||
.directory(dylibFile.parentFile)
|
||||
.inheritIO()
|
||||
.command(command)
|
||||
.start()
|
||||
.waitFor()
|
||||
if (resultCode != 0) {
|
||||
throw Exception("Resultcode $resultCode when executing ${command.joinToString(" ")}")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue