diff --git a/src/Passwordless/Models/ApplicationEvent.cs b/src/Passwordless/Models/ApplicationEvent.cs index b5401c1..741f21b 100644 --- a/src/Passwordless/Models/ApplicationEvent.cs +++ b/src/Passwordless/Models/ApplicationEvent.cs @@ -5,19 +5,37 @@ namespace Passwordless.Models; /// /// An event that occured using Passwordless library. /// -/// 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 +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 diff --git a/src/Passwordless/Models/Credential.cs b/src/Passwordless/Models/Credential.cs index 5b5e1f4..d3b386d 100644 --- a/src/Passwordless/Models/Credential.cs +++ b/src/Passwordless/Models/Credential.cs @@ -6,48 +6,95 @@ namespace Passwordless; /// The passkey credential stored by Passwordless. /// /// -/// 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) +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 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; init; } + public bool? BackupState { get; set; } /// - /// Whether the credential is eligible for backup or syncing. + /// Whether the credential is eligible for backup or syncing /// - public bool? IsBackupEligible { get; init; } + public bool? IsBackupEligible { get; set; } /// - /// Whether the credential is discoverable. + /// Whether the credential is discoverable /// - public bool? IsDiscoverable { get; init; } + public bool? IsDiscoverable { get; set; } } \ No newline at end of file diff --git a/src/Passwordless/Models/GetEventLogRequest.cs b/src/Passwordless/Models/GetEventLogRequest.cs index ef60157..6385011 100644 --- a/src/Passwordless/Models/GetEventLogRequest.cs +++ b/src/Passwordless/Models/GetEventLogRequest.cs @@ -5,6 +5,16 @@ namespace Passwordless.Models; /// /// Request for getting the event logs for an application. /// -/// 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 +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 diff --git a/src/Passwordless/Models/GetEventLogResponse.cs b/src/Passwordless/Models/GetEventLogResponse.cs index 921b199..6e9fdf7 100644 --- a/src/Passwordless/Models/GetEventLogResponse.cs +++ b/src/Passwordless/Models/GetEventLogResponse.cs @@ -5,11 +5,21 @@ namespace Passwordless.Models; /// /// Response from GetEventLog. Contains list of events for the application. /// -/// 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 +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 diff --git a/src/Passwordless/Models/RegisterOptions.cs b/src/Passwordless/Models/RegisterOptions.cs index bdc7aeb..90920c1 100644 --- a/src/Passwordless/Models/RegisterOptions.cs +++ b/src/Passwordless/Models/RegisterOptions.cs @@ -4,55 +4,67 @@ namespace Passwordless; /// -/// Options for registering a new WebAuthn credential. +/// /// -/// 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) +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. + /// + 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; init; } + public string? DisplayName { get; set; } /// /// WebAuthn attestation conveyance preference. Only "none" (default) is supported. /// - public string? Attestation { get; init; } + public string? Attestation { get; set; } /// /// 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; init; } + public string? AuthenticatorType { get; set; } /// /// If true, creates a client-side Discoverable Credential that allows sign in without needing a username. /// - public bool? Discoverable { get; init; } + public bool? Discoverable { get; set; } /// /// Allows choosing preference for requiring User Verification /// (biometrics, pin code etc) when authenticating Can be "preferred" (default), "required" or "discouraged". /// - public string? UserVerification { get; init; } + public string? UserVerification { get; set; } /// /// Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds. /// - public DateTime? ExpiresAt { get; init; } + public DateTime? ExpiresAt { get; set; } /// /// 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; init; } = []; + public HashSet Aliases { get; set; } = []; /// /// Whether aliases should be hashed before being stored. Defaults to true. /// - public bool? AliasHashing { get; init; } + public bool? AliasHashing { get; set; } } \ No newline at end of file diff --git a/src/Passwordless/Models/SetAliasRequest.cs b/src/Passwordless/Models/SetAliasRequest.cs index 2c1bcdc..d8829bf 100644 --- a/src/Passwordless/Models/SetAliasRequest.cs +++ b/src/Passwordless/Models/SetAliasRequest.cs @@ -3,13 +3,7 @@ namespace Passwordless.Models; -/// -/// 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) +public class SetAliasRequest(string userId, HashSet aliases, bool hashing = true) { /// /// Sets a single alias for a given user, and removes any other aliases that may exist. @@ -19,9 +13,16 @@ public SetAliasRequest(string userId, string alias, bool hashing = true) { } - public IReadOnlyCollection Aliases { get; } = Aliases == null + public string UserId { get; } = userId; + + public IReadOnlyCollection Aliases { get; } = aliases == null ? [] - : new HashSet(Aliases.Where(x => !string.IsNullOrWhiteSpace(x))); + : 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; /// /// Removes all aliases from a user. diff --git a/src/Passwordless/PasswordlessClient.cs b/src/Passwordless/PasswordlessClient.cs index bdfe4aa..4a5bdf2 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))!; + cancellationToken)) ?? new GetEventLogResponse(); /// public async Task GetUsersCountAsync(CancellationToken cancellationToken = default) => diff --git a/tests/Passwordless.Tests/ApplicationEventLogsTests.cs b/tests/Passwordless.Tests/ApplicationEventLogsTests.cs index ce4852a..771da36 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(1, 100) + new GetEventLogRequest { PageNumber = 1, NumberOfResults = 100 } ); // Assert