< Summary - Heimdall API

Information
Class: ArturRios.Heimdall.Command.Services.ApplicationCredentialSecret
Assembly: ArturRios.Heimdall.Command
File(s): /home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Command/Services/ApplicationCredentialSecret.cs
Line coverage
100%
Covered lines: 5
Uncovered lines: 0
Coverable lines: 5
Total lines: 38
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 2
Fully covered methods: 2
Total methods: 2
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
New()100%11100%
HashOf(...)100%11100%

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Application/ArturRios.Heimdall.Command/Services/ApplicationCredentialSecret.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2
 3namespace ArturRios.Heimdall.Command.Services;
 4
 5/// <summary>
 6///     Generates and hashes the secrets of UC-53 (FR-AP-10, Threat Model TH-33).
 7/// </summary>
 8/// <remarks>
 9///     <para>
 10///         <b>Shape.</b> <see cref="Prefix" /> plus 32 bytes from a cryptographic generator,
 11///         base64url-encoded without padding. The prefix makes a leaked secret recognisable — to a
 12///         person reading a log and to a secret scanner — and base64url keeps it safe in a URL, a
 13///         header or an environment file.
 14///     </para>
 15///     <para>
 16///         <b>Why a fast hash.</b> 256 random bits cannot be guessed, so a slow password hash buys
 17///         nothing and would put UC-56 behind the Argon2id gate the password logins share (NFR-18).
 18///         A credential is found by looking its hash up, so no comparison runs whose duration
 19///         depends on how much of a submitted secret matches.
 20///     </para>
 21/// </remarks>
 22public static class ApplicationCredentialSecret
 23{
 24    /// <summary>The prefix every secret starts with.</summary>
 25    public const string Prefix = "hds_";
 26
 27    private const int SecretBytes = 32;
 28
 29    /// <summary>A new secret, shown to the issuer once and never stored.</summary>
 30    public static string New() =>
 7431        Prefix + Convert.ToBase64String(RandomNumberGenerator.GetBytes(SecretBytes))
 7432            .TrimEnd('=')
 7433            .Replace('+', '-')
 7434            .Replace('/', '_');
 35
 36    /// <summary>The value stored in <c>ApplicationCredential.SecretHash</c> and looked up by UC-56.</summary>
 10437    public static string HashOf(string secret) => SingleUseTokenHash.Of(secret);
 38}

Methods/Properties

New()
HashOf(System.String)