< Summary

Information
Class: AsiBackbone.Core.Signing.CanonicalPayloadHash
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/CanonicalPayloadHash.cs
Line coverage
100%
Covered lines: 54
Uncovered lines: 0
Coverable lines: 54
Total lines: 162
Line coverage: 100%
Branch coverage
78%
Covered branches: 11
Total branches: 14
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_ArtifactType()100%11100%
get_ArtifactId()100%11100%
get_PayloadSchemaVersion()100%11100%
get_CanonicalizationVersion()100%11100%
get_HashAlgorithm()100%11100%
get_HashValue()100%11100%
Create(...)100%11100%
ToSigningMetadata(...)80%1010100%
NormalizeHashAlgorithm(...)75%44100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/CanonicalPayloadHash.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2
 3namespace AsiBackbone.Core.Signing;
 4
 5/// <summary>
 6/// Represents provider-neutral hash metadata for a canonical AsiBackbone payload.
 7/// </summary>
 8public sealed class CanonicalPayloadHash
 9{
 12810    private CanonicalPayloadHash(
 12811        string artifactType,
 12812        string artifactId,
 12813        string payloadSchemaVersion,
 12814        string canonicalizationVersion,
 12815        string hashAlgorithm,
 12816        string hashValue)
 17    {
 12818        ArtifactType = artifactType;
 12819        ArtifactId = artifactId;
 12820        PayloadSchemaVersion = payloadSchemaVersion;
 12821        CanonicalizationVersion = canonicalizationVersion;
 12822        HashAlgorithm = hashAlgorithm;
 12823        HashValue = hashValue;
 12824    }
 25
 26    /// <summary>
 27    /// Gets the artifact type bound into the hashed payload.
 28    /// </summary>
 24829    public string ArtifactType { get; }
 30
 31    /// <summary>
 32    /// Gets the artifact identifier bound into the hashed payload.
 33    /// </summary>
 22834    public string ArtifactId { get; }
 35
 36    /// <summary>
 37    /// Gets the payload schema version bound into the hashed payload.
 38    /// </summary>
 16739    public string PayloadSchemaVersion { get; }
 40
 41    /// <summary>
 42    /// Gets the canonicalization version used before hashing.
 43    /// </summary>
 19044    public string CanonicalizationVersion { get; }
 45
 46    /// <summary>
 47    /// Gets the hash algorithm descriptor.
 48    /// </summary>
 22549    public string HashAlgorithm { get; }
 50
 51    /// <summary>
 52    /// Gets the lowercase hexadecimal hash value.
 53    /// </summary>
 41454    public string HashValue { get; }
 55
 56    /// <summary>
 57    /// Creates provider-neutral hash metadata.
 58    /// </summary>
 59    public static CanonicalPayloadHash Create(
 60        string artifactType,
 61        string artifactId,
 62        string payloadSchemaVersion,
 63        string canonicalizationVersion,
 64        string hashAlgorithm,
 65        string hashValue)
 66    {
 12867        ArgumentException.ThrowIfNullOrWhiteSpace(artifactType);
 12868        ArgumentException.ThrowIfNullOrWhiteSpace(artifactId);
 12869        ArgumentException.ThrowIfNullOrWhiteSpace(payloadSchemaVersion);
 12870        ArgumentException.ThrowIfNullOrWhiteSpace(canonicalizationVersion);
 12871        ArgumentException.ThrowIfNullOrWhiteSpace(hashAlgorithm);
 12872        ArgumentException.ThrowIfNullOrWhiteSpace(hashValue);
 73
 12874        return new CanonicalPayloadHash(
 12875            artifactType.Trim(),
 12876            artifactId.Trim(),
 12877            payloadSchemaVersion.Trim(),
 12878            canonicalizationVersion.Trim(),
 12879            NormalizeHashAlgorithm(hashAlgorithm),
 12880            hashValue.Trim().ToLowerInvariant());
 81    }
 82
 83    /// <summary>
 84    /// Creates signing metadata that carries the hash and canonical payload descriptors without implying that the artif
 85    /// </summary>
 86    public SigningMetadata ToSigningMetadata(IReadOnlyDictionary<string, string>? metadata = null)
 87    {
 8188        Dictionary<string, string> hashMetadata = new(StringComparer.Ordinal)
 8189        {
 8190            ["artifact_id"] = ArtifactId,
 8191            ["artifact_type"] = ArtifactType,
 8192            ["canonicalization_version"] = CanonicalizationVersion,
 8193            ["payload_schema_version"] = PayloadSchemaVersion
 8194        };
 95
 8196        if (metadata is not null)
 97        {
 498            foreach (KeyValuePair<string, string> item in metadata)
 99            {
 1100                if (string.IsNullOrWhiteSpace(item.Key))
 101                {
 102                    continue;
 103                }
 104
 1105                hashMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 106            }
 107        }
 108
 81109        return SigningMetadata.Create(
 81110            signingHash: HashValue,
 81111            hashAlgorithm: HashAlgorithm,
 81112            metadata: hashMetadata);
 113    }
 114
 115    internal static string NormalizeHashAlgorithm(string hashAlgorithm)
 116    {
 300117        string normalized = hashAlgorithm.Trim();
 118
 300119        return normalized.Equals("SHA256", StringComparison.OrdinalIgnoreCase)
 300120            ? CanonicalPayloadOptions.DefaultHashAlgorithm
 300121            : normalized.Equals(CanonicalPayloadOptions.DefaultHashAlgorithm, StringComparison.OrdinalIgnoreCase)
 300122                ? CanonicalPayloadOptions.DefaultHashAlgorithm
 300123                : normalized;
 124    }
 125}
 126
 127/// <summary>
 128/// Computes provider-neutral hashes for canonical AsiBackbone payloads.
 129/// </summary>
 130public static class CanonicalPayloadHasher
 131{
 132    /// <summary>
 133    /// Computes a hash over the canonical payload bytes.
 134    /// </summary>
 135    public static CanonicalPayloadHash ComputeHash(
 136        CanonicalPayload payload,
 137        string? hashAlgorithm = null)
 138    {
 139        ArgumentNullException.ThrowIfNull(payload);
 140
 141        string algorithm = CanonicalPayloadHash.NormalizeHashAlgorithm(
 142            string.IsNullOrWhiteSpace(hashAlgorithm)
 143                ? CanonicalPayloadOptions.DefaultHashAlgorithm
 144                : hashAlgorithm);
 145
 146        if (!algorithm.Equals(CanonicalPayloadOptions.DefaultHashAlgorithm, StringComparison.Ordinal))
 147        {
 148            throw new NotSupportedException($"The built-in canonical payload hasher supports {CanonicalPayloadOptions.De
 149        }
 150
 151        byte[] hashBytes = SHA256.HashData(payload.ToUtf8Bytes());
 152        string hashValue = Convert.ToHexString(hashBytes).ToLowerInvariant();
 153
 154        return CanonicalPayloadHash.Create(
 155            payload.ArtifactType,
 156            payload.ArtifactId,
 157            payload.PayloadSchemaVersion,
 158            payload.CanonicalizationVersion,
 159            algorithm,
 160            hashValue);
 161    }
 162}