Skip to content

Commit

Permalink
Improve Code Quality (#509)
Browse files Browse the repository at this point in the history
* Use HashSizeInBytes

* Use throw helpers

* Use FrozenDictionary

* Use required properties

* Use primary constructor

* Use byte[] for Base64Url encoded properties

* Use required properties (part 2)

* Improve nullability annotations for AuthenticationExtensionsPRFValues

* Improve nullability annotations for AssertionOptions

* Format code

* Update AssertionOptions.Challenge nullability

* Simplify AppleAppAttestRootCA construction
  • Loading branch information
iamcarbon authored Jul 15, 2024
1 parent a14a53b commit b0bb79d
Show file tree
Hide file tree
Showing 21 changed files with 112 additions and 112 deletions.
4 changes: 1 addition & 3 deletions Src/Fido2.AspNet/DistributedCacheMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ public DistributedCacheMetadataService(
ILogger<DistributedCacheMetadataService> logger,
ISystemClock systemClock)
{

if (repositories == null)
throw new ArgumentNullException(nameof(repositories));
ArgumentNullException.ThrowIfNull(repositories);

_repositories = repositories.ToList();
_distributedCache = distributedCache;
Expand Down
25 changes: 16 additions & 9 deletions Src/Fido2.Models/AssertionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,28 @@ namespace Fido2NetLib;
public class AssertionOptions : Fido2ResponseBase
{
/// <summary>
/// This member represents a challenge that the selected authenticator signs, along with other data, when producing an authentication assertion.See the §13.1 Cryptographic Challenges security consideration.
/// This member represents a challenge that the selected authenticator signs, along with other data, when producing an authentication assertion.
/// See the §13.1 Cryptographic Challenges security consideration.
/// </summary>
[JsonPropertyName("challenge")]
[JsonConverter(typeof(Base64UrlConverter))]
public byte[] Challenge { get; set; }

#nullable enable

/// <summary>
/// This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and MAY be overridden by the client.
/// This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete.
/// This is treated as a hint, and MAY be overridden by the client.
/// </summary>
[JsonPropertyName("timeout")]
public ulong Timeout { get; set; }

/// <summary>
/// This OPTIONAL member specifies the relying party identifier claimed by the caller.If omitted, its value will be the CredentialsContainer object’s relevant settings object's origin's effective domain
/// This OPTIONAL member specifies the relying party identifier claimed by the caller.
/// If omitted, its value will be the CredentialsContainer object’s relevant settings object's origin's effective domain
/// </summary>
[JsonPropertyName("rpId")]
public string RpId { get; set; }
public string? RpId { get; set; }

/// <summary>
/// This OPTIONAL member contains a list of PublicKeyCredentialDescriptor objects representing public key credentials acceptable to the caller, in descending order of the caller’s preference(the first item in the list is the most preferred credential, and so on down the list)
Expand All @@ -37,24 +42,26 @@ public class AssertionOptions : Fido2ResponseBase
public IReadOnlyList<PublicKeyCredentialDescriptor> AllowCredentials { get; set; } = Array.Empty<PublicKeyCredentialDescriptor>();

/// <summary>
/// This member describes the Relying Party's requirements regarding user verification for the get() operation. Eligible authenticators are filtered to only those capable of satisfying this requirement
/// This member describes the Relying Party's requirements regarding user verification for the get() operation.
/// Eligible authenticators are filtered to only those capable of satisfying this requirement
/// </summary>
[JsonPropertyName("userVerification")]
public UserVerificationRequirement? UserVerification { get; set; }

/// <summary>
/// This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension.
/// This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator.
/// For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension.
/// </summary>
[JsonPropertyName("extensions")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public AuthenticationExtensionsClientInputs Extensions { get; set; }
public AuthenticationExtensionsClientInputs? Extensions { get; set; }

public static AssertionOptions Create(
Fido2Configuration config,
byte[] challenge,
IReadOnlyList<PublicKeyCredentialDescriptor> allowedCredentials,
UserVerificationRequirement? userVerification,
AuthenticationExtensionsClientInputs extensions)
AuthenticationExtensionsClientInputs? extensions)
{
return new AssertionOptions()
{
Expand All @@ -76,6 +83,6 @@ public string ToJson()

public static AssertionOptions FromJson(string json)
{
return JsonSerializer.Deserialize(json, FidoModelSerializerContext.Default.AssertionOptions);
return JsonSerializer.Deserialize(json, FidoModelSerializerContext.Default.AssertionOptions)!;
}
}
24 changes: 13 additions & 11 deletions Src/Fido2.Models/Converters/EnumNameMapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Collections.Frozen;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.Serialization;

Expand All @@ -7,19 +8,20 @@ namespace Fido2NetLib;
public static class EnumNameMapper<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum>
where TEnum : struct, Enum
{
private static readonly Dictionary<TEnum, string> s_valueToNames = GetIdToNameMap();
private static readonly Dictionary<string, TEnum> s_namesToValues = Invert(s_valueToNames);
private static readonly FrozenDictionary<TEnum, string> s_valueToNames = GetIdToNameMap();
private static readonly FrozenDictionary<string, TEnum> s_namesToValues = Invert(s_valueToNames);

private static Dictionary<string, TEnum> Invert(Dictionary<TEnum, string> map)
private static FrozenDictionary<string, TEnum> Invert(FrozenDictionary<TEnum, string> map)
{
var result = new Dictionary<string, TEnum>(map.Count, StringComparer.OrdinalIgnoreCase);
var items = new KeyValuePair<string, TEnum>[map.Count];
int i = 0;

foreach (var item in map)
{
result[item.Value] = item.Key;
items[i++] = new(item.Value, item.Key);
}

return result;
return items.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
}

public static bool TryGetValue(string name, out TEnum value)
Expand All @@ -37,19 +39,19 @@ public static IEnumerable<string> GetNames()
return s_namesToValues.Keys;
}

private static Dictionary<TEnum, string> GetIdToNameMap()
private static FrozenDictionary<TEnum, string> GetIdToNameMap()
{
var dic = new Dictionary<TEnum, string>();
var items = new List<KeyValuePair<TEnum, string>>();

foreach (var field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static))
{
var description = field.GetCustomAttribute<EnumMemberAttribute>(false);

var value = (TEnum)field.GetValue(null);

dic[value] = description is not null ? description.Value : value.ToString();
items.Add(new(value, description is not null ? description.Value : value.ToString()));
}

return dic;
return items.ToFrozenDictionary();
}
}
9 changes: 5 additions & 4 deletions Src/Fido2.Models/Metadata/BiometricStatusReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ public class BiometricStatusReport
/// <summary>
/// Gets or sets the level of the biometric certification of this biometric component of the authenticator.
/// </summary>
[JsonPropertyName("certLevel"), Required]
public ushort CertLevel { get; set; }
[JsonPropertyName("certLevel")]
public required ushort CertLevel { get; set; }

/// <summary>
/// Gets or sets a single USER_VERIFY constant indicating the modality of the biometric component.
/// </summary>
/// <remarks>
/// This is not a bit flag combination.
/// This value MUST be non-zero and this value MUST correspond to one or more entries in field userVerificationDetails in the related Metadata Statement.
/// </remarks>
[JsonPropertyName("modality"), Required]
public ulong Modality { get; set; }
[JsonPropertyName("modality")]
public required ulong Modality { get; set; }

/// <summary>
/// Gets or sets a ISO-8601 formatted date since when the certLevel achieved, if applicable.
Expand Down
15 changes: 7 additions & 8 deletions Src/Fido2.Models/Metadata/CodeAccuracyDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Fido2NetLib;

Expand All @@ -14,15 +13,15 @@ public sealed class CodeAccuracyDescriptor
/// <summary>
/// Gets or sets the numeric system base (radix) of the code, e.g. 10 in the case of decimal digits.
/// </summary>
[JsonPropertyName("base"), Required]
public ushort Base { get; set; }

[JsonPropertyName("base")]
public required ushort Base { get; set; }

/// <summary>
/// Gets or sets the minimum number of digits of the given base required for that code, e.g. 4 in the case of 4 digits.
/// </summary>
[JsonPropertyName("minLength"), Required]
public ushort MinLength { get; set; }

[JsonPropertyName("minLength")]
public required ushort MinLength { get; set; }

/// <summary>
/// Gets or sets the maximum number of false attempts before the authenticator will block this method (at least for some time).
/// <para>Zero (0) means it will never block.</para>
Expand Down
33 changes: 16 additions & 17 deletions Src/Fido2.Models/Metadata/DisplayPNGCharacteristicsDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Fido2NetLib;

Expand All @@ -14,44 +13,44 @@ public sealed class DisplayPNGCharacteristicsDescriptor
/// <summary>
/// Gets or sets the image width.
/// </summary>
[JsonPropertyName("width"), Required]
public ulong Width { get; set; }

[JsonPropertyName("width")]
public required ulong Width { get; set; }

/// <summary>
/// Gets or sets the image height.
/// </summary>
[JsonPropertyName("height"), Required]
public ulong Height { get; set; }
[JsonPropertyName("height")]
public required ulong Height { get; set; }

/// <summary>
/// Gets or sets the bit depth - bits per sample or per palette index.
/// </summary>
[JsonPropertyName("bitDepth"), Required]
public byte BitDepth { get; set; }
[JsonPropertyName("bitDepth")]
public required byte BitDepth { get; set; }

/// <summary>
/// Gets or sets the color type defines the PNG image type.
/// </summary>
[JsonPropertyName("colorType"), Required]
public byte ColorType { get; set; }
[JsonPropertyName("colorType")]
public required byte ColorType { get; set; }

/// <summary>
/// Gets or sets the compression method used to compress the image data.
/// </summary>
[JsonPropertyName("compression"), Required]
public byte Compression { get; set; }
[JsonPropertyName("compression")]
public required byte Compression { get; set; }

/// <summary>
/// Gets or sets the filter method is the preprocessing method applied to the image data before compression.
/// </summary>
[JsonPropertyName("filter"), Required]
public byte Filter { get; set; }
[JsonPropertyName("filter")]
public required byte Filter { get; set; }

/// <summary>
/// Gets or sets the interlace method is the transmission order of the image data.
/// </summary>
[JsonPropertyName("interlace"), Required]
public byte Interlace { get; set; }
[JsonPropertyName("interlace")]
public required byte Interlace { get; set; }

/// <summary>
/// Gets or sets the palette (1 to 256 palette entries).
Expand Down
32 changes: 18 additions & 14 deletions Src/Fido2.Models/Metadata/EcdaaTrustAnchor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Fido2NetLib;

Expand All @@ -15,37 +14,42 @@ public sealed class EcdaaTrustAnchor
/// <summary>
/// Gets or sets a base64url encoding of the result of ECPoint2ToB of the ECPoint2 X=P2​x​​.
/// </summary>
[JsonPropertyName("x"), Required]
public string X { get; set; }
[JsonConverter(typeof(Base64UrlConverter))]
[JsonPropertyName("x")]
public required byte[] X { get; set; }

/// <summary>
/// Gets or sets a base64url encoding of the result of ECPoint2ToB of the ECPoint2.
/// </summary>
[JsonPropertyName("y"), Required]
public string Y { get; set; }
[JsonConverter(typeof(Base64UrlConverter))]
[JsonPropertyName("y")]
public required byte[] Y { get; set; }

/// <summary>
/// Gets or sets a base64url encoding of the result of BigNumberToB(c).
/// </summary>
[JsonPropertyName("c"), Required]
public string C { get; set; }
[JsonConverter(typeof(Base64UrlConverter))]
[JsonPropertyName("c")]
public required byte[] C { get; set; }

/// <summary>
/// Gets or sets the base64url encoding of the result of BigNumberToB(sx).
/// </summary>
[JsonPropertyName("sx"), Required]
public string SX { get; set; }
[JsonConverter(typeof(Base64UrlConverter))]
[JsonPropertyName("sx")]
public required byte[] SX { get; set; }

/// <summary>
/// Gets or sets the base64url encoding of the result of BigNumberToB(sy).
/// </summary>
[JsonPropertyName("sy"), Required]
public string SY { get; set; }
[JsonConverter(typeof(Base64UrlConverter))]
[JsonPropertyName("sy")]
public required byte[] SY { get; set; }

/// <summary>
/// Gets or sets a name of the Barreto-Naehrig elliptic curve for G1.
/// <para>"BN_P256", "BN_P638", "BN_ISOP256", and "BN_ISOP512" are supported.</para>
/// </summary>
[JsonPropertyName("G1Curve"), Required]
public string G1Curve { get; set; }
[JsonPropertyName("G1Curve")]
public required string G1Curve { get; set; }
}
10 changes: 6 additions & 4 deletions Src/Fido2.Models/Metadata/ExtensionDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.ComponentModel.DataAnnotations;
#nullable enable

using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;

namespace Fido2NetLib;
Expand All @@ -14,8 +16,8 @@ public class ExtensionDescriptor
/// <summary>
/// Gets or sets the identifier that identifies the extension.
/// </summary>
[JsonPropertyName("id"), Required]
public string Id { get; set; }
[JsonPropertyName("id")]
public required string Id { get; set; }

/// <summary>
/// Gets or sets the tag.
Expand All @@ -35,7 +37,7 @@ public class ExtensionDescriptor
/// This field MAY be missing or it MAY be empty.
/// </remarks>
[JsonPropertyName("data")]
public string Data { get; set; }
public string? Data { get; set; }

/// <summary>
/// Gets or sets a value indication whether an unknown extensions must be ignored (<c>false</c>) or must lead to an error (<c>true</c>) when the extension is to be processed by the FIDO Server, FIDO Client, ASM, or FIDO Authenticator.
Expand Down
7 changes: 3 additions & 4 deletions Src/Fido2.Models/Metadata/PatternAccuracyDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Fido2NetLib;

Expand All @@ -14,8 +13,8 @@ public sealed class PatternAccuracyDescriptor
/// <summary>
/// Gets or sets the number of possible patterns (having the minimum length) out of which exactly one would be the right one, i.e. 1/probability in the case of equal distribution.
/// </summary>
[JsonPropertyName("minComplexity"), Required]
public ulong MinComplexity { get; set; }
[JsonPropertyName("minComplexity")]
public required ulong MinComplexity { get; set; }

/// <summary>
/// Gets or sets maximum number of false attempts before the authenticator will block authentication using this method (at least temporarily).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public sealed class AuthenticationExtensionsPRFInputs
/// </summary>
[JsonPropertyName("eval")]
public AuthenticationExtensionsPRFValues Eval { get; set; }

/// <summary>
/// A record mapping base64url encoded credential IDs to PRF inputs to evaluate for that credential.
/// https://w3c.github.io/webauthn/#dom-authenticationextensionsprfinputs-evalbycredential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public sealed class AuthenticationExtensionsPRFOutputs
/// </summary>
[JsonPropertyName("enabled")]
public bool Enabled { get; set; }

/// <summary>
/// The results of evaluating the PRF inputs.
/// </summary>
Expand Down
Loading

0 comments on commit b0bb79d

Please sign in to comment.