diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 311e94b..d0d8d62 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-serialization:1.6.10") implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.1") implementation("com.google.code.gson:gson:2.8.9") + implementation("org.bouncycastle:bcprov-jdk15on:1.70") } java.sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SetupPaperServer.kt b/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SetupPaperServer.kt index 4ff9650..84ccda1 100644 --- a/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SetupPaperServer.kt +++ b/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SetupPaperServer.kt @@ -59,14 +59,11 @@ open class SetupPaperServer : DefaultTask() { val build = builds.last() val download = build.downloads["application"]!! val url = paperVersionClient.resolveDownloadUrl(build, download) - - ant.invokeMethod( - "get", mapOf( - "src" to url.toString(), - "dest" to paperJarFile.absolutePath - ) - ) - - logger.lifecycle("Installed Paper Server ${build.version} build ${build.build}") + val downloader = SmartDownload(paperJarFile.toPath(), url, download.sha256) + if (downloader.download()) { + logger.lifecycle("Installed Paper Server ${build.version} build ${build.build}") + } else { + logger.lifecycle("Paper Server ${build.version} build ${build.build} is up-to-date") + } } } diff --git a/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SmartDownload.kt b/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SmartDownload.kt new file mode 100644 index 0000000..5c98057 --- /dev/null +++ b/buildSrc/src/main/kotlin/cloud/kubelet/foundation/gradle/SmartDownload.kt @@ -0,0 +1,62 @@ +package cloud.kubelet.foundation.gradle + +import java.net.URI +import java.nio.file.Files +import java.nio.file.Path +import java.security.MessageDigest + +class SmartDownload(val localFilePath: Path, val remoteDownloadUrl: URI, val sha256: String) { + fun download(): Boolean { + if (!checkLocalFileHash()) { + downloadRemoteFile() + return true + } + return false + } + + private fun downloadRemoteFile() { + val url = remoteDownloadUrl.toURL() + val remoteFileStream = url.openStream() + val localFileStream = Files.newOutputStream(localFilePath) + remoteFileStream.transferTo(localFileStream) + if (!checkLocalFileHash()) { + throw RuntimeException("Download of ${remoteDownloadUrl} did not result in valid hash.") + } + } + + private fun checkLocalFileHash(): Boolean { + if (!Files.exists(localFilePath)) { + return false + } + + val digest = MessageDigest.getInstance("SHA-256") + val localFileStream = Files.newInputStream(localFilePath) + val buffer = ByteArray(16 * 1024) + + while (true) { + val size = localFileStream.read(buffer) + if (size <= 0) { + break + } + + val bytes = buffer.take(size).toByteArray() + digest.update(bytes) + } + + val sha256Bytes = digest.digest() + val localSha256Hash = bytesToHex(sha256Bytes) + return localSha256Hash.equals(sha256, ignoreCase = true) + } + + private fun bytesToHex(hash: ByteArray): String { + val hexString = StringBuilder(2 * hash.size) + for (i in hash.indices) { + val hex = Integer.toHexString(0xff and hash[i].toInt()) + if (hex.length == 1) { + hexString.append('0') + } + hexString.append(hex) + } + return hexString.toString() + } +}