Skip to content

Commit b0bb79d

Browse files
authored
Improve Code Quality (#509)
* 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
1 parent a14a53b commit b0bb79d

21 files changed

+112
-112
lines changed

Src/Fido2.AspNet/DistributedCacheMetadataService.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ public DistributedCacheMetadataService(
2929
ILogger<DistributedCacheMetadataService> logger,
3030
ISystemClock systemClock)
3131
{
32-
33-
if (repositories == null)
34-
throw new ArgumentNullException(nameof(repositories));
32+
ArgumentNullException.ThrowIfNull(repositories);
3533

3634
_repositories = repositories.ToList();
3735
_distributedCache = distributedCache;

Src/Fido2.Models/AssertionOptions.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,28 @@ namespace Fido2NetLib;
1212
public class AssertionOptions : Fido2ResponseBase
1313
{
1414
/// <summary>
15-
/// 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.
15+
/// This member represents a challenge that the selected authenticator signs, along with other data, when producing an authentication assertion.
16+
/// See the §13.1 Cryptographic Challenges security consideration.
1617
/// </summary>
1718
[JsonPropertyName("challenge")]
1819
[JsonConverter(typeof(Base64UrlConverter))]
1920
public byte[] Challenge { get; set; }
2021

22+
#nullable enable
23+
2124
/// <summary>
22-
/// 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.
25+
/// This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete.
26+
/// This is treated as a hint, and MAY be overridden by the client.
2327
/// </summary>
2428
[JsonPropertyName("timeout")]
2529
public ulong Timeout { get; set; }
2630

2731
/// <summary>
28-
/// 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
32+
/// This OPTIONAL member specifies the relying party identifier claimed by the caller.
33+
/// If omitted, its value will be the CredentialsContainer object’s relevant settings object's origin's effective domain
2934
/// </summary>
3035
[JsonPropertyName("rpId")]
31-
public string RpId { get; set; }
36+
public string? RpId { get; set; }
3237

3338
/// <summary>
3439
/// 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)
@@ -37,24 +42,26 @@ public class AssertionOptions : Fido2ResponseBase
3742
public IReadOnlyList<PublicKeyCredentialDescriptor> AllowCredentials { get; set; } = Array.Empty<PublicKeyCredentialDescriptor>();
3843

3944
/// <summary>
40-
/// 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
45+
/// This member describes the Relying Party's requirements regarding user verification for the get() operation.
46+
/// Eligible authenticators are filtered to only those capable of satisfying this requirement
4147
/// </summary>
4248
[JsonPropertyName("userVerification")]
4349
public UserVerificationRequirement? UserVerification { get; set; }
4450

4551
/// <summary>
46-
/// 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.
52+
/// This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator.
53+
/// For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension.
4754
/// </summary>
4855
[JsonPropertyName("extensions")]
4956
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
50-
public AuthenticationExtensionsClientInputs Extensions { get; set; }
57+
public AuthenticationExtensionsClientInputs? Extensions { get; set; }
5158

5259
public static AssertionOptions Create(
5360
Fido2Configuration config,
5461
byte[] challenge,
5562
IReadOnlyList<PublicKeyCredentialDescriptor> allowedCredentials,
5663
UserVerificationRequirement? userVerification,
57-
AuthenticationExtensionsClientInputs extensions)
64+
AuthenticationExtensionsClientInputs? extensions)
5865
{
5966
return new AssertionOptions()
6067
{
@@ -76,6 +83,6 @@ public string ToJson()
7683

7784
public static AssertionOptions FromJson(string json)
7885
{
79-
return JsonSerializer.Deserialize(json, FidoModelSerializerContext.Default.AssertionOptions);
86+
return JsonSerializer.Deserialize(json, FidoModelSerializerContext.Default.AssertionOptions)!;
8087
}
8188
}
Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Diagnostics.CodeAnalysis;
1+
using System.Collections.Frozen;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Reflection;
34
using System.Runtime.Serialization;
45

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

13-
private static Dictionary<string, TEnum> Invert(Dictionary<TEnum, string> map)
14+
private static FrozenDictionary<string, TEnum> Invert(FrozenDictionary<TEnum, string> map)
1415
{
15-
var result = new Dictionary<string, TEnum>(map.Count, StringComparer.OrdinalIgnoreCase);
16+
var items = new KeyValuePair<string, TEnum>[map.Count];
17+
int i = 0;
1618

1719
foreach (var item in map)
1820
{
19-
result[item.Value] = item.Key;
21+
items[i++] = new(item.Value, item.Key);
2022
}
2123

22-
return result;
24+
return items.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
2325
}
2426

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

40-
private static Dictionary<TEnum, string> GetIdToNameMap()
42+
private static FrozenDictionary<TEnum, string> GetIdToNameMap()
4143
{
42-
var dic = new Dictionary<TEnum, string>();
44+
var items = new List<KeyValuePair<TEnum, string>>();
4345

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

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

50-
dic[value] = description is not null ? description.Value : value.ToString();
52+
items.Add(new(value, description is not null ? description.Value : value.ToString()));
5153
}
5254

53-
return dic;
55+
return items.ToFrozenDictionary();
5456
}
5557
}

Src/Fido2.Models/Metadata/BiometricStatusReport.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@ public class BiometricStatusReport
1414
/// <summary>
1515
/// Gets or sets the level of the biometric certification of this biometric component of the authenticator.
1616
/// </summary>
17-
[JsonPropertyName("certLevel"), Required]
18-
public ushort CertLevel { get; set; }
17+
[JsonPropertyName("certLevel")]
18+
public required ushort CertLevel { get; set; }
19+
1920
/// <summary>
2021
/// Gets or sets a single USER_VERIFY constant indicating the modality of the biometric component.
2122
/// </summary>
2223
/// <remarks>
2324
/// This is not a bit flag combination.
2425
/// This value MUST be non-zero and this value MUST correspond to one or more entries in field userVerificationDetails in the related Metadata Statement.
2526
/// </remarks>
26-
[JsonPropertyName("modality"), Required]
27-
public ulong Modality { get; set; }
27+
[JsonPropertyName("modality")]
28+
public required ulong Modality { get; set; }
2829

2930
/// <summary>
3031
/// Gets or sets a ISO-8601 formatted date since when the certLevel achieved, if applicable.

Src/Fido2.Models/Metadata/CodeAccuracyDescriptor.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.ComponentModel.DataAnnotations;
2-
using System.Text.Json.Serialization;
1+
using System.Text.Json.Serialization;
32

43
namespace Fido2NetLib;
54

@@ -14,15 +13,15 @@ public sealed class CodeAccuracyDescriptor
1413
/// <summary>
1514
/// Gets or sets the numeric system base (radix) of the code, e.g. 10 in the case of decimal digits.
1615
/// </summary>
17-
[JsonPropertyName("base"), Required]
18-
public ushort Base { get; set; }
19-
16+
[JsonPropertyName("base")]
17+
public required ushort Base { get; set; }
18+
2019
/// <summary>
2120
/// 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.
2221
/// </summary>
23-
[JsonPropertyName("minLength"), Required]
24-
public ushort MinLength { get; set; }
25-
22+
[JsonPropertyName("minLength")]
23+
public required ushort MinLength { get; set; }
24+
2625
/// <summary>
2726
/// Gets or sets the maximum number of false attempts before the authenticator will block this method (at least for some time).
2827
/// <para>Zero (0) means it will never block.</para>

Src/Fido2.Models/Metadata/DisplayPNGCharacteristicsDescriptor.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.ComponentModel.DataAnnotations;
2-
using System.Text.Json.Serialization;
1+
using System.Text.Json.Serialization;
32

43
namespace Fido2NetLib;
54

@@ -14,44 +13,44 @@ public sealed class DisplayPNGCharacteristicsDescriptor
1413
/// <summary>
1514
/// Gets or sets the image width.
1615
/// </summary>
17-
[JsonPropertyName("width"), Required]
18-
public ulong Width { get; set; }
19-
16+
[JsonPropertyName("width")]
17+
public required ulong Width { get; set; }
18+
2019
/// <summary>
2120
/// Gets or sets the image height.
2221
/// </summary>
23-
[JsonPropertyName("height"), Required]
24-
public ulong Height { get; set; }
22+
[JsonPropertyName("height")]
23+
public required ulong Height { get; set; }
2524

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

3231
/// <summary>
3332
/// Gets or sets the color type defines the PNG image type.
3433
/// </summary>
35-
[JsonPropertyName("colorType"), Required]
36-
public byte ColorType { get; set; }
34+
[JsonPropertyName("colorType")]
35+
public required byte ColorType { get; set; }
3736

3837
/// <summary>
3938
/// Gets or sets the compression method used to compress the image data.
4039
/// </summary>
41-
[JsonPropertyName("compression"), Required]
42-
public byte Compression { get; set; }
40+
[JsonPropertyName("compression")]
41+
public required byte Compression { get; set; }
4342

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

5049
/// <summary>
5150
/// Gets or sets the interlace method is the transmission order of the image data.
5251
/// </summary>
53-
[JsonPropertyName("interlace"), Required]
54-
public byte Interlace { get; set; }
52+
[JsonPropertyName("interlace")]
53+
public required byte Interlace { get; set; }
5554

5655
/// <summary>
5756
/// Gets or sets the palette (1 to 256 palette entries).
Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.ComponentModel.DataAnnotations;
2-
using System.Text.Json.Serialization;
1+
using System.Text.Json.Serialization;
32

43
namespace Fido2NetLib;
54

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

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

2728
/// <summary>
2829
/// Gets or sets a base64url encoding of the result of BigNumberToB(c).
2930
/// </summary>
30-
[JsonPropertyName("c"), Required]
31-
public string C { get; set; }
31+
[JsonConverter(typeof(Base64UrlConverter))]
32+
[JsonPropertyName("c")]
33+
public required byte[] C { get; set; }
3234

3335
/// <summary>
3436
/// Gets or sets the base64url encoding of the result of BigNumberToB(sx).
3537
/// </summary>
36-
[JsonPropertyName("sx"), Required]
37-
public string SX { get; set; }
38+
[JsonConverter(typeof(Base64UrlConverter))]
39+
[JsonPropertyName("sx")]
40+
public required byte[] SX { get; set; }
3841

3942
/// <summary>
4043
/// Gets or sets the base64url encoding of the result of BigNumberToB(sy).
4144
/// </summary>
42-
[JsonPropertyName("sy"), Required]
43-
public string SY { get; set; }
45+
[JsonConverter(typeof(Base64UrlConverter))]
46+
[JsonPropertyName("sy")]
47+
public required byte[] SY { get; set; }
4448

4549
/// <summary>
4650
/// Gets or sets a name of the Barreto-Naehrig elliptic curve for G1.
4751
/// <para>"BN_P256", "BN_P638", "BN_ISOP256", and "BN_ISOP512" are supported.</para>
4852
/// </summary>
49-
[JsonPropertyName("G1Curve"), Required]
50-
public string G1Curve { get; set; }
53+
[JsonPropertyName("G1Curve")]
54+
public required string G1Curve { get; set; }
5155
}

Src/Fido2.Models/Metadata/ExtensionDescriptor.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.ComponentModel.DataAnnotations;
1+
#nullable enable
2+
3+
using System.ComponentModel.DataAnnotations;
24
using System.Text.Json.Serialization;
35

46
namespace Fido2NetLib;
@@ -14,8 +16,8 @@ public class ExtensionDescriptor
1416
/// <summary>
1517
/// Gets or sets the identifier that identifies the extension.
1618
/// </summary>
17-
[JsonPropertyName("id"), Required]
18-
public string Id { get; set; }
19+
[JsonPropertyName("id")]
20+
public required string Id { get; set; }
1921

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

4042
/// <summary>
4143
/// 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.

Src/Fido2.Models/Metadata/PatternAccuracyDescriptor.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.ComponentModel.DataAnnotations;
2-
using System.Text.Json.Serialization;
1+
using System.Text.Json.Serialization;
32

43
namespace Fido2NetLib;
54

@@ -14,8 +13,8 @@ public sealed class PatternAccuracyDescriptor
1413
/// <summary>
1514
/// 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.
1615
/// </summary>
17-
[JsonPropertyName("minComplexity"), Required]
18-
public ulong MinComplexity { get; set; }
16+
[JsonPropertyName("minComplexity")]
17+
public required ulong MinComplexity { get; set; }
1918

2019
/// <summary>
2120
/// Gets or sets maximum number of false attempts before the authenticator will block authentication using this method (at least temporarily).

Src/Fido2.Models/Objects/AuthenticationExtensionsPRFInputs.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public sealed class AuthenticationExtensionsPRFInputs
1313
/// </summary>
1414
[JsonPropertyName("eval")]
1515
public AuthenticationExtensionsPRFValues Eval { get; set; }
16+
1617
/// <summary>
1718
/// A record mapping base64url encoded credential IDs to PRF inputs to evaluate for that credential.
1819
/// https://w3c.github.io/webauthn/#dom-authenticationextensionsprfinputs-evalbycredential

0 commit comments

Comments
 (0)