Skip to content

Commit

Permalink
Revert "Move more model classes to records (#108)"
Browse files Browse the repository at this point in the history
This reverts commit 30273e1.
  • Loading branch information
jonashendrickx authored Feb 25, 2024
1 parent 854d3e5 commit 0aa117b
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 84 deletions.
50 changes: 34 additions & 16 deletions src/Passwordless/Models/ApplicationEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,37 @@ namespace Passwordless.Models;
/// <summary>
/// An event that occured using Passwordless library.
/// </summary>
/// <param name="Id">Event ID.</param>
/// <param name="PerformedAt">When the event was performed.</param>
/// <param name="EventType">The type of event. <see href="https://github.com/passwordless/passwordless-server/blob/main/src/Common/EventLog/Enums/EventType.cs"/></param>
/// <param name="Message">Description of the event.</param>
/// <param name="Severity">Severity of the event. <see href="https://github.com/passwordless/passwordless-server/blob/main/src/Common/EventLog/Enums/Severity.cs"/></param>
/// <param name="Subject">The target of the event. Can be in reference to a user or the application.</param>
/// <param name="ApiKeyId">Last 4 characters of the api key (public/secret) used to perform the event.</param>
public record ApplicationEvent(
Guid Id,
DateTime PerformedAt,
string EventType,
string Message,
string Severity,
string Subject,
string ApiKeyId
);
public class ApplicationEvent
{
public Guid Id { get; set; }

/// <summary>
/// When the record was performed. This will be in UTC.
/// </summary>
public DateTime PerformedAt { get; set; }

/// <summary>
/// The type of event <see href="https://github.com/passwordless/passwordless-server/blob/main/src/Common/EventLog/Enums/EventType.cs" />
/// </summary>
public string EventType { get; set; } = string.Empty;

/// <summary>
/// Description of the event
/// </summary>
public string Message { get; set; } = string.Empty;

/// <summary>
/// Severity of the event <see href="https://github.com/passwordless/passwordless-server/blob/main/src/Common/EventLog/Enums/Severity.cs"/>
/// </summary>
public string Severity { get; set; } = string.Empty;

/// <summary>
/// The target of the event. Can be in reference to a user or the application.
/// </summary>
public string Subject { get; set; } = string.Empty;

/// <summary>
/// Last 4 characters of the api key (public/secret) used to perform the event.
/// </summary>
public string ApiKeyId { get; set; } = string.Empty;
}
115 changes: 81 additions & 34 deletions src/Passwordless/Models/Credential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,95 @@ namespace Passwordless;
/// The passkey credential stored by Passwordless.
/// <see href="https://www.w3.org/TR/webauthn-2/#public-key-credential"/>
/// </summary>
/// <param name="Descriptor">Descriptor of the credential as defined by the WebAuthn specification. <see href="https://w3c.github.io/webauthn/#enumdef-publickeycredentialtype" /></param>
/// <param name="PublicKey">Public key of the passkey pair.</param>
/// <param name="UserHandle">Byte array of user identifier.</param>
/// <param name="SignatureCounter">WebAuthn SignatureCounter, used for anti forgery.</param>
/// <param name="AttestationFmt">Attestation Statement format used to create credential.</param>
/// <param name="CreatedAt">When the credential was created.</param>
/// <param name="AaGuid">The AAGUID of the authenticator. Can be used to identify the make and model of the authenticator. <see href="https://www.w3.org/TR/webauthn/#aaguid"/></param>
/// <param name="LastUsedAt">Last time credential was used.</param>
/// <param name="RpId">Relying Party identifier. <see href="https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-rp"/></param>
/// <param name="Origin">Domain credential was created for.</param>
/// <param name="Country">Optional country credential was created in.</param>
/// <param name="Device">Device the credential was created on.</param>
/// <param name="Nickname">Friendly name for credential.</param>
/// <param name="UserId">Identifier for the user.</param>
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)
{
/// <summary>
/// Descriptor of the credential as defined by the WebAuthn specification
/// <see href="https://w3c.github.io/webauthn/#enumdef-publickeycredentialtype" />
/// </summary>
public CredentialDescriptor Descriptor { get; } = descriptor;

/// <summary>
/// Public key of the passkey pair.
/// </summary>
public byte[] PublicKey { get; } = publicKey;

/// <summary>
/// Byte array of user identifier
/// </summary>
public byte[] UserHandle { get; } = userHandle;

/// <summary>
/// WebAuthn SignatureCounter, used for anti forgery.
/// </summary>
public uint SignatureCounter { get; } = signatureCounter;

/// <summary>
/// Attestation Statement format used to create credential
/// </summary>
public string AttestationFmt { get; } = attestationFmt;

/// <summary>
/// When the credential was created
/// </summary>
public DateTime CreatedAt { get; } = createdAt;

/// <summary>
/// The AAGUID of the authenticator. Can be used to identify the make and model of the authenticator.
/// <see href="https://www.w3.org/TR/webauthn/#aaguid"/>
/// </summary>
public Guid AaGuid { get; } = aaGuid;

/// <summary>
/// Last time credential was used
/// </summary>
public DateTime LastUsedAt { get; } = lastUsedAt;

/// <summary>
/// Relying Party identifier
/// <see href="https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-rp"/>
/// </summary>
public string RpId { get; } = rpId;

/// <summary>
/// Domain credential was created for
/// </summary>
public string Origin { get; } = origin;

/// <summary>
/// Optional country credential was created in
/// </summary>
public string Country { get; } = country;

/// <summary>
/// Device the credential was created on
/// </summary>
public string Device { get; } = device;

/// <summary>
/// Friendly name for credential.
/// </summary>
public string Nickname { get; } = nickname;

/// <summary>
/// Identifier for the user
/// </summary>
public string UserId { get; } = userId;

/// <summary>
/// Whether the credential is synced (or backed up or not).
/// </summary>
public bool? BackupState { get; init; }
public bool? BackupState { get; set; }

/// <summary>
/// Whether the credential is eligible for backup or syncing.
/// Whether the credential is eligible for backup or syncing
/// </summary>
public bool? IsBackupEligible { get; init; }
public bool? IsBackupEligible { get; set; }

/// <summary>
/// Whether the credential is discoverable.
/// Whether the credential is discoverable
/// </summary>
public bool? IsDiscoverable { get; init; }
public bool? IsDiscoverable { get; set; }
}
16 changes: 13 additions & 3 deletions src/Passwordless/Models/GetEventLogRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ namespace Passwordless.Models;
/// <summary>
/// Request for getting the event logs for an application.
/// </summary>
/// <param name="PageNumber">Page number for retrieving event log records.</param>
/// <param name="NumberOfResults">This is the max number of results that will be returned. Must be between 1-1000.</param>
public record GetEventLogRequest(int PageNumber, int? NumberOfResults = null);
public class GetEventLogRequest
{
/// <summary>
/// Page number for retrieving event log records.
/// </summary>
public int PageNumber { get; set; }

/// <summary>
/// This is the max number of results that will be returned. Must be between 1-1000.
/// </summary>
[Range(1, 1000)]
public int? NumberOfResults { get; set; }
}
26 changes: 18 additions & 8 deletions src/Passwordless/Models/GetEventLogResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@ namespace Passwordless.Models;
/// <summary>
/// Response from GetEventLog. Contains list of events for the application.
/// </summary>
/// <param name="TenantId">Name of application the events correspond to.</param>
/// <param name="Events">List of events for the application based on the request pagination parameters. This will always be sorted by PerformedAt in descending order.</param>
/// <param name="TotalEventCount">Total number of events for the application.</param>
public record GetEventLogResponse(
string TenantId,
IReadOnlyList<ApplicationEvent> Events,
int TotalEventCount
);
public class GetEventLogResponse
{
/// <summary>
/// Name of application the events correspond to.
/// </summary>
public string TenantId { get; set; } = string.Empty;

/// <summary>
/// List of events for the application based on the request pagination parameters.
/// This will always be sorted by PerformedAt in descending order.
/// </summary>
public IReadOnlyList<ApplicationEvent> Events { get; set; } = new List<ApplicationEvent>();

/// <summary>
/// Total number of events for the application.
/// </summary>
public int TotalEventCount { get; set; }
}
36 changes: 24 additions & 12 deletions src/Passwordless/Models/RegisterOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,67 @@
namespace Passwordless;

/// <summary>
/// Options for registering a new WebAuthn credential.
///
/// </summary>
/// <param name="UserId">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.</param>
/// <param name="Username">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.</param>
public record RegisterOptions(string UserId, string Username)
public class RegisterOptions(string userId, string username)
{
/// <summary>
/// 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.
/// </summary>
public string UserId { get; } = userId;

/// <summary>
/// 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.
/// </summary>
public string Username { get; } = username;

/// <summary>
/// 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.
/// </summary>
public string? DisplayName { get; init; }
public string? DisplayName { get; set; }

/// <summary>
/// WebAuthn attestation conveyance preference. Only "none" (default) is supported.
/// </summary>
public string? Attestation { get; init; }
public string? Attestation { get; set; }

/// <summary>
/// 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.
/// </summary>
public string? AuthenticatorType { get; init; }
public string? AuthenticatorType { get; set; }

/// <summary>
/// If true, creates a client-side Discoverable Credential that allows sign in without needing a username.
/// </summary>
public bool? Discoverable { get; init; }
public bool? Discoverable { get; set; }

/// <summary>
/// Allows choosing preference for requiring User Verification
/// (biometrics, pin code etc) when authenticating Can be "preferred" (default), "required" or "discouraged".
/// </summary>
public string? UserVerification { get; init; }
public string? UserVerification { get; set; }

/// <summary>
/// Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds.
/// </summary>
public DateTime? ExpiresAt { get; init; }
public DateTime? ExpiresAt { get; set; }

/// <summary>
/// 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 [].
/// </summary>
public HashSet<string> Aliases { get; init; } = [];
public HashSet<string> Aliases { get; set; } = [];

/// <summary>
/// Whether aliases should be hashed before being stored. Defaults to true.
/// </summary>
public bool? AliasHashing { get; init; }
public bool? AliasHashing { get; set; }
}
19 changes: 10 additions & 9 deletions src/Passwordless/Models/SetAliasRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@

namespace Passwordless.Models;

/// <summary>
/// Sets aliases for a given user.
/// </summary>
/// <param name="UserId">User ID.</param>
/// <param name="Aliases">List of user aliases to overwrite the current aliases (if any) with.</param>
/// <param name="Hashing">If you want your aliases to be available in plain text, set the <see cref="bool"/> false.</param>
public record SetAliasRequest(string UserId, IReadOnlyCollection<string> Aliases, bool Hashing = true)
public class SetAliasRequest(string userId, HashSet<string> aliases, bool hashing = true)
{
/// <summary>
/// Sets a single alias for a given user, and removes any other aliases that may exist.
Expand All @@ -19,9 +13,16 @@ public SetAliasRequest(string userId, string alias, bool hashing = true)
{
}

public IReadOnlyCollection<string> Aliases { get; } = Aliases == null
public string UserId { get; } = userId;

public IReadOnlyCollection<string> Aliases { get; } = aliases == null
? []
: new HashSet<string>(Aliases.Where(x => !string.IsNullOrWhiteSpace(x)));
: new HashSet<string>(aliases.Where(x => !string.IsNullOrWhiteSpace(x)));

/// <summary>
/// If you want your aliases to be available in plain text, set the <see cref="bool"/> false.
/// </summary>
public bool Hashing { get; } = hashing;

/// <summary>
/// Removes all aliases from a user.
Expand Down
2 changes: 1 addition & 1 deletion src/Passwordless/PasswordlessClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public async Task<VerifiedUser> VerifyAuthenticationTokenAsync(
public async Task<GetEventLogResponse> GetEventLogAsync(GetEventLogRequest request, CancellationToken cancellationToken = default) =>
(await _http.GetFromJsonAsync($"events?pageNumber={request.PageNumber}&numberOfResults={request.NumberOfResults}",
PasswordlessSerializerContext.Default.GetEventLogResponse,
cancellationToken))!;
cancellationToken)) ?? new GetEventLogResponse();

/// <inheritdoc />
public async Task<UsersCount> GetUsersCountAsync(CancellationToken cancellationToken = default) =>
Expand Down
2 changes: 1 addition & 1 deletion tests/Passwordless.Tests/ApplicationEventLogsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0aa117b

Please sign in to comment.