diff --git a/src/Identity/Extensions.Core/src/PublicAPI.Unshipped.txt b/src/Identity/Extensions.Core/src/PublicAPI.Unshipped.txt index 8e7ea89bc368..3884283ff48e 100644 --- a/src/Identity/Extensions.Core/src/PublicAPI.Unshipped.txt +++ b/src/Identity/Extensions.Core/src/PublicAPI.Unshipped.txt @@ -1,3 +1,4 @@ #nullable enable Microsoft.AspNetCore.Identity.UserPasskeyInfo.Aaguid.get -> byte[]? Microsoft.AspNetCore.Identity.UserPasskeyInfo.Aaguid.set -> void +Microsoft.AspNetCore.Identity.UserPasskeyInfo.UserPasskeyInfo(byte[]! credentialId, byte[]! publicKey, System.DateTimeOffset createdAt, uint signCount, string![]? transports, bool isUserVerified, bool isBackupEligible, bool isBackedUp, byte[]! attestationObject, byte[]! clientDataJson, string? name) -> void diff --git a/src/Identity/Extensions.Core/src/UserPasskeyInfo.cs b/src/Identity/Extensions.Core/src/UserPasskeyInfo.cs index a8454f2dd04d..bd93c54f9043 100644 --- a/src/Identity/Extensions.Core/src/UserPasskeyInfo.cs +++ b/src/Identity/Extensions.Core/src/UserPasskeyInfo.cs @@ -34,6 +34,36 @@ public UserPasskeyInfo( bool isBackedUp, byte[] attestationObject, byte[] clientDataJson) + : this(credentialId, publicKey, createdAt, signCount, transports, isUserVerified, isBackupEligible, isBackedUp, attestationObject, clientDataJson, name: null) + { + } + + /// + /// Initializes a new instance of with a friendly name. + /// + /// The credential ID for the passkey. + /// The public key for the passkey. + /// The time when the passkey was created. + /// The signature counter for the passkey. + /// The transports supported by this passkey. + /// Indicates if the passkey has a verified user. + /// Indicates if the passkey is eligible for backup. + /// Indicates if the passkey is currently backed up. + /// The passkey's attestation object. + /// The passkey's client data JSON. + /// An optional friendly name for the passkey. + public UserPasskeyInfo( + byte[] credentialId, + byte[] publicKey, + DateTimeOffset createdAt, + uint signCount, + string[]? transports, + bool isUserVerified, + bool isBackupEligible, + bool isBackedUp, + byte[] attestationObject, + byte[] clientDataJson, + string? name) { CredentialId = credentialId; PublicKey = publicKey; @@ -45,6 +75,7 @@ public UserPasskeyInfo( IsBackedUp = isBackedUp; AttestationObject = attestationObject; ClientDataJson = clientDataJson; + Name = name; } /// diff --git a/src/Identity/test/Identity.Test/UserPasskeyInfoTest.cs b/src/Identity/test/Identity.Test/UserPasskeyInfoTest.cs new file mode 100644 index 000000000000..4d268671c23c --- /dev/null +++ b/src/Identity/test/Identity.Test/UserPasskeyInfoTest.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit; + +namespace Microsoft.AspNetCore.Identity.Test; + +public class UserPasskeyInfoTest +{ + [Fact] + public void Ctor_WithName_SetsAllProperties() + { + // Arrange + var credentialId = new byte[] { 1, 2, 3 }; + var publicKey = new byte[] { 4, 5, 6 }; + var createdAt = DateTimeOffset.UtcNow; + var transports = new[] { "usb", "nfc" }; + var attestationObject = new byte[] { 7, 8, 9 }; + var clientDataJson = new byte[] { 10, 11 }; + var name = "My Security Key"; + + // Act + var passkey = new UserPasskeyInfo( + credentialId, + publicKey, + createdAt, + signCount: 42, + transports, + isUserVerified: true, + isBackupEligible: true, + isBackedUp: false, + attestationObject, + clientDataJson, + name); + + // Assert + Assert.Equal(credentialId, passkey.CredentialId); + Assert.Equal(publicKey, passkey.PublicKey); + Assert.Equal(createdAt, passkey.CreatedAt); + Assert.Equal(42u, passkey.SignCount); + Assert.Equal(transports, passkey.Transports); + Assert.True(passkey.IsUserVerified); + Assert.True(passkey.IsBackupEligible); + Assert.False(passkey.IsBackedUp); + Assert.Equal(attestationObject, passkey.AttestationObject); + Assert.Equal(clientDataJson, passkey.ClientDataJson); + Assert.Equal("My Security Key", passkey.Name); + } + + [Fact] + public void Ctor_WithNullName_LeavesNameNull() + { + var passkey = new UserPasskeyInfo( + new byte[] { 1 }, + new byte[] { 2 }, + DateTimeOffset.UtcNow, + signCount: 0, + transports: null, + isUserVerified: false, + isBackupEligible: false, + isBackedUp: false, + new byte[] { 3 }, + new byte[] { 4 }, + name: null); + + Assert.Null(passkey.Name); + } + + [Fact] + public void Ctor_WithoutName_LeavesNameNull() + { + // The original constructor should still work and leave Name unset. + var passkey = new UserPasskeyInfo( + new byte[] { 1 }, + new byte[] { 2 }, + DateTimeOffset.UtcNow, + signCount: 0, + transports: null, + isUserVerified: false, + isBackupEligible: false, + isBackedUp: false, + new byte[] { 3 }, + new byte[] { 4 }); + + Assert.Null(passkey.Name); + } +}