CredentialManager.cs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. using System.Text;
  2. using System.Text.Json;
  3. using Fido2NetLib;
  4. using Fido2NetLib.Objects;
  5. namespace Passwordless;
  6. public class CredentialManager
  7. {
  8. private readonly IFido2 _fido2;
  9. private readonly JsonSerializerOptions _jsonOptions;
  10. public CredentialManager(IFido2 fido2)
  11. {
  12. _fido2 = fido2;
  13. _jsonOptions = new JsonSerializerOptions()
  14. {
  15. WriteIndented = true,
  16. };
  17. }
  18. public CredentialCreateOptions BuildCredentialOptions(string login)
  19. {
  20. var loginDisplay = Encoding.UTF8.GetString(Convert.FromBase64String(login));
  21. var loginName = NameTransform.ToFileName(loginDisplay);
  22. var user = new Fido2User
  23. {
  24. DisplayName = loginDisplay,
  25. Id = Convert.FromBase64String(login),
  26. Name = loginName,
  27. };
  28. var authenticatorSelection = new AuthenticatorSelection
  29. {
  30. UserVerification = UserVerificationRequirement.Discouraged,
  31. RequireResidentKey = false,
  32. };
  33. var extensions = new AuthenticationExtensionsClientInputs
  34. {
  35. Extensions = true,
  36. UserVerificationMethod = false,
  37. };
  38. var options = _fido2.RequestNewCredential(user, new List<PublicKeyCredentialDescriptor>(), authenticatorSelection, AttestationConveyancePreference.None, extensions);
  39. return options;
  40. }
  41. public async Task<Fido2.CredentialMakeResult> RegisterCredential(string login, AuthenticatorAttestationRawResponse attestationResponse)
  42. {
  43. // 2. Create callback so that lib can verify credential id is unique to this user
  44. static Task<bool> Callback(IsCredentialIdUniqueToUserParams args, CancellationToken cancellationToken)
  45. {
  46. return Task.FromResult(!File.Exists($"./data/{args.CredentialId}"));
  47. }
  48. var options = BuildCredentialOptions(login);
  49. var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, Callback);
  50. if (success.Status == "ok")
  51. {
  52. await using var fileStream = File.OpenWrite($"./data/{success.Result!.User.Name}");
  53. await JsonSerializer.SerializeAsync(fileStream, success.Result, _jsonOptions);
  54. }
  55. return success;
  56. }
  57. }