add sha256sum checksum check to downloadFormUrl

This commit is contained in:
az 2021-08-25 19:10:54 +02:00
parent f518e00208
commit a0fde38bd2
9 changed files with 111 additions and 47 deletions

View file

@ -352,11 +352,10 @@ open class Prov protected constructor(
"============================================== "
)
for (result in internalResults) {
println(
result.toString().escapeNewline()
.replace("Success --", ANSI_BRIGHT_GREEN + "Success" + ANSI_RESET + " --")
.replace("FAILED --", ANSI_BRIGHT_RED + "FAILED" + ANSI_RESET + " --")
)
val outputLine = result.toString().escapeControlChars()
.replaceFirst("Success --", ANSI_BRIGHT_GREEN + "Success" + ANSI_RESET + " --")
.replaceFirst("FAILED --", ANSI_BRIGHT_RED + "FAILED" + ANSI_RESET + " --")
println(outputLine)
}
if (internalResults.size > 1) {
println("----------------------------------------------------------------------------------------------------- ")
@ -410,7 +409,7 @@ internal data class ResultLine(val level: Int, val method: String?, var provResu
return if (provResult != null) {
prefix(level) + (if (provResult.success) "Success -- " else "FAILED -- ") +
method + " " + (provResult.cmd ?: "") +
(if (!provResult.success && provResult.err != null) " -- Error: " + provResult.err.escapeNewline() else "")
(if (!provResult.success && provResult.err != null) " -- Error: " + provResult.err.escapeControlChars() else "")
} else
prefix(level) + method + " " + "... in progress ... "

View file

@ -40,7 +40,8 @@ fun getCallingMethodName(): String? {
}
fun String.escapeNewline(): String = this.replace("\r\n", "\\n").replace("\n", "\\n")
fun String.escapeNewline(): String = this.replace("\r", "\\r").replace("\n", "\\n")
fun String.escapeControlChars(): String = this.replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t").replace("[\\p{Cntrl}]".toRegex(), "\\?")
fun String.escapeBackslash(): String = this.replace("\\", "\\\\")
fun String.escapeDoubleQuote(): String = this.replace("\"", "\\\"")
fun String.escapeSingleQuote(): String = this.replace("'", "\'")

View file

@ -17,7 +17,7 @@ class UbuntuPlusUser(private val userName: String = "testuser") : DockerImage {
override fun imageText(): String {
return """
FROM ubuntu:18.04
FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive

View file

@ -2,29 +2,39 @@ package org.domaindrivenarchitecture.provs.extensions.workplace.base
import org.domaindrivenarchitecture.provs.core.Prov
import org.domaindrivenarchitecture.provs.core.ProvResult
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createDir
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createDirs
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createFile
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.userHome
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.*
import org.domaindrivenarchitecture.provs.ubuntu.install.base.aptInstall
import org.domaindrivenarchitecture.provs.ubuntu.install.base.isPackageInstalled
import org.domaindrivenarchitecture.provs.ubuntu.web.base.downloadFromURL
fun Prov.installGopass(version: String = "1.12.7", enforceVersion: Boolean = false) = def {
val sha256sum = "0824d5110ff1e68bff1ba10c1be63acb67cb1ad8e3bccddd6b6fc989608beca8" // checksum for sha256sum version 8.30 (e.g. ubuntu 20.04)
if (isPackageInstalled("gopass") && !enforceVersion) {
ProvResult(true)
} else {
return@def ProvResult(true)
}
if (checkGopassVersion(version)) {
return@def ProvResult(true, out = "Version $version of gopass is already installed.")
}
val path = "tmp"
// install required dependencies
aptInstall("rng-tools gnupg2 git")
aptInstall("curl")
sh(
"""
curl -L https://github.com/gopasspw/gopass/releases/download/v${version}/gopass_${version}_linux_amd64.deb -o gopass_${version}_linux_amd64.deb
sudo dpkg -i gopass_${version}_linux_amd64.deb
"""
val filename = "gopass_${version}_linux_amd64.deb"
val result = downloadFromURL(
"https://github.com/gopasspw/gopass/releases/download/v$version/$filename",
filename,
path,
sha256sum = sha256sum
)
gopassEnsureVersion(version)
if (result.success) {
cmd("sudo dpkg -i $path/gopass_${version}_linux_amd64.deb")
// Cross-check if installation was successful
addResultToEval(ProvResult(checkGopassVersion(version)))
} else {
addResultToEval(ProvResult(false, err = "Gopass could not be installed. " + result.err))
}
}
@ -76,13 +86,9 @@ mounts: {}
*
* @param version that is checked; specifies left part of text of installed version, e.g. both "1" and "1.12" will return true if installed version is "1.12.6+8d7a311b9273846bbb618e4bd9ddbae51b1db7b8"
*/
internal fun Prov.gopassEnsureVersion(version: String) = def {
internal fun Prov.checkGopassVersion(version: String): Boolean {
val installedGopassVersion = gopassVersion()
if (installedGopassVersion != null && installedGopassVersion.startsWith("gopass " + version)) {
ProvResult(true, out = "Required gopass version ($version) matches installed version ($installedGopassVersion)")
} else {
ProvResult(false, err = "Wrong gopass version. Expected $version but found $installedGopassVersion")
}
return installedGopassVersion != null && installedGopassVersion.startsWith("gopass " + version)
}
internal fun Prov.gopassVersion(): String? {

View file

@ -34,7 +34,7 @@ fun Prov.installGopassBridgeJsonApi() = def {
if (installedJsonApiVersion == null) {
if (chk("gopass ls")) {
if (gopassEnsureVersion(requiredGopassVersion).success) {
if (checkGopassVersion(requiredGopassVersion)) {
aptInstall("git gnupg2") // required dependencies
createDir(downloadDir)
downloadFromURL(downloadUrl, filename, downloadDir)

View file

@ -54,8 +54,8 @@ fun Prov.createSecretFile(
}
fun Prov.deleteFile(file: String, sudo: Boolean = false): ProvResult = def {
cmd((if (sudo) "sudo " else "") + "rm $file")
fun Prov.deleteFile(file: String, path: String? = null, sudo: Boolean = false): ProvResult = def {
cmd((path?.let { "cd $path && " } ?: "") + (if (sudo) "sudo " else "") + "rm $file")
}

View file

@ -2,25 +2,45 @@ package org.domaindrivenarchitecture.provs.ubuntu.web.base
import org.domaindrivenarchitecture.provs.core.Prov
import org.domaindrivenarchitecture.provs.core.ProvResult
import org.domaindrivenarchitecture.provs.core.tags.Api
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createDirs
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.deleteFile
import org.domaindrivenarchitecture.provs.ubuntu.install.base.aptInstall
import org.domaindrivenarchitecture.provs.ubuntu.install.base.isPackageInstalled
/**
* Downloads a file from the given URL using curl
* Downloads a file from the given URL using curl.
*
* @param path where to download to
* @param url file to download
* @param filename filename after download
* ATTENTION: sha256sum uses the version available, which can differ in different versions of ubuntu; e.g. gopass download only works with sha256sum version 8.30 from ubuntu 20.04 !
*/
@Suppress("unused") // used externally
fun Prov.downloadFromURL(url: String, filename: String? = null, path: String? = null, sudo: Boolean = false) : ProvResult = def {
@Api
fun Prov.downloadFromURL(
url: String,
filename: String? = null,
path: String? = null,
sudo: Boolean = false,
followRedirect: Boolean = true,
sha256sum: String? = null
): ProvResult = def {
if (!isPackageInstalled("curl")) aptInstall("curl")
aptInstall("curl")
if (filename == null) {
cmd("curl $url", path, sudo)
val followRedirectOption = if (followRedirect) "-L" else ""
val filenameFromUrl = url.substringAfterLast("/")
val finalFilename: String = filename ?: filenameFromUrl
path?.let { createDirs(path) }
cmd("curl $followRedirectOption $url -o $finalFilename", path, sudo)
if (sha256sum != null) {
if (!cmd("echo \"$sha256sum $finalFilename\" | sha256sum --check", path).success) {
deleteFile(finalFilename, path, sudo)
} else {
cmd("curl $url -o $filename", path, sudo)
ProvResult(true, out = "Sha256sum is correct.")
}
} else {
ProvResult(true, out = "No sha256sum check requested.")
}
}

View file

@ -49,7 +49,7 @@ internal class FilesystemKtTest {
val res4b = prov.fileContainsText(file, "some non-existing content")
val res5 = prov.deleteFile(file)
val res6 = prov.fileExists(file)
val res7 = prov.deleteFile(file, true)
val res7 = prov.deleteFile(file, sudo = true)
val res8 = prov.fileExists(file)
// then

View file

@ -4,8 +4,8 @@ import org.domaindrivenarchitecture.provs.test.defaultTestContainer
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createFile
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.fileContent
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.fileExists
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
internal class WebKtTest {
@ -27,4 +27,42 @@ internal class WebKtTest {
assertTrue(res.success)
assertEquals("hello", res2)
}
@ContainerTest
@Test
fun downloadFromURL_local_file_with_correct_checksum() {
// given
val a = defaultTestContainer()
val srcFile = "file3.txt"
val targetFile = "file3b.txt"
a.createFile("/tmp/" + srcFile, "hello")
// when
val res = a.downloadFromURL("file:///tmp/" + srcFile, targetFile, "tmp", sha256sum ="2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824") // ubuntu 20.04 sha256sum version 8.30
// then
val res2 = a.fileContent("tmp/$targetFile")
assertEquals("hello", res2)
assertTrue(res.success)
}
@ContainerTest
@Test
fun downloadFromURL_local_file_with_incorrect_checksum() {
// given
val a = defaultTestContainer()
val srcFile = "file3.txt"
val targetFile = "file3b.txt"
a.createFile("/tmp/" + srcFile, "hello")
// when
val res = a.downloadFromURL("file:///tmp/" + srcFile, targetFile, "tmp", sha256sum = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824WRONG")
// then
val res2 = a.fileExists("tmp/$targetFile")
assertFalse(res.success)
assertFalse(res2)
}
}