From a2807c2bbe3e3a345fb9cad07b5256d2bbc43480 Mon Sep 17 00:00:00 2001
From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com>
Date: Tue, 16 Jan 2024 19:58:00 +0200
Subject: [PATCH] Move more model classes to records
---
src/Passwordless/Models/ApplicationEvent.cs | 50 +++-----
src/Passwordless/Models/Credential.cs | 115 ++++++------------
src/Passwordless/Models/GetEventLogRequest.cs | 16 +--
.../Models/GetEventLogResponse.cs | 26 ++--
src/Passwordless/Models/RegisterOptions.cs | 36 ++----
src/Passwordless/Models/SetAliasRequest.cs | 19 ++-
src/Passwordless/PasswordlessClient.cs | 2 +-
.../ApplicationEventLogsTests.cs | 2 +-
8 files changed, 84 insertions(+), 182 deletions(-)
diff --git a/src/Passwordless/Models/ApplicationEvent.cs b/src/Passwordless/Models/ApplicationEvent.cs
index 741f21b..b5401c1 100644
--- a/src/Passwordless/Models/ApplicationEvent.cs
+++ b/src/Passwordless/Models/ApplicationEvent.cs
@@ -5,37 +5,19 @@ namespace Passwordless.Models;
///
/// An event that occured using Passwordless library.
///
-public class ApplicationEvent
-{
- public Guid Id { get; set; }
-
- ///
- /// When the record was performed. This will be in UTC.
- ///
- public DateTime PerformedAt { get; set; }
-
- ///
- /// The type of event
- ///
- public string EventType { get; set; } = string.Empty;
-
- ///
- /// Description of the event
- ///
- public string Message { get; set; } = string.Empty;
-
- ///
- /// Severity of the event
- ///
- public string Severity { get; set; } = string.Empty;
-
- ///
- /// The target of the event. Can be in reference to a user or the application.
- ///
- public string Subject { get; set; } = string.Empty;
-
- ///
- /// Last 4 characters of the api key (public/secret) used to perform the event.
- ///
- public string ApiKeyId { get; set; } = string.Empty;
-}
\ No newline at end of file
+/// Event ID.
+/// When the event was performed.
+/// The type of event.
+/// Description of the event.
+/// Severity of the event.
+/// The target of the event. Can be in reference to a user or the application.
+/// Last 4 characters of the api key (public/secret) used to perform the event.
+public record ApplicationEvent(
+ Guid Id,
+ DateTime PerformedAt,
+ string EventType,
+ string Message,
+ string Severity,
+ string Subject,
+ string ApiKeyId
+);
\ No newline at end of file
diff --git a/src/Passwordless/Models/Credential.cs b/src/Passwordless/Models/Credential.cs
index d3b386d..5b5e1f4 100644
--- a/src/Passwordless/Models/Credential.cs
+++ b/src/Passwordless/Models/Credential.cs
@@ -6,95 +6,48 @@ namespace Passwordless;
/// The passkey credential stored by Passwordless.
///
///
-public class Credential(CredentialDescriptor descriptor, byte[] publicKey, byte[] userHandle, uint signatureCounter,
- string attestationFmt, DateTime createdAt, Guid aaGuid, DateTime lastUsedAt, string rpId,
- string origin, string country, string device, string nickname, string userId)
+/// Descriptor of the credential as defined by the WebAuthn specification.
+/// Public key of the passkey pair.
+/// Byte array of user identifier.
+/// WebAuthn SignatureCounter, used for anti forgery.
+/// Attestation Statement format used to create credential.
+/// When the credential was created.
+/// The AAGUID of the authenticator. Can be used to identify the make and model of the authenticator.
+/// Last time credential was used.
+/// Relying Party identifier.
+/// Domain credential was created for.
+/// Optional country credential was created in.
+/// Device the credential was created on.
+/// Friendly name for credential.
+/// Identifier for the user.
+public record Credential(
+ CredentialDescriptor Descriptor,
+ byte[] PublicKey,
+ byte[] UserHandle,
+ uint SignatureCounter,
+ string AttestationFmt,
+ DateTime CreatedAt,
+ Guid AaGuid,
+ DateTime LastUsedAt,
+ string RpId,
+ string Origin,
+ string Country,
+ string Device,
+ string Nickname,
+ string UserId)
{
- ///
- /// Descriptor of the credential as defined by the WebAuthn specification
- ///
- ///
- public CredentialDescriptor Descriptor { get; } = descriptor;
-
- ///
- /// Public key of the passkey pair.
- ///
- public byte[] PublicKey { get; } = publicKey;
-
- ///
- /// Byte array of user identifier
- ///
- public byte[] UserHandle { get; } = userHandle;
-
- ///
- /// WebAuthn SignatureCounter, used for anti forgery.
- ///
- public uint SignatureCounter { get; } = signatureCounter;
-
- ///
- /// Attestation Statement format used to create credential
- ///
- public string AttestationFmt { get; } = attestationFmt;
-
- ///
- /// When the credential was created
- ///
- public DateTime CreatedAt { get; } = createdAt;
-
- ///
- /// The AAGUID of the authenticator. Can be used to identify the make and model of the authenticator.
- ///
- ///
- public Guid AaGuid { get; } = aaGuid;
-
- ///
- /// Last time credential was used
- ///
- public DateTime LastUsedAt { get; } = lastUsedAt;
-
- ///
- /// Relying Party identifier
- ///
- ///
- public string RpId { get; } = rpId;
-
- ///
- /// Domain credential was created for
- ///
- public string Origin { get; } = origin;
-
- ///
- /// Optional country credential was created in
- ///
- public string Country { get; } = country;
-
- ///
- /// Device the credential was created on
- ///
- public string Device { get; } = device;
-
- ///
- /// Friendly name for credential.
- ///
- public string Nickname { get; } = nickname;
-
- ///
- /// Identifier for the user
- ///
- public string UserId { get; } = userId;
-
///
/// Whether the credential is synced (or backed up or not).
///
- public bool? BackupState { get; set; }
+ public bool? BackupState { get; init; }
///
- /// Whether the credential is eligible for backup or syncing
+ /// Whether the credential is eligible for backup or syncing.
///
- public bool? IsBackupEligible { get; set; }
+ public bool? IsBackupEligible { get; init; }
///
- /// Whether the credential is discoverable
+ /// Whether the credential is discoverable.
///
- public bool? IsDiscoverable { get; set; }
+ public bool? IsDiscoverable { get; init; }
}
\ No newline at end of file
diff --git a/src/Passwordless/Models/GetEventLogRequest.cs b/src/Passwordless/Models/GetEventLogRequest.cs
index 6385011..ef60157 100644
--- a/src/Passwordless/Models/GetEventLogRequest.cs
+++ b/src/Passwordless/Models/GetEventLogRequest.cs
@@ -5,16 +5,6 @@ namespace Passwordless.Models;
///
/// Request for getting the event logs for an application.
///
-public class GetEventLogRequest
-{
- ///
- /// Page number for retrieving event log records.
- ///
- public int PageNumber { get; set; }
-
- ///
- /// This is the max number of results that will be returned. Must be between 1-1000.
- ///
- [Range(1, 1000)]
- public int? NumberOfResults { get; set; }
-}
\ No newline at end of file
+/// Page number for retrieving event log records.
+/// This is the max number of results that will be returned. Must be between 1-1000.
+public record GetEventLogRequest(int PageNumber, int? NumberOfResults = null);
\ No newline at end of file
diff --git a/src/Passwordless/Models/GetEventLogResponse.cs b/src/Passwordless/Models/GetEventLogResponse.cs
index 6e9fdf7..921b199 100644
--- a/src/Passwordless/Models/GetEventLogResponse.cs
+++ b/src/Passwordless/Models/GetEventLogResponse.cs
@@ -5,21 +5,11 @@ namespace Passwordless.Models;
///
/// Response from GetEventLog. Contains list of events for the application.
///
-public class GetEventLogResponse
-{
- ///
- /// Name of application the events correspond to.
- ///
- public string TenantId { get; set; } = string.Empty;
-
- ///
- /// List of events for the application based on the request pagination parameters.
- /// This will always be sorted by PerformedAt in descending order.
- ///
- public IReadOnlyList Events { get; set; } = new List();
-
- ///
- /// Total number of events for the application.
- ///
- public int TotalEventCount { get; set; }
-}
\ No newline at end of file
+/// Name of application the events correspond to.
+/// List of events for the application based on the request pagination parameters. This will always be sorted by PerformedAt in descending order.
+/// Total number of events for the application.
+public record GetEventLogResponse(
+ string TenantId,
+ IReadOnlyList Events,
+ int TotalEventCount
+);
\ No newline at end of file
diff --git a/src/Passwordless/Models/RegisterOptions.cs b/src/Passwordless/Models/RegisterOptions.cs
index 90920c1..bdc7aeb 100644
--- a/src/Passwordless/Models/RegisterOptions.cs
+++ b/src/Passwordless/Models/RegisterOptions.cs
@@ -4,67 +4,55 @@
namespace Passwordless;
///
-///
+/// Options for registering a new WebAuthn credential.
///
-public class RegisterOptions(string userId, string username)
+/// A WebAuthn User Handle, which should be generated by your application. This is used to identify your user (could be a database primary key ID or a guid). Max. 64 bytes. Should not contain PII about the user.
+/// A human-palatable identifier for a user account. It is intended only for display, i.e., aiding the user in determining the difference between user accounts with similar displayNames. Used in Browser UI's and never stored on the server.
+public record RegisterOptions(string UserId, string Username)
{
- ///
- /// A WebAuthn User Handle, which should be generated by your application.
- /// This is used to identify your user (could be a database primary key ID or a guid).
- /// Max. 64 bytes. Should not contain PII about the user.
- ///
- public string UserId { get; } = userId;
-
- ///
- /// A human-palatable identifier for a user account. It is intended only for display,
- /// i.e., aiding the user in determining the difference between user accounts with
- /// similar displayNames. Used in Browser UI's and never stored on the server.
- ///
- public string Username { get; } = username;
-
///
/// A human-palatable name for the account, which should be chosen by the user.
/// Used in Browser UI's and never stored on the server.
///
- public string? DisplayName { get; set; }
+ public string? DisplayName { get; init; }
///
/// WebAuthn attestation conveyance preference. Only "none" (default) is supported.
///
- public string? Attestation { get; set; }
+ public string? Attestation { get; init; }
///
/// WebAuthn authenticator attachment modality. Can be "any" (default), "platform",
/// which triggers client device-specific options Windows Hello, FaceID, or TouchID,
/// or "cross-platform", which triggers roaming options like security keys.
///
- public string? AuthenticatorType { get; set; }
+ public string? AuthenticatorType { get; init; }
///
/// If true, creates a client-side Discoverable Credential that allows sign in without needing a username.
///
- public bool? Discoverable { get; set; }
+ public bool? Discoverable { get; init; }
///
/// Allows choosing preference for requiring User Verification
/// (biometrics, pin code etc) when authenticating Can be "preferred" (default), "required" or "discouraged".
///
- public string? UserVerification { get; set; }
+ public string? UserVerification { get; init; }
///
/// Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds.
///
- public DateTime? ExpiresAt { get; set; }
+ public DateTime? ExpiresAt { get; init; }
///
/// A array of aliases for the userId, such as an email or username. Used to initiate a
/// signin on the client side with the signinWithAlias() method. An alias must be unique to the userId.
/// Defaults to an empty array [].
///
- public HashSet Aliases { get; set; } = [];
+ public HashSet Aliases { get; init; } = [];
///
/// Whether aliases should be hashed before being stored. Defaults to true.
///
- public bool? AliasHashing { get; set; }
+ public bool? AliasHashing { get; init; }
}
\ No newline at end of file
diff --git a/src/Passwordless/Models/SetAliasRequest.cs b/src/Passwordless/Models/SetAliasRequest.cs
index d8829bf..2c1bcdc 100644
--- a/src/Passwordless/Models/SetAliasRequest.cs
+++ b/src/Passwordless/Models/SetAliasRequest.cs
@@ -3,7 +3,13 @@
namespace Passwordless.Models;
-public class SetAliasRequest(string userId, HashSet aliases, bool hashing = true)
+///
+/// Sets aliases for a given user.
+///
+/// User ID.
+/// List of user aliases to overwrite the current aliases (if any) with.
+/// If you want your aliases to be available in plain text, set the false.
+public record SetAliasRequest(string UserId, IReadOnlyCollection Aliases, bool Hashing = true)
{
///
/// Sets a single alias for a given user, and removes any other aliases that may exist.
@@ -13,16 +19,9 @@ public SetAliasRequest(string userId, string alias, bool hashing = true)
{
}
- public string UserId { get; } = userId;
-
- public IReadOnlyCollection Aliases { get; } = aliases == null
+ public IReadOnlyCollection Aliases { get; } = Aliases == null
? []
- : new HashSet(aliases.Where(x => !string.IsNullOrWhiteSpace(x)));
-
- ///
- /// If you want your aliases to be available in plain text, set the false.
- ///
- public bool Hashing { get; } = hashing;
+ : new HashSet(Aliases.Where(x => !string.IsNullOrWhiteSpace(x)));
///
/// Removes all aliases from a user.
diff --git a/src/Passwordless/PasswordlessClient.cs b/src/Passwordless/PasswordlessClient.cs
index 4a5bdf2..bdfe4aa 100644
--- a/src/Passwordless/PasswordlessClient.cs
+++ b/src/Passwordless/PasswordlessClient.cs
@@ -112,7 +112,7 @@ public async Task VerifyAuthenticationTokenAsync(
public async Task GetEventLogAsync(GetEventLogRequest request, CancellationToken cancellationToken = default) =>
(await _http.GetFromJsonAsync($"events?pageNumber={request.PageNumber}&numberOfResults={request.NumberOfResults}",
PasswordlessSerializerContext.Default.GetEventLogResponse,
- cancellationToken)) ?? new GetEventLogResponse();
+ cancellationToken))!;
///
public async Task GetUsersCountAsync(CancellationToken cancellationToken = default) =>
diff --git a/tests/Passwordless.Tests/ApplicationEventLogsTests.cs b/tests/Passwordless.Tests/ApplicationEventLogsTests.cs
index 771da36..ce4852a 100644
--- a/tests/Passwordless.Tests/ApplicationEventLogsTests.cs
+++ b/tests/Passwordless.Tests/ApplicationEventLogsTests.cs
@@ -18,7 +18,7 @@ public async Task I_can_view_application_event_logs_when_event_logs_are_enabled(
// Act
var response = await passwordless.GetEventLogAsync(
- new GetEventLogRequest { PageNumber = 1, NumberOfResults = 100 }
+ new GetEventLogRequest(1, 100)
);
// Assert