toolkit.model.33.0.0.source-code.Hash.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of model Show documentation
Show all versions of model Show documentation
Part of the OSS Review Toolkit (ORT), a suite to automate software compliance checks.
/*
* Copyright (C) 2017 The ORT Project Authors (see )
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/
package org.ossreviewtoolkit.model
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.util.StdConverter
import java.io.File
import kotlin.io.encoding.Base64
/**
* A class that bundles a hash algorithm with its hash value.
*/
data class Hash(
/**
* The value calculated using the hash algorithm.
*/
@JsonSerialize(converter = StringLowercaseConverter::class)
val value: String,
/**
* The algorithm used to calculate the hash value.
*/
val algorithm: HashAlgorithm
) {
companion object {
/**
* A constant to specify that no hash value (and thus also no hash algorithm) is provided.
*/
val NONE = Hash(HashAlgorithm.NONE.toString(), HashAlgorithm.NONE)
/**
* Create a [Hash] instance from a known hash [value]. If the [HashAlgorithm] cannot be determined, the original
* [value] is returned with [HashAlgorithm.UNKNOWN], or with [HashAlgorithm.NONE] if the value is blank.
*/
fun create(value: String): Hash {
val splitValue = value.split('-')
return if (splitValue.size == 2) {
// Support Subresource Integrity (SRI) hashes, see
// https://w3c.github.io/webappsec-subresource-integrity/
Hash(
value = Base64.decode(splitValue.last()).toHexString(),
algorithm = HashAlgorithm.fromString(splitValue.first())
)
} else {
Hash(value.lowercase(), HashAlgorithm.create(value))
}
}
}
init {
require(value.length == algorithm.size || algorithm == HashAlgorithm.UNKNOWN) {
"'$value' is not a $algorithm hash."
}
}
/**
* Construct a [Hash] instance from hash [value] and [algorithm] strings.
*/
constructor(value: String, algorithm: String) : this(value, HashAlgorithm.fromString(algorithm))
/**
* Return the hash in Support Subresource Integrity (SRI) format.
*/
fun toSri() = algorithm.name.lowercase() + "-" + Base64.encode(value.hexToByteArray())
/**
* Verify that the [file] matches this hash.
*/
fun verify(file: File): Boolean {
require(algorithm in HashAlgorithm.VERIFIABLE) {
"Cannot verify algorithm '$algorithm'. Supported algorithms are ${HashAlgorithm.VERIFIABLE}."
}
return algorithm.calculate(file).equals(value, ignoreCase = true)
}
/**
* Verify that the provided [hash] matches this hash.
*/
fun verify(hash: Hash): Boolean = algorithm == hash.algorithm && value.equals(hash.value, ignoreCase = true)
}
private class StringLowercaseConverter : StdConverter() {
override fun convert(value: String): String = value.lowercase()
}