mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
1 Commits
bugfix/SG-
...
fido2-goog
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1461ab16b |
@@ -92,6 +92,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.3.0.1" />
|
||||
<PackageReference Include="Xamarin.Google.Dagger" Version="2.37.0" />
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.Fido" Version="118.1.0" />
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||
<Version>117.0.0</Version>
|
||||
</PackageReference>
|
||||
@@ -115,6 +116,8 @@
|
||||
<Compile Include="Effects\FixedSizeEffect.cs" />
|
||||
<Compile Include="Effects\SelectableLabelEffect.cs" />
|
||||
<Compile Include="Effects\TabBarEffect.cs" />
|
||||
<Compile Include="Fido2System\Fido2BuilderObject.cs" />
|
||||
<Compile Include="Fido2System\Fido2Service.cs" />
|
||||
<Compile Include="Push\FirebaseMessagingService.cs" />
|
||||
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
|
||||
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
|
||||
|
||||
106
src/Android/Fido2System/Fido2BuilderObject.cs
Normal file
106
src/Android/Fido2System/Fido2BuilderObject.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
#if !FDROID
|
||||
using System.Collections.Generic;
|
||||
using Android.Gms.Fido.Common;
|
||||
using Android.Gms.Fido.Fido2.Api.Common;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Response;
|
||||
using Bit.Core.Utilities;
|
||||
using Java.Lang;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Bit.Droid.Fido2System
|
||||
{
|
||||
class Fido2BuilderObject
|
||||
{
|
||||
public static PublicKeyCredentialRequestOptions ParsePublicKeyCredentialRequestOptions(
|
||||
Fido2AuthenticationChallengeResponse data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var builder = new PublicKeyCredentialRequestOptions.Builder();
|
||||
|
||||
if (!string.IsNullOrEmpty(data.Challenge))
|
||||
{
|
||||
builder.SetChallenge(CoreHelpers.Base64UrlDecode(data.Challenge));
|
||||
}
|
||||
if (data.AllowCredentials != null && data.AllowCredentials.Count > 0)
|
||||
{
|
||||
builder.SetAllowList(ParseCredentialDescriptors(data.AllowCredentials));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(data.RpId))
|
||||
{
|
||||
builder.SetRpId(data.RpId);
|
||||
}
|
||||
if (data.Timeout > 0)
|
||||
{
|
||||
builder.SetTimeoutSeconds((Double)(data.Timeout / 1000));
|
||||
}
|
||||
if (data.Extensions != null)
|
||||
{
|
||||
builder.SetAuthenticationExtensions(ParseExtensions((JObject)data.Extensions));
|
||||
}
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private static List<PublicKeyCredentialDescriptor> ParseCredentialDescriptors(
|
||||
List<Fido2CredentialDescriptor> listData)
|
||||
{
|
||||
if (listData == null || listData.Count == 0)
|
||||
{
|
||||
return new List<PublicKeyCredentialDescriptor>();
|
||||
}
|
||||
|
||||
var credentials = new List<PublicKeyCredentialDescriptor>();
|
||||
|
||||
foreach (var data in listData)
|
||||
{
|
||||
string id = null;
|
||||
string type = null;
|
||||
var transports = new List<Transport>();
|
||||
|
||||
if (!string.IsNullOrEmpty(data.Id))
|
||||
{
|
||||
id = data.Id;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(data.Type))
|
||||
{
|
||||
type = data.Type;
|
||||
}
|
||||
if (data.Transports != null && data.Transports.Count > 0)
|
||||
{
|
||||
foreach (var transport in data.Transports)
|
||||
{
|
||||
transports.Add(Transport.FromString(transport));
|
||||
}
|
||||
}
|
||||
|
||||
credentials.Add(new PublicKeyCredentialDescriptor(type, CoreHelpers.Base64UrlDecode(id), transports));
|
||||
}
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private static AuthenticationExtensions ParseExtensions(JObject extensions)
|
||||
{
|
||||
var builder = new AuthenticationExtensions.Builder();
|
||||
|
||||
if (extensions.ContainsKey("appid"))
|
||||
{
|
||||
var appId = new FidoAppIdExtension((string)extensions.GetValue("appid"));
|
||||
builder.SetFido2Extension(appId);
|
||||
}
|
||||
|
||||
if (extensions.ContainsKey("uvm"))
|
||||
{
|
||||
var uvm = new UserVerificationMethodExtension((bool)extensions.GetValue("uvm"));
|
||||
builder.SetUserVerificationMethodExtension(uvm);
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
249
src/Android/Fido2System/Fido2Service.cs
Normal file
249
src/Android/Fido2System/Fido2Service.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
#if !FDROID
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Gms.Fido;
|
||||
using Android.Gms.Fido.Fido2;
|
||||
using Android.Gms.Fido.Fido2.Api.Common;
|
||||
using Android.Gms.Tasks;
|
||||
using Android.Util;
|
||||
using AndroidX.AppCompat.App;
|
||||
using Bit.App.Services;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Request;
|
||||
using Bit.Core.Models.Response;
|
||||
using Bit.Core.Utilities;
|
||||
using Java.Lang;
|
||||
using Newtonsoft.Json;
|
||||
using Xamarin.Forms;
|
||||
using Enum = System.Enum;
|
||||
|
||||
namespace Bit.Droid.Fido2System
|
||||
{
|
||||
public class Fido2Service
|
||||
{
|
||||
public static readonly string _tag_log = "Fido2Service";
|
||||
|
||||
public static Fido2Service INSTANCE = new Fido2Service();
|
||||
|
||||
private readonly MobileI18nService _i18nService;
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
|
||||
private AppCompatActivity _activity;
|
||||
private Fido2ApiClient _fido2ApiClient;
|
||||
private Fido2CodesTypes _fido2CodesType;
|
||||
|
||||
public Fido2Service()
|
||||
{
|
||||
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
|
||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
}
|
||||
|
||||
public void Start(AppCompatActivity activity)
|
||||
{
|
||||
_activity = activity;
|
||||
_fido2ApiClient = Fido.GetFido2ApiClient(_activity);
|
||||
}
|
||||
|
||||
public void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
if (resultCode == Result.Ok && Enum.IsDefined(typeof(Fido2CodesTypes), requestCode))
|
||||
{
|
||||
switch ((Fido2CodesTypes)requestCode)
|
||||
{
|
||||
case Fido2CodesTypes.RequestSignInUser:
|
||||
var errorExtra = data?.GetByteArrayExtra(Fido.Fido2KeyErrorExtra);
|
||||
if (errorExtra != null)
|
||||
{
|
||||
HandleErrorCode(errorExtra);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
SignInUserResponse(data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// TODO: Key registration, should we ever choose to implement client-side
|
||||
/*case Fido2CodesTypes.RequestRegisterNewKey:
|
||||
errorExtra = data?.GetByteArrayExtra(Fido.Fido2KeyErrorExtra);
|
||||
if (errorExtra != null)
|
||||
{
|
||||
HandleErrorCode(errorExtra);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
// begin registration flow
|
||||
}
|
||||
}
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
else if (resultCode == Result.Canceled && Enum.IsDefined(typeof(Fido2CodesTypes), requestCode))
|
||||
{
|
||||
Log.Info(_tag_log, "cancelled");
|
||||
_platformUtilsService.ShowDialogAsync(_i18nService.T("Fido2AbortError"),
|
||||
_i18nService.T("Fido2Title"));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSuccess(Object result)
|
||||
{
|
||||
if (result != null && Enum.IsDefined(typeof(Fido2CodesTypes), _fido2CodesType))
|
||||
{
|
||||
try
|
||||
{
|
||||
_activity.StartIntentSenderForResult(((PendingIntent)result).IntentSender, (int)_fido2CodesType,
|
||||
null, 0, 0, 0);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Log.Error(_tag_log, e.Message);
|
||||
_platformUtilsService.ShowDialogAsync(_i18nService.T("Fido2SomethingWentWrong"),
|
||||
_i18nService.T("Fido2Title"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnFailure(Exception e)
|
||||
{
|
||||
Log.Error(_tag_log, e.Message ?? "OnFailure: No error message returned");
|
||||
_platformUtilsService.ShowDialogAsync(_i18nService.T("Fido2SomethingWentWrong"),
|
||||
_i18nService.T("Fido2Title"));
|
||||
}
|
||||
|
||||
public void OnComplete(Task task)
|
||||
{
|
||||
Log.Debug(_tag_log, "OnComplete");
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task SignInUserRequestAsync(string dataJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dataObject = JsonConvert.DeserializeObject<Fido2AuthenticationChallengeResponse>(dataJson);
|
||||
_fido2CodesType = Fido2CodesTypes.RequestSignInUser;
|
||||
var options = Fido2BuilderObject.ParsePublicKeyCredentialRequestOptions(dataObject);
|
||||
var task = _fido2ApiClient.GetSignPendingIntent(options);
|
||||
task.AddOnSuccessListener((IOnSuccessListener)_activity)
|
||||
.AddOnFailureListener((IOnFailureListener)_activity)
|
||||
.AddOnCompleteListener((IOnCompleteListener)_activity);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Log.Error(_tag_log, e.StackTrace);
|
||||
await _platformUtilsService.ShowDialogAsync(_i18nService.T("Fido2SomethingWentWrong"),
|
||||
_i18nService.T("Fido2Title"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.Info(_tag_log, "SignInUserRequest() -> finally()");
|
||||
}
|
||||
}
|
||||
|
||||
private void SignInUserResponse(Intent data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response =
|
||||
AuthenticatorAssertionResponse.DeserializeFromBytes(
|
||||
data.GetByteArrayExtra(Fido.Fido2KeyResponseExtra));
|
||||
var responseJson = JsonConvert.SerializeObject(new Fido2AuthenticationChallengeRequest
|
||||
{
|
||||
Id = CoreHelpers.Base64UrlEncode(response.GetKeyHandle()),
|
||||
RawId = CoreHelpers.Base64UrlEncode(response.GetKeyHandle()),
|
||||
Type = "public-key",
|
||||
Response = new Fido2AssertionResponse
|
||||
{
|
||||
AuthenticatorData = CoreHelpers.Base64UrlEncode(response.GetAuthenticatorData()),
|
||||
ClientDataJson = CoreHelpers.Base64UrlEncode(response.GetClientDataJSON()),
|
||||
Signature = CoreHelpers.Base64UrlEncode(response.GetSignature()),
|
||||
UserHandle = (response.GetUserHandle() != null
|
||||
? CoreHelpers.Base64UrlEncode(response.GetUserHandle()) : null),
|
||||
},
|
||||
Extensions = null
|
||||
}
|
||||
);
|
||||
Device.BeginInvokeOnMainThread(() => ((MainActivity)_activity).Fido2Submission(responseJson));
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Log.Error(_tag_log, e.Message);
|
||||
_platformUtilsService.ShowDialogAsync(_i18nService.T("Fido2SomethingWentWrong"),
|
||||
_i18nService.T("Fido2Title"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.Info(_tag_log, "SignInUserResponse() -> finally()");
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleErrorCode(byte[] errorExtra)
|
||||
{
|
||||
var error = AuthenticatorErrorResponse.DeserializeFromBytes(errorExtra);
|
||||
if (error.ErrorMessage.Length > 0)
|
||||
{
|
||||
Log.Info(_tag_log, error.ErrorMessage);
|
||||
}
|
||||
string message = "";
|
||||
if (error.ErrorCode == ErrorCode.AbortErr)
|
||||
{
|
||||
message = "Fido2AbortError";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.TimeoutErr)
|
||||
{
|
||||
message = "Fido2TimeoutError";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.AttestationNotPrivateErr)
|
||||
{
|
||||
message = "Fido2PrivacyError";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.ConstraintErr)
|
||||
{
|
||||
message = "Fido2SomethingWentWrong";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.DataErr)
|
||||
{
|
||||
message = "Fido2ServerDataFail";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.EncodingErr)
|
||||
{
|
||||
message = "Fido2SomethingWentWrong";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.InvalidStateErr)
|
||||
{
|
||||
message = "Fido2SomethingWentWrong";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.NetworkErr)
|
||||
{
|
||||
message = "Fido2NetworkFail";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.NotAllowedErr)
|
||||
{
|
||||
message = "Fido2NoPermission";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.NotSupportedErr)
|
||||
{
|
||||
message = "Fido2NotSupportedError";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.SecurityErr)
|
||||
{
|
||||
message = "Fido2SecurityError";
|
||||
}
|
||||
else if (error.ErrorCode == ErrorCode.UnknownErr)
|
||||
{
|
||||
message = "Fido2SomethingWentWrong";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "Fido2SomethingWentWrong";
|
||||
}
|
||||
_platformUtilsService.ShowDialogAsync(_i18nService.T(message), _i18nService.T("Fido2Title"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@ using Bit.Core.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Android.Content;
|
||||
using Bit.Droid.Utilities;
|
||||
using Bit.Droid.Receivers;
|
||||
@@ -17,7 +18,11 @@ using Bit.Core.Enums;
|
||||
using Android.Nfc;
|
||||
using Bit.App.Utilities;
|
||||
using System.Threading.Tasks;
|
||||
using Android.Util;
|
||||
using AndroidX.Core.Content;
|
||||
#if !FDROID
|
||||
using Bit.Droid.Fido2System;
|
||||
#endif
|
||||
using ZXing.Net.Mobile.Android;
|
||||
|
||||
namespace Bit.Droid
|
||||
@@ -42,7 +47,10 @@ namespace Bit.Droid
|
||||
@"text/*"
|
||||
})]
|
||||
[Register("com.x8bit.bitwarden.MainActivity")]
|
||||
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity,
|
||||
Android.Gms.Tasks.IOnSuccessListener,
|
||||
Android.Gms.Tasks.IOnCompleteListener,
|
||||
Android.Gms.Tasks.IOnFailureListener
|
||||
{
|
||||
private IDeviceActionService _deviceActionService;
|
||||
private IMessagingService _messagingService;
|
||||
@@ -57,6 +65,7 @@ namespace Bit.Droid
|
||||
private string _activityKey = $"{nameof(MainActivity)}_{Java.Lang.JavaSystem.CurrentTimeMillis().ToString()}";
|
||||
private Java.Util.Regex.Pattern _otpPattern =
|
||||
Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
|
||||
private string _fidoDataJson;
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
@@ -91,6 +100,7 @@ namespace Bit.Droid
|
||||
#if !FDROID
|
||||
var appCenterHelper = new AppCenterHelper(_appIdService, _userService);
|
||||
var appCenterTask = appCenterHelper.InitAsync();
|
||||
Fido2Service.INSTANCE.Start(this);
|
||||
#endif
|
||||
|
||||
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
||||
@@ -112,6 +122,14 @@ namespace Bit.Droid
|
||||
{
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(() => Finish());
|
||||
}
|
||||
else if (message.Command == "listenFido2")
|
||||
{
|
||||
ListenFido2((Dictionary<string, object>)message.Data);
|
||||
}
|
||||
else if (message.Command == "listenFido2TryAgain")
|
||||
{
|
||||
ListenFido2();
|
||||
}
|
||||
else if (message.Command == "listenYubiKeyOTP")
|
||||
{
|
||||
ListenYubiKey((bool)message.Data);
|
||||
@@ -260,6 +278,34 @@ namespace Bit.Droid
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (resultCode == Result.Ok &&
|
||||
Enum.IsDefined(typeof(Fido2CodesTypes), requestCode))
|
||||
{
|
||||
#if !FDROID
|
||||
Fido2Service.INSTANCE.OnActivityResult(requestCode, resultCode, data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSuccess(Java.Lang.Object result)
|
||||
{
|
||||
#if !FDROID
|
||||
Fido2Service.INSTANCE.OnSuccess(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnComplete(Android.Gms.Tasks.Task task)
|
||||
{
|
||||
#if !FDROID
|
||||
Fido2Service.INSTANCE.OnComplete(task);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnFailure(Java.Lang.Exception e)
|
||||
{
|
||||
#if !FDROID
|
||||
Fido2Service.INSTANCE.OnFailure(e);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
@@ -268,6 +314,41 @@ namespace Bit.Droid
|
||||
_broadcasterService.Unsubscribe(_activityKey);
|
||||
}
|
||||
|
||||
private void ListenFido2(Dictionary<string, object> data = null)
|
||||
{
|
||||
if (!_deviceActionService.SupportsFido2())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if !FDROID
|
||||
RunOnUiThread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
_fidoDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(data);
|
||||
await Fido2Service.INSTANCE.SignInUserRequestAsync(_fidoDataJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Fido2Service.INSTANCE.SignInUserRequestAsync(_fidoDataJson);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(Fido2Service._tag_log, e.Message);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Fido2Submission(string token)
|
||||
{
|
||||
_messagingService.Send("gotFido2Token", token);
|
||||
}
|
||||
|
||||
private void ListenYubiKey(bool listen)
|
||||
{
|
||||
if (!_deviceActionService.SupportsNfc())
|
||||
|
||||
@@ -778,7 +778,13 @@ namespace Bit.Droid.Services
|
||||
|
||||
public bool SupportsFido2()
|
||||
{
|
||||
return true;
|
||||
#if !FDROID
|
||||
if ((int)Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool DeleteDir(Java.IO.File dir)
|
||||
|
||||
@@ -75,6 +75,18 @@ namespace Bit.App.Pages
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (message.Command == "gotFido2Token")
|
||||
{
|
||||
var token = (string)message.Data;
|
||||
if (!string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(async () =>
|
||||
{
|
||||
_vm.Token = token;
|
||||
await _vm.SubmitAsync();
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (message.Command == "resumeYubiKey")
|
||||
{
|
||||
if (_vm.YubikeyMethod)
|
||||
@@ -174,7 +186,14 @@ namespace Bit.App.Pages
|
||||
{
|
||||
if (_vm.Fido2Method)
|
||||
{
|
||||
await _vm.Fido2AuthenticateAsync();
|
||||
if (Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
_messagingService.Send("listenFido2TryAgain", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _vm.Fido2AuthenticateAsync();
|
||||
}
|
||||
}
|
||||
else if (_vm.YubikeyMethod)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
@@ -151,7 +153,14 @@ namespace Bit.App.Pages
|
||||
switch (SelectedProviderType.Value)
|
||||
{
|
||||
case TwoFactorProviderType.Fido2WebAuthn:
|
||||
Fido2AuthenticateAsync(providerData);
|
||||
if (Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
_messagingService.Send("listenFido2", providerData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fido2AuthenticateAsync(providerData);
|
||||
}
|
||||
break;
|
||||
case TwoFactorProviderType.YubiKey:
|
||||
_messagingService.Send("listenYubiKeyOTP", true);
|
||||
|
||||
48
src/App/Resources/AppResources.Designer.cs
generated
48
src/App/Resources/AppResources.Designer.cs
generated
@@ -3590,5 +3590,53 @@ namespace Bit.App.Resources {
|
||||
return ResourceManager.GetString("Fido2SomethingWentWrong", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2AbortError {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2AbortError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2NetworkFail {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2NetworkFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2NoPermission {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2NoPermission", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2NotSupportedError {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2NotSupportedError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2PrivacyError {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2PrivacyError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2SecurityError {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2SecurityError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2ServerDataFail {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2ServerDataFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Fido2TimeoutError {
|
||||
get {
|
||||
return ResourceManager.GetString("Fido2TimeoutError", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2031,4 +2031,28 @@
|
||||
<data name="Fido2SomethingWentWrong" xml:space="preserve">
|
||||
<value>Something Went Wrong. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2AbortError" xml:space="preserve">
|
||||
<value>Aborted FIDO2 operation. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2NetworkFail" xml:space="preserve">
|
||||
<value>No internet connection. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2NoPermission" xml:space="preserve">
|
||||
<value>Permission was not given. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2NotSupportedError" xml:space="preserve">
|
||||
<value>Unsupported device.</value>
|
||||
</data>
|
||||
<data name="Fido2PrivacyError" xml:space="preserve">
|
||||
<value>Privacy issues encountered. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2SecurityError" xml:space="preserve">
|
||||
<value>Security issues encountered.</value>
|
||||
</data>
|
||||
<data name="Fido2ServerDataFail" xml:space="preserve">
|
||||
<value>The server returned invalid data. Try again.</value>
|
||||
</data>
|
||||
<data name="Fido2TimeoutError" xml:space="preserve">
|
||||
<value>Timeout for FIDO2. Try again</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
8
src/Core/Enums/Fido2CodesTypes.cs
Normal file
8
src/Core/Enums/Fido2CodesTypes.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Bit.Core.Enums
|
||||
{
|
||||
public enum Fido2CodesTypes
|
||||
{
|
||||
RequestSignInUser = 994,
|
||||
RequestRegisterNewKey = 995,
|
||||
}
|
||||
}
|
||||
16
src/Core/Models/Data/Fido2AssertionResponse.cs
Normal file
16
src/Core/Models/Data/Fido2AssertionResponse.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2AssertionResponse : Data
|
||||
{
|
||||
[JsonProperty("authenticatorData")]
|
||||
public string AuthenticatorData { get; set; }
|
||||
[JsonProperty("signature")]
|
||||
public string Signature { get; set; }
|
||||
[JsonProperty("clientDataJson")]
|
||||
public string ClientDataJson { get; set; }
|
||||
[JsonProperty("userHandle")]
|
||||
public string UserHandle { get; set; }
|
||||
}
|
||||
}
|
||||
14
src/Core/Models/Data/Fido2AuthenticatorSelection.cs
Normal file
14
src/Core/Models/Data/Fido2AuthenticatorSelection.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2AuthenticatorSelection : Data
|
||||
{
|
||||
[JsonProperty("authenticatorAttachment")]
|
||||
public string AuthenticatorAttachment { get; set; }
|
||||
[JsonProperty("userVerification")]
|
||||
public string UserVerification { get; set; }
|
||||
[JsonProperty("requireResidentKey")]
|
||||
public string RequireResidentKey { get; set; }
|
||||
}
|
||||
}
|
||||
15
src/Core/Models/Data/Fido2CredentialDescriptor.cs
Normal file
15
src/Core/Models/Data/Fido2CredentialDescriptor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2CredentialDescriptor : Data
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonProperty("transports", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public List<string> Transports { get; set; }
|
||||
}
|
||||
}
|
||||
12
src/Core/Models/Data/Fido2PubKeyCredParam.cs
Normal file
12
src/Core/Models/Data/Fido2PubKeyCredParam.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2PubKeyCredParam : Data
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
[JsonProperty("alg")]
|
||||
public int Alg { get; set; }
|
||||
}
|
||||
}
|
||||
14
src/Core/Models/Data/Fido2RP.cs
Normal file
14
src/Core/Models/Data/Fido2RP.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2RP : Data
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("icon")]
|
||||
public string Icon { get; set; }
|
||||
}
|
||||
}
|
||||
16
src/Core/Models/Data/Fido2User.cs
Normal file
16
src/Core/Models/Data/Fido2User.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class Fido2User : Data
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("displayName")]
|
||||
public string DisplayName { get; set; }
|
||||
[JsonProperty("icon")]
|
||||
public string Icon { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Bit.Core.Models.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Request
|
||||
{
|
||||
public class Fido2AuthenticationChallengeRequest
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonProperty("rawId")]
|
||||
public string RawId { get; set; }
|
||||
[JsonProperty("response")]
|
||||
public Fido2AssertionResponse Response { get; set; }
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
[JsonProperty("extensions", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Extensions { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Models.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Response
|
||||
{
|
||||
public class Fido2AuthenticationChallengeResponse
|
||||
{
|
||||
[JsonProperty("challenge")]
|
||||
public string Challenge { get; set; }
|
||||
[JsonProperty("rpId")]
|
||||
public string RpId { get; set; }
|
||||
[JsonProperty("timeout")]
|
||||
public double Timeout { get; set; }
|
||||
[JsonProperty("allowCredentials")]
|
||||
public List<Fido2CredentialDescriptor> AllowCredentials { get; set; }
|
||||
[JsonProperty("userVerification")]
|
||||
public string UserVerification { get; set; }
|
||||
[JsonProperty("extensions", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public object Extensions { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Models.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Response
|
||||
{
|
||||
public class Fido2RegistrationChallengeResponse
|
||||
{
|
||||
[JsonProperty("challenge")]
|
||||
public string Challenge { get; set; }
|
||||
[JsonProperty("timeout")]
|
||||
public double Timeout { get; set; }
|
||||
[JsonProperty("rp")]
|
||||
public Fido2RP Rp { get; set; }
|
||||
[JsonProperty("user")]
|
||||
public Fido2User User { get; set; }
|
||||
[JsonProperty("pubKeyCredParams")]
|
||||
public List<Fido2PubKeyCredParam> PubKeyCredParams { get; set; }
|
||||
[JsonProperty("excludeCredentials")]
|
||||
public List<Fido2CredentialDescriptor> ExcludeCredentials { get; set; }
|
||||
[JsonProperty("authenticatorSelection")]
|
||||
public Fido2AuthenticatorSelection AuthenticatorSelection { get; set; }
|
||||
[JsonProperty("attestation", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public object Attestation { get; set; }
|
||||
[JsonProperty("extensions", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public object Extensions { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user