CredentialManager.cs 2.6 KB

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