Skip to content

Commit

Permalink
Merge pull request #571 from alvasw/refactor_gradle_electrum_downloader
Browse files Browse the repository at this point in the history
Generalize binary downloader/verifier
  • Loading branch information
alvasw authored Nov 29, 2022
2 parents 2562562 + 70614c4 commit 695ee02
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 264 deletions.
Original file line number Diff line number Diff line change
@@ -1,83 +1,23 @@
package bisq.gradle.electrum

import bisq.gradle.electrum.tasks.DownloadElectrumBinariesTask
import bisq.gradle.electrum.tasks.ExtractElectrumAppFromDmgFile
import bisq.gradle.electrum.tasks.VerifyElectrumBinariesTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.register
import java.util.*


class BisqElectrumPlugin : Plugin<Project> {

companion object {
private const val DATA_DIR = "electrum_binaries"
private const val DOWNLOADS_DIR = "$DATA_DIR/downloads"
private const val BINARIES_DIR = "$DATA_DIR/binaries"
const val DATA_DIR = "electrum_binaries"
}

override fun apply(project: Project) {
val extension = project.extensions.create<BisqElectrumPluginExtension>("electrum")

val downloadTask: TaskProvider<DownloadElectrumBinariesTask> =
project.tasks.register<DownloadElectrumBinariesTask>("downloadElectrumBinaries") {
electrumVersion.set(extension.version)
val electrumBinaryDownloader = ElectrumBinaryDownloader(project, extension)
electrumBinaryDownloader.registerTasks()

binaryHashes.appImageHash.set(extension.appImageHash)
binaryHashes.dmgHash.set(extension.dmgHash)
binaryHashes.exeHash.set(extension.exeHash)

outputDir.set(project.layout.buildDirectory.dir(DOWNLOADS_DIR))
}

val verifyElectrumBinariesTask: TaskProvider<VerifyElectrumBinariesTask> =
project.tasks.register<VerifyElectrumBinariesTask>("verifyElectrumBinaries") {
electrumVersion.set(extension.version)

val downloadsDirectory: Provider<Directory> = downloadTask.flatMap { it.outputDir }
inputDirectory.set(downloadsDirectory)

outputDirectory.set(project.layout.buildDirectory.dir(BINARIES_DIR))
}

var extractElectrumAppFromDmgFileTask: TaskProvider<ExtractElectrumAppFromDmgFile>? = null
if (isMacOs()) {
extractElectrumAppFromDmgFileTask =
project.tasks.register<ExtractElectrumAppFromDmgFile>("extractElectrumAppFromDmgFile") {
electrumVersion.set(extension.version)
inputDirectory.set(verifyElectrumBinariesTask.flatMap { it.inputDirectory })
outputDirectory.set(project.layout.buildDirectory.dir(BINARIES_DIR))
}
}

val packageElectrumBinariesTask: TaskProvider<Zip> =
project.tasks.register<Zip>("packageElectrumBinaries") {

if (isMacOs()) {
dependsOn(extractElectrumAppFromDmgFileTask)
}

archiveFileName.set("electrum-binaries.zip")
destinationDirectory.set(project.layout.buildDirectory.dir("generated/src/main/resources"))

val binariesDir: Provider<Directory> = verifyElectrumBinariesTask.flatMap { it.outputDirectory }
from(binariesDir)
}

val processResourcesTask = project.tasks.named("processResources")
processResourcesTask.configure {
dependsOn(packageElectrumBinariesTask)
}
}

private fun isMacOs(): Boolean {
val osName: String = System.getProperty("os.name").toLowerCase(Locale.US)
return osName.contains("mac") || osName.contains("darwin")
val electrumBinaryPackager = ElectrumBinaryPackager(project, electrumBinaryDownloader)
electrumBinaryPackager.registerTasks()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package bisq.gradle.electrum

import bisq.gradle.electrum.tasks.DownloadTask
import bisq.gradle.electrum.tasks.FileVerificationTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.register

class ElectrumBinaryDownloader(
private val project: Project,
private val pluginExtension: BisqElectrumPluginExtension
) {

companion object {
private const val ELECTRUM_WEBSITE_URL = "https://download.electrum.org"
private const val DOWNLOADS_DIR = "${BisqElectrumPlugin.DATA_DIR}/downloads"
}

private val taskDownloadDirectory: Provider<Directory> = project.layout.buildDirectory.dir(DOWNLOADS_DIR)

val binaryFile: RegularFile
get() = taskDownloadDirectory.get().file(getBinaryFileName())

lateinit var lastTask: TaskProvider<out Task>

fun registerTasks() {
val binaryDownloadTask: TaskProvider<DownloadTask> =
project.tasks.register<DownloadTask>("downloadElectrumBinary") {
downloadUrl.set(getBinaryDownloadUrl())
sha256hash.set(getBinaryHash())
downloadDirectory.set(taskDownloadDirectory)
}

val signatureDownloadTask: TaskProvider<DownloadTask> =
project.tasks.register<DownloadTask>("downloadElectrumSignature") {
downloadUrl.set(getSignatureDownloadUrl())
downloadDirectory.set(taskDownloadDirectory)
}

lastTask = project.tasks.register<FileVerificationTask>("verifyElectrumBinary") {
dependsOn(binaryDownloadTask, signatureDownloadTask)

fileToVerify.set(binaryDownloadTask.flatMap { it.outputFile })
detachedSignatureFile.set(signatureDownloadTask.flatMap { it.outputFile })
publicKeyUrls.set(getPublicKeyUrls())
publicKeyFingerprints.set(getPublicKeyFingerprints())
}
}

private fun getBinaryFileName(): String {
val electrumVersion: String = pluginExtension.version.get()
return when (getOS()) {
OS.LINUX -> "electrum-$electrumVersion-x86_64.AppImage"
OS.MAC_OS -> "electrum-$electrumVersion.dmg"
OS.WINDOWS -> "electrum-$electrumVersion.exe"
}
}

private fun getBinaryDownloadUrl(): String = "$ELECTRUM_WEBSITE_URL/${pluginExtension.version.get()}/" + getBinaryFileName()

private fun getSignatureDownloadUrl(): String = "${getBinaryDownloadUrl()}.asc"

private fun getBinaryHash(): Property<String> {
return when (getOS()) {
OS.LINUX -> pluginExtension.appImageHash
OS.MAC_OS -> pluginExtension.dmgHash
OS.WINDOWS -> pluginExtension.exeHash
}
}

private fun getPublicKeyUrls() =
setOf(
this::class.java.getResource("/ThomasV.asc")!!,

// Why failing signature check?
// this::class.java.getResource("/Emzy.asc")!!

this::class.java.getResource("/SomberNight.asc")!!
)

private fun getPublicKeyFingerprints(): Set<String> {
val fingerprints = setOf(
// ThomasV
"6694 D8DE 7BE8 EE56 31BE D950 2BD5 824B 7F94 70E6",
// Emzy
"9EDA FF80 E080 6596 04F4 A76B 2EBB 056F D847 F8A7",
// SomberNight
"0EED CFD5 CAFB 4590 6734 9B23 CA9E EEC4 3DF9 11DC"
)

return fingerprints.map { fingerprint ->
fingerprint.filterNot { it.isWhitespace() } // Remove all spaces
.toLowerCase()
}.toSet()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package bisq.gradle.electrum

import bisq.gradle.electrum.tasks.ExtractElectrumAppFromDmgFile
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.register

class ElectrumBinaryPackager(
private val project: Project,
private val binaryDownloader: ElectrumBinaryDownloader,
) {
companion object {
private const val BINARIES_DIR = "${BisqElectrumPlugin.DATA_DIR}/binaries"
}

private val binariesDir: Provider<Directory> = project.layout.buildDirectory.dir(BINARIES_DIR)

fun registerTasks() {
val extractDmgOrCopyTask: TaskProvider<out Task> =
if (isMacOS()) {
registerDmgExtractionTask()
} else {
registerVerifiedElectrumBinary()
}

extractDmgOrCopyTask.configure {
dependsOn(binaryDownloader.lastTask)
}

val packageElectrumBinariesTask: TaskProvider<Zip> =
project.tasks.register<Zip>("packageElectrumBinaries") {
dependsOn(extractDmgOrCopyTask)

archiveFileName.set("electrum-binaries.zip")
destinationDirectory.set(project.layout.buildDirectory.dir("generated/src/main/resources"))

from(binariesDir)
}

val processResourcesTask = project.tasks.named("processResources")
processResourcesTask.configure {
dependsOn(packageElectrumBinariesTask)
}
}

private fun isMacOS() = getOS() == OS.MAC_OS

private fun registerDmgExtractionTask(): TaskProvider<out Task> =
project.tasks.register<ExtractElectrumAppFromDmgFile>("extractElectrumAppFromDmgFile") {
dmgFile.set(binaryDownloader.binaryFile)
outputDirectory.set(binariesDir)
}

private fun registerVerifiedElectrumBinary(): TaskProvider<out Task> =
project.tasks.register<Copy>("copyVerifiedElectrumBinary") {
from(binaryDownloader.binaryFile.asFile.absolutePath)
into(binariesDir.get().asFile.absolutePath)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bisq.gradle.electrum

import java.util.*

enum class OS {
LINUX, MAC_OS, WINDOWS
}

fun getOS(): OS {
val osName = System.getProperty("os.name").toLowerCase(Locale.US)
if (isLinux(osName)) {
return OS.LINUX
} else if (isMacOs(osName)) {
return OS.MAC_OS
} else if (isWindows(osName)) {
return OS.WINDOWS
}

throw IllegalStateException("Running on unsupported OS: $osName")
}

private fun isLinux(osName: String): Boolean {
return osName.contains("linux")
}

private fun isMacOs(osName: String): Boolean {
return osName.contains("mac") || osName.contains("darwin")
}

private fun isWindows(osName: String): Boolean {
return osName.contains("win")
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class SignatureVerifier(
) {

fun verifySignature(
fileToVerify: File,
signatureFile: File,
fileToVerify: File
): Boolean {
Security.addProvider(BouncyCastleProvider())

Expand Down

This file was deleted.

Loading

0 comments on commit 695ee02

Please sign in to comment.