< Summary - Heimdall API

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Matched()100%11100%
get_ConsumedEmailCode()100%11100%
get_ConsumedRecoveryCode()100%11100%
.cctor()100%11100%
get_AppCodeMatch()100%11100%
ForEmailCode(...)100%11100%
ForRecoveryCode(...)100%11100%

File(s)

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

#LineLine coverage
 1using ArturRios.Heimdall.Domain.Entities;
 2
 3namespace ArturRios.Heimdall.Command.Services;
 4
 5/// <summary>
 6///     The result of <see cref="ITwoFactorFactorVerifier.VerifyAsync" />: whether the submitted code
 7///     or recovery code matched, and — when it did — which row (if any) the caller must mark
 8///     consumed. At most one of <see cref="ConsumedEmailCode" />/<see cref="ConsumedRecoveryCode" />
 9///     is ever set, since a match is either an app code (neither), an email code, or a recovery code.
 10/// </summary>
 5511public sealed record TwoFactorFactorVerificationResult(
 17012    bool Matched,
 5013    TwoFactorEmailCode? ConsumedEmailCode,
 10614    TwoFactorRecoveryCode? ConsumedRecoveryCode)
 15{
 216    public static readonly TwoFactorFactorVerificationResult NoMatch = new(false, null, null);
 17
 2918    public static TwoFactorFactorVerificationResult AppCodeMatch { get; } = new(true, null, null);
 19
 20    public static TwoFactorFactorVerificationResult ForEmailCode(TwoFactorEmailCode emailCode) =>
 1221        new(true, emailCode, null);
 22
 23    public static TwoFactorFactorVerificationResult ForRecoveryCode(TwoFactorRecoveryCode recoveryCode) =>
 3924        new(true, null, recoveryCode);
 25}
 26
 27/// <summary>
 28///     Verifies a submitted second factor — a TOTP/email code, or a recovery code — against a
 29///     person's <see cref="TwoFactorAuth" /> configuration. Extracted out of
 30///     <c>VerifyTwoFactorAuthCommandHandler</c> (UC-38) so the same "code against TOTP, or against
 31///     the current email code, or against an unused recovery code" comparison is written exactly
 32///     once and reused wherever else a second factor must be proven — <c>DisableTwoFactorAuthCommandHandler</c>
 33///     (UC-39) and <c>RegenerateRecoveryCodesCommandHandler</c> (UC-40).
 34/// </summary>
 35public interface ITwoFactorFactorVerifier
 36{
 37    /// <summary>
 38    ///     Checks <paramref name="recoveryCode" /> against an unused, matching recovery code when it
 39    ///     is supplied; otherwise checks <paramref name="code" /> against a current TOTP code (when
 40    ///     <see cref="TwoFactorAuth.AppEnabled" />) and, failing that, against a live email code
 41    ///     (when <see cref="TwoFactorAuth.EmailEnabled" />). Writes only what guessing itself costs —
 42    ///     an accepted TOTP step (FR-2F-14) and a charged email-code guess (FR-2F-13). Spending the
 43    ///     returned email or recovery code is the caller's, once every other check for its own use
 44    ///     case has also passed, and is done through <c>IAtomicWrites</c> so only one request can.
 45    /// </summary>
 46    Task<TwoFactorFactorVerificationResult> VerifyAsync(
 47        TwoFactorAuth twoFactorAuth, string? code, string? recoveryCode);
 48}