From 7bf2a26fe402e033d3a4eb28cfae78e854ada3ab Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 10 Jul 2021 00:42:51 -0400 Subject: [PATCH] Sign MacOS Server JAR for Notarization (#15) * Initial test to sign a server jar for noterization * Update README and Build.yml * Remove no Tachidesk jar error --- .github/workflows/Build.yml | 22 ++---- README.md | 2 +- buildSrc/src/main/kotlin/TachideskTasks.kt | 70 ++++++++++++++++++- .../ca/gosyer/data/server/ServerService.kt | 14 ++-- src/main/kotlin/ca/gosyer/ui/main/main.kt | 10 +-- src/main/resources/values/values/strings.xml | 1 - 6 files changed, 83 insertions(+), 36 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index b7e9505e..0149838f 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -30,7 +30,13 @@ jobs: arch: x64 os: macOS-latest shell: bash - build: setupTachideskJar packageUberJarForCurrentOS + build: | + setupTachideskJar packageUberJarForCurrentOS \ + packageDmg notarizeDmg \ + -Pcompose.desktop.mac.sign=true \ + -Pcompose.desktop.mac.signing.identity=${{ secrets.APPLE_IDENTITY }} \ + -Pcompose.desktop.mac.notarization.appleID=${{ secrets.APPLE_ID }} \ + -Pcompose.desktop.mac.notarization.password=${{ secrets.APPLE_PASSWORD }} setupCl: ./scripts/SetupClUnix.sh - runtime: win-x64 @@ -67,20 +73,6 @@ jobs: security import certificate.p12 -k build.keychain -P ${{ secrets.APPLE_CERT_PASSWORD }} -T /usr/bin/codesign security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} build.keychain - - name: Build Mac Package - if: ${{ matrix.runtime == 'osx-x64' }} - uses: eskatos/gradle-command-action@v1 - with: - arguments: | - packageDmg notarizeDmg \ - -Pcompose.desktop.mac.sign=true \ - -Pcompose.desktop.mac.signing.identity=${{ secrets.APPLE_IDENTITY }} \ - -Pcompose.desktop.mac.notarization.appleID=${{ secrets.APPLE_ID }} \ - -Pcompose.desktop.mac.notarization.password=${{ secrets.APPLE_PASSWORD }} - wrapper-cache-enabled: true - dependencies-cache-enabled: true - configuration-cache-enabled: true - - name: Build rpm Package if: ${{ matrix.runtime == 'linux-centos-x64' }} uses: Syer10/CentOS-Java15-Action@v1 diff --git a/README.md b/README.md index e34d49ee..af3620ff 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Download the latest msi release from [the releases section](https://github.com/S 2. Add the Java Scoop bucket - `scoop bucket add java` 3. Install TachideskJUI - `scoop install tachideskjui` -### MacOS (x64, Java Included, Server not included) +### MacOS (x64, Java 8+ required for server) Download the latest dmg release from [the releases section](https://github.com/Suwayomi/TachideskJUI/releases). ### Debian based Linux (x64, Java 8+ required for server) diff --git a/buildSrc/src/main/kotlin/TachideskTasks.kt b/buildSrc/src/main/kotlin/TachideskTasks.kt index 41fb6c8b..88a8f6d3 100644 --- a/buildSrc/src/main/kotlin/TachideskTasks.kt +++ b/buildSrc/src/main/kotlin/TachideskTasks.kt @@ -10,6 +10,7 @@ import java.io.File import Config.tachideskVersion import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.tasks.bundling.Zip private const val tachideskGroup = "tachidesk" private const val downloadTask = "downloadTar" @@ -18,12 +19,27 @@ private const val androidScriptTask = "runGetAndroid" private const val setupCITask = "setupServerCI" private const val buildTachideskTask = "buildTachidesk" private const val copyTachideskJarTask = "copyTachidesk" +private const val extractTachideskJar = "extractJar" +private const val signTachideskJar = "signJar" +private const val zipTachideskJar = "zipJar" private const val deleteTmpFolderTask = "deleteTmp" private const val runAllTachideskTasks = "setupTachideskJar" private fun Task.onlyIfTachideskDoesntExist(rootDir: File) { onlyIf { !File(rootDir, "src/main/resources/Tachidesk.jar").exists() } } +private fun Task.onlyIfSigning(project: Project) { + with (project){ + onlyIf { + DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX + && isSigning(properties) + && !File(rootDir, "src/main/resources/Tachidesk.jar").exists() + } + } + +} + +private fun isSigning(properties: Map) = properties["compose.desktop.mac.sign"].toString() == "true" private fun Project.tmpDir() = File(rootDir, "tmp") @@ -99,13 +115,60 @@ fun TaskContainerScope.registerTachideskTasks(project: Project) { from(File(tmpDir(), "Tachidesk-${tachideskVersion.drop(1)}/server/build/")) include("Tachidesk-$tachideskVersion-r*.jar") - into(File(rootDir, "src/main/resources/")) + val os = DefaultNativePlatform.getCurrentOperatingSystem() + when { + os.isMacOsX && isSigning(properties) -> into(File(tmpDir(), "macos/")) + else -> into(File(rootDir, "src/main/resources/")) + } rename { "Tachidesk.jar" } } - register(deleteTmpFolderTask) { + register(extractTachideskJar) { + group = tachideskGroup mustRunAfter(copyTachideskJarTask) + onlyIfSigning(project) + + from(zipTree(File(tmpDir(), "macos/Tachidesk.jar"))) + into(File(tmpDir(), "macos/jar/")) + } + register(signTachideskJar) { + group = tachideskGroup + mustRunAfter(extractTachideskJar) + onlyIfSigning(project) + + doFirst { + File(tmpDir(), "macos/jar/").walkTopDown() + .asSequence() + .filter { it.extension.equals("dylib", true) || it.extension.equals("jnilib", true) } + .forEach { + exec { + commandLine( + "codesign", + "--deep", + "-vvv", + "-f", + "--sign", + properties["compose.desktop.mac.signing.identity"], + it.absolutePath + ) + } + } + } + } + register(zipTachideskJar) { + group = tachideskGroup + mustRunAfter(signTachideskJar) + onlyIfSigning(project) + + from(File(tmpDir(), "macos/jar/")) + archiveBaseName.set("Tachidesk") + archiveVersion.set("") + archiveExtension.set("jar") + destinationDirectory.set(File(rootDir, "src/main/resources/")) + } + register(deleteTmpFolderTask) { + mustRunAfter(zipTachideskJar) delete(tmpDir()) } register(runAllTachideskTasks) { @@ -118,6 +181,9 @@ fun TaskContainerScope.registerTachideskTasks(project: Project) { setupCITask, buildTachideskTask, copyTachideskJarTask, + extractTachideskJar, + signTachideskJar, + zipTachideskJar, deleteTmpFolderTask ) } diff --git a/src/main/kotlin/ca/gosyer/data/server/ServerService.kt b/src/main/kotlin/ca/gosyer/data/server/ServerService.kt index e417ceaa..b61aff5a 100644 --- a/src/main/kotlin/ca/gosyer/data/server/ServerService.kt +++ b/src/main/kotlin/ca/gosyer/data/server/ServerService.kt @@ -45,12 +45,12 @@ class ServerService @Inject constructor( } @Throws(IOException::class) - private fun copyJar(jarFile: File): Boolean { - return javaClass.getResourceAsStream("/Tachidesk.jar")?.buffered()?.use { input -> + private fun copyJar(jarFile: File) { + javaClass.getResourceAsStream("/Tachidesk.jar")?.buffered()?.use { input -> jarFile.outputStream().use { output -> input.copyTo(output) } - }?.let { true } ?: false + } } private fun getJavaFromPath(javaPath: File): String? { @@ -108,9 +108,7 @@ class ServerService @Inject constructor( val jarFile = File(userDataDir, "Tachidesk.jar") if (!jarFile.exists()) { info { "Copying server to resources" } - if (withIOContext { !copyJar(jarFile) }) { - initialized.value = ServerResult.NO_TACHIDESK_JAR - } + withIOContext { copyJar(jarFile) } } else { try { val jarVersion = withIOContext { @@ -121,9 +119,7 @@ class ServerService @Inject constructor( if (jarVersion != BuildConfig.TACHIDESK_SP_VERSION) { info { "Updating server file from resources" } - if (withIOContext { !copyJar(jarFile) }) { - initialized.value = ServerResult.NO_TACHIDESK_JAR - } + withIOContext { copyJar(jarFile) } } } catch (e: IOException) { error(e) { diff --git a/src/main/kotlin/ca/gosyer/ui/main/main.kt b/src/main/kotlin/ca/gosyer/ui/main/main.kt index 1b5c555e..6878db59 100644 --- a/src/main/kotlin/ca/gosyer/ui/main/main.kt +++ b/src/main/kotlin/ca/gosyer/ui/main/main.kt @@ -139,16 +139,10 @@ fun main() { ServerResult.STARTED, ServerResult.UNUSED -> { MainMenu(rootBundle) } - ServerResult.STARTING, ServerResult.FAILED, ServerResult.NO_TACHIDESK_JAR -> { + ServerResult.STARTING, ServerResult.FAILED -> { LoadingScreen( initialized == ServerResult.STARTING, - errorMessage = stringResource( - if (initialized == ServerResult.NO_TACHIDESK_JAR) { - "tachidesk_doesnt_exist" - } else { - "unable_to_start_server" - } - ), + errorMessage = stringResource("unable_to_start_server"), retryMessage = stringResource("action_start_anyway"), retry = serverService::startAnyway ) diff --git a/src/main/resources/values/values/strings.xml b/src/main/resources/values/values/strings.xml index ac7862e8..0b6a48d9 100644 --- a/src/main/resources/values/values/strings.xml +++ b/src/main/resources/values/values/strings.xml @@ -9,7 +9,6 @@ TachideskJUI - Tachidesk JAR does not exist, run Tachidesk yourself Cannot start server