diff --git a/src/App/Platforms/Android/AndroidManifest.xml b/src/App/Platforms/Android/AndroidManifest.xml index 62208bf8b..22d585242 100644 --- a/src/App/Platforms/Android/AndroidManifest.xml +++ b/src/App/Platforms/Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + diff --git a/src/App/Platforms/Android/Constants.cs b/src/App/Platforms/Android/Constants.cs index 398bfb708..b6fe75d1e 100644 --- a/src/App/Platforms/Android/Constants.cs +++ b/src/App/Platforms/Android/Constants.cs @@ -3,5 +3,11 @@ public static class Constants { public const string PACKAGE_NAME = "com.x8bit.bitwarden"; + public const string TEMP_CAMERA_IMAGE_NAME = "temp_camera_image.jpg"; + + /// + /// This directory must also be declared in filepaths.xml + /// + public const string TEMP_CAMERA_IMAGE_DIR = "camera_temp"; } } diff --git a/src/App/Platforms/Android/MainActivity.cs b/src/App/Platforms/Android/MainActivity.cs index 1f5f0fc51..ea72a165c 100644 --- a/src/App/Platforms/Android/MainActivity.cs +++ b/src/App/Platforms/Android/MainActivity.cs @@ -235,18 +235,22 @@ namespace Bit.Droid string fileName = null; if (data != null && data.Data != null) { - uri = data.Data; - fileName = AndroidHelpers.GetFileName(ApplicationContext, uri); + if (data.Data.ToString()?.Contains(Constants.PACKAGE_NAME) != true) + { + uri = data.Data; + fileName = AndroidHelpers.GetFileName(ApplicationContext, uri); + } } else { // camera - var file = new Java.IO.File(FilesDir, "temp_camera_photo.jpg"); + var tmpDir = new Java.IO.File(FilesDir, Constants.TEMP_CAMERA_IMAGE_DIR); + var file = new Java.IO.File(tmpDir, Constants.TEMP_CAMERA_IMAGE_NAME); uri = FileProvider.GetUriForFile(this, "com.x8bit.bitwarden.fileprovider", file); fileName = $"photo_{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.jpg"; } - if (uri == null) + if (uri == null || fileName == null) { return; } diff --git a/src/App/Platforms/Android/Resources/xml/filepaths.xml b/src/App/Platforms/Android/Resources/xml/filepaths.xml index be754fbbb..d8e6022f2 100644 --- a/src/App/Platforms/Android/Resources/xml/filepaths.xml +++ b/src/App/Platforms/Android/Resources/xml/filepaths.xml @@ -1,5 +1,5 @@  - + diff --git a/src/App/Platforms/Android/Services/FileService.cs b/src/App/Platforms/Android/Services/FileService.cs index 9fd7d8973..42dd9ec5a 100644 --- a/src/App/Platforms/Android/Services/FileService.cs +++ b/src/App/Platforms/Android/Services/FileService.cs @@ -191,7 +191,8 @@ namespace Bit.Droid.Services { try { - var file = new Java.IO.File(activity.FilesDir, "temp_camera_photo.jpg"); + var tmpDir = new Java.IO.File(activity.FilesDir, Constants.TEMP_CAMERA_IMAGE_DIR); + var file = new Java.IO.File(tmpDir, Constants.TEMP_CAMERA_IMAGE_NAME); if (!file.Exists()) { file.ParentFile.Mkdirs(); diff --git a/src/Core/Abstractions/ICipherService.cs b/src/Core/Abstractions/ICipherService.cs index 928f79686..b344bc101 100644 --- a/src/Core/Abstractions/ICipherService.cs +++ b/src/Core/Abstractions/ICipherService.cs @@ -10,12 +10,6 @@ namespace Bit.Core.Abstractions { public interface ICipherService { - public enum ShareWithServerError - { - None, - DuplicatedPasskeyInOrg - } - Task ClearAsync(string userId); Task ClearCacheAsync(); Task DeleteAsync(List ids); @@ -36,7 +30,7 @@ namespace Bit.Core.Abstractions Task SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data); Task SaveCollectionsWithServerAsync(Cipher cipher); Task SaveWithServerAsync(Cipher cipher); - Task ShareWithServerAsync(CipherView cipher, string organizationId, HashSet collectionIds); + Task ShareWithServerAsync(CipherView cipher, string organizationId, HashSet collectionIds); Task UpdateLastUsedDateAsync(string id); Task UpsertAsync(CipherData cipher); Task UpsertAsync(List cipher); diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 66582bdf9..427179776 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -62,5 +62,6 @@ namespace Bit.Core.Abstractions Task EncryptToBytesAsync(byte[] plainValue, SymmetricCryptoKey key = null); Task DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey); Task GetOrDeriveMasterKeyAsync(string password, string userId = null); + Task UpdateMasterKeyAndUserKeyAsync(MasterKey masterKey); } } diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 7fe9fe8f5..04641a6b0 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -69,9 +69,9 @@ namespace Bit.Core public const int MasterPasswordMinimumChars = 12; public const int CipherKeyRandomBytesLength = 64; public const string CipherKeyEncryptionMinServerVersion = "2023.9.1"; - public const string DefaultFido2KeyType = "public-key"; - public const string DefaultFido2KeyAlgorithm = "ECDSA"; - public const string DefaultFido2KeyCurve = "P-256"; + public const string DefaultFido2CredentialType = "public-key"; + public const string DefaultFido2CredentialAlgorithm = "ECDSA"; + public const string DefaultFido2CredentialCurve = "P-256"; public static readonly string[] AndroidAllClearCipherCacheKeys = { diff --git a/src/Core/Enums/DeviceType.cs b/src/Core/Enums/DeviceType.cs index 7c4b7065a..418329140 100644 --- a/src/Core/Enums/DeviceType.cs +++ b/src/Core/Enums/DeviceType.cs @@ -27,24 +27,4 @@ namespace Bit.Core.Enums VivaldiExtension = 19, SafariExtension = 20 } - - public static class DeviceTypeExtensions - { - public static List GetMobileTypes() => new List - { - DeviceType.Android, - DeviceType.AndroidAmazon, - DeviceType.iOS - }; - - public static List GetDesktopTypes() => new List - { - DeviceType.WindowsDesktop, - DeviceType.MacOsDesktop, - DeviceType.LinuxDesktop, - DeviceType.UWP, - }; - - public static List GetDesktopAndMobileTypes() => GetMobileTypes().Concat(GetDesktopTypes()).ToList(); - } } diff --git a/src/Core/Enums/ForwardedEmailServiceType.cs b/src/Core/Enums/ForwardedEmailServiceType.cs index b969e207d..8d73ed03e 100644 --- a/src/Core/Enums/ForwardedEmailServiceType.cs +++ b/src/Core/Enums/ForwardedEmailServiceType.cs @@ -15,5 +15,7 @@ namespace Bit.Core.Enums DuckDuckGo = 3, [LocalizableEnum("Fastmail")] Fastmail = 4, + [LocalizableEnum("ForwardEmail")] + ForwardEmail = 5, } } diff --git a/src/Core/Models/Api/Fido2KeyApi.cs b/src/Core/Models/Api/Fido2CredentialApi.cs similarity index 78% rename from src/Core/Models/Api/Fido2KeyApi.cs rename to src/Core/Models/Api/Fido2CredentialApi.cs index 40c5595d0..7953e06a1 100644 --- a/src/Core/Models/Api/Fido2KeyApi.cs +++ b/src/Core/Models/Api/Fido2CredentialApi.cs @@ -1,14 +1,15 @@ -using Bit.Core.Models.Domain; +using System; +using Bit.Core.Models.Domain; namespace Bit.Core.Models.Api { - public class Fido2KeyApi + public class Fido2CredentialApi { - public Fido2KeyApi() + public Fido2CredentialApi() { } - public Fido2KeyApi(Fido2Key fido2Key) + public Fido2CredentialApi(Fido2Credential fido2Key) { CredentialId = fido2Key.CredentialId?.EncryptedString; Discoverable = fido2Key.Discoverable?.EncryptedString; @@ -21,18 +22,20 @@ namespace Bit.Core.Models.Api UserHandle = fido2Key.UserHandle?.EncryptedString; UserName = fido2Key.UserName?.EncryptedString; Counter = fido2Key.Counter?.EncryptedString; + CreationDate = fido2Key.CreationDate; } public string CredentialId { get; set; } public string Discoverable { get; set; } - public string KeyType { get; set; } = Constants.DefaultFido2KeyType; - public string KeyAlgorithm { get; set; } = Constants.DefaultFido2KeyAlgorithm; - public string KeyCurve { get; set; } = Constants.DefaultFido2KeyCurve; + public string KeyType { get; set; } = Constants.DefaultFido2CredentialType; + public string KeyAlgorithm { get; set; } = Constants.DefaultFido2CredentialAlgorithm; + public string KeyCurve { get; set; } = Constants.DefaultFido2CredentialCurve; public string KeyValue { get; set; } public string RpId { get; set; } public string RpName { get; set; } public string UserHandle { get; set; } public string UserName { get; set; } public string Counter { get; set; } + public DateTime CreationDate { get; set; } } } diff --git a/src/Core/Models/Api/LoginApi.cs b/src/Core/Models/Api/LoginApi.cs index 2ebefc0c3..2d4c1d851 100644 --- a/src/Core/Models/Api/LoginApi.cs +++ b/src/Core/Models/Api/LoginApi.cs @@ -10,6 +10,6 @@ namespace Bit.Core.Models.Api public string Password { get; set; } public DateTime? PasswordRevisionDate { get; set; } public string Totp { get; set; } - public List Fido2Keys { get; set; } + public List Fido2Credentials { get; set; } } } diff --git a/src/Core/Models/Data/Fido2KeyData.cs b/src/Core/Models/Data/Fido2CredentialData.cs similarity index 74% rename from src/Core/Models/Data/Fido2KeyData.cs rename to src/Core/Models/Data/Fido2CredentialData.cs index aa1fd8e39..846df59f4 100644 --- a/src/Core/Models/Data/Fido2KeyData.cs +++ b/src/Core/Models/Data/Fido2CredentialData.cs @@ -1,12 +1,13 @@ -using Bit.Core.Models.Api; +using System; +using Bit.Core.Models.Api; namespace Bit.Core.Models.Data { - public class Fido2KeyData : Data + public class Fido2CredentialData : Data { - public Fido2KeyData() { } + public Fido2CredentialData() { } - public Fido2KeyData(Fido2KeyApi apiData) + public Fido2CredentialData(Fido2CredentialApi apiData) { CredentialId = apiData.CredentialId; Discoverable = apiData.Discoverable; @@ -19,18 +20,20 @@ namespace Bit.Core.Models.Data UserHandle = apiData.UserHandle; UserName = apiData.UserName; Counter = apiData.Counter; + CreationDate = apiData.CreationDate; } public string CredentialId { get; set; } public string Discoverable { get; set; } - public string KeyType { get; set; } = Constants.DefaultFido2KeyType; - public string KeyAlgorithm { get; set; } = Constants.DefaultFido2KeyAlgorithm; - public string KeyCurve { get; set; } = Constants.DefaultFido2KeyCurve; + public string KeyType { get; set; } = Constants.DefaultFido2CredentialType; + public string KeyAlgorithm { get; set; } = Constants.DefaultFido2CredentialAlgorithm; + public string KeyCurve { get; set; } = Constants.DefaultFido2CredentialCurve; public string KeyValue { get; set; } public string RpId { get; set; } public string RpName { get; set; } public string UserHandle { get; set; } public string UserName { get; set; } public string Counter { get; set; } + public DateTime CreationDate { get; set; } } } diff --git a/src/Core/Models/Data/LoginData.cs b/src/Core/Models/Data/LoginData.cs index bc71df1af..ede56065f 100644 --- a/src/Core/Models/Data/LoginData.cs +++ b/src/Core/Models/Data/LoginData.cs @@ -16,7 +16,7 @@ namespace Bit.Core.Models.Data PasswordRevisionDate = data.PasswordRevisionDate; Totp = data.Totp; Uris = data.Uris?.Select(u => new LoginUriData(u)).ToList(); - Fido2Keys = data.Fido2Keys?.Select(f => new Fido2KeyData(f)).ToList(); + Fido2Credentials = data.Fido2Credentials?.Select(f => new Fido2CredentialData(f)).ToList(); } public List Uris { get; set; } @@ -24,6 +24,6 @@ namespace Bit.Core.Models.Data public string Password { get; set; } public DateTime? PasswordRevisionDate { get; set; } public string Totp { get; set; } - public List Fido2Keys { get; set; } + public List Fido2Credentials { get; set; } } } diff --git a/src/Core/Models/Domain/Fido2Credential.cs b/src/Core/Models/Domain/Fido2Credential.cs new file mode 100644 index 000000000..7c6928204 --- /dev/null +++ b/src/Core/Models/Domain/Fido2Credential.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Bit.Core.Models.Data; +using Bit.Core.Models.View; + +namespace Bit.Core.Models.Domain +{ + public class Fido2Credential : Domain + { + public static HashSet EncryptablePropertiesToMap => new HashSet + { + nameof(CredentialId), + nameof(Discoverable), + nameof(KeyType), + nameof(KeyAlgorithm), + nameof(KeyCurve), + nameof(KeyValue), + nameof(RpId), + nameof(RpName), + nameof(UserHandle), + nameof(UserName), + nameof(Counter) + }; + + public static HashSet NonEncryptablePropertiesToMap => new HashSet + { + nameof(CreationDate) + }; + + public static HashSet AllPropertiesToMap => new HashSet(EncryptablePropertiesToMap.Concat(NonEncryptablePropertiesToMap)); + + public Fido2Credential() { } + + public Fido2Credential(Fido2CredentialData data, bool alreadyEncrypted = false) + { + BuildDomainModel(this, data, AllPropertiesToMap, alreadyEncrypted, NonEncryptablePropertiesToMap); + } + + public EncString CredentialId { get; set; } + public EncString Discoverable { get; set; } + public EncString KeyType { get; set; } + public EncString KeyAlgorithm { get; set; } + public EncString KeyCurve { get; set; } + public EncString KeyValue { get; set; } + public EncString RpId { get; set; } + public EncString RpName { get; set; } + public EncString UserHandle { get; set; } + public EncString UserName { get; set; } + public EncString Counter { get; set; } + public DateTime CreationDate { get; set; } + + public async Task DecryptAsync(string orgId, SymmetricCryptoKey key = null) + { + return await DecryptObjAsync(new Fido2CredentialView(this), this, EncryptablePropertiesToMap, orgId, key); + } + + public Fido2CredentialData ToFido2CredentialData() + { + var data = new Fido2CredentialData(); + BuildDataModel(this, data, AllPropertiesToMap, NonEncryptablePropertiesToMap); + return data; + } + } +} diff --git a/src/Core/Models/Domain/Fido2Key.cs b/src/Core/Models/Domain/Fido2Key.cs deleted file mode 100644 index 504830fd7..000000000 --- a/src/Core/Models/Domain/Fido2Key.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.Core.Models.Data; -using Bit.Core.Models.View; - -namespace Bit.Core.Models.Domain -{ - public class Fido2Key : Domain - { - public static HashSet EncryptableProperties => new HashSet - { - nameof(CredentialId), - nameof(Discoverable), - nameof(KeyType), - nameof(KeyAlgorithm), - nameof(KeyCurve), - nameof(KeyValue), - nameof(RpId), - nameof(RpName), - nameof(UserHandle), - nameof(UserName), - nameof(Counter) - }; - - public Fido2Key() { } - - public Fido2Key(Fido2KeyData data, bool alreadyEncrypted = false) - { - BuildDomainModel(this, data, EncryptableProperties, alreadyEncrypted); - } - - public EncString CredentialId { get; set; } - public EncString Discoverable { get; set; } - public EncString KeyType { get; set; } - public EncString KeyAlgorithm { get; set; } - public EncString KeyCurve { get; set; } - public EncString KeyValue { get; set; } - public EncString RpId { get; set; } - public EncString RpName { get; set; } - public EncString UserHandle { get; set; } - public EncString UserName { get; set; } - public EncString Counter { get; set; } - - public async Task DecryptAsync(string orgId, SymmetricCryptoKey key = null) - { - return await DecryptObjAsync(new Fido2KeyView(), this, EncryptableProperties, orgId, key); - } - - public Fido2KeyData ToFido2KeyData() - { - var data = new Fido2KeyData(); - BuildDataModel(this, data, EncryptableProperties); - return data; - } - } -} diff --git a/src/Core/Models/Domain/Login.cs b/src/Core/Models/Domain/Login.cs index 43900b179..ed1822c13 100644 --- a/src/Core/Models/Domain/Login.cs +++ b/src/Core/Models/Domain/Login.cs @@ -15,7 +15,7 @@ namespace Bit.Core.Models.Domain { PasswordRevisionDate = obj.PasswordRevisionDate; Uris = obj.Uris?.Select(u => new LoginUri(u, alreadyEncrypted)).ToList(); - Fido2Keys = obj.Fido2Keys?.Select(f => new Fido2Key(f, alreadyEncrypted)).ToList(); + Fido2Credentials = obj.Fido2Credentials?.Select(f => new Fido2Credential(f, alreadyEncrypted)).ToList(); BuildDomainModel(this, obj, new HashSet { "Username", @@ -29,7 +29,7 @@ namespace Bit.Core.Models.Domain public EncString Password { get; set; } public DateTime? PasswordRevisionDate { get; set; } public EncString Totp { get; set; } - public List Fido2Keys { get; set; } + public List Fido2Credentials { get; set; } public async Task DecryptAsync(string orgId, SymmetricCryptoKey key = null) { @@ -47,12 +47,12 @@ namespace Bit.Core.Models.Domain view.Uris.Add(await uri.DecryptAsync(orgId, key)); } } - if (Fido2Keys != null) + if (Fido2Credentials != null) { - view.Fido2Keys = new List(); - foreach (var fido2Key in Fido2Keys) + view.Fido2Credentials = new List(); + foreach (var fido2Credential in Fido2Credentials) { - view.Fido2Keys.Add(await fido2Key.DecryptAsync(orgId, key)); + view.Fido2Credentials.Add(await fido2Credential.DecryptAsync(orgId, key)); } } return view; @@ -72,9 +72,9 @@ namespace Bit.Core.Models.Domain { l.Uris = Uris.Select(u => u.ToLoginUriData()).ToList(); } - if (Fido2Keys != null) + if (Fido2Credentials != null) { - l.Fido2Keys = Fido2Keys.Select(f => f.ToFido2KeyData()).ToList(); + l.Fido2Credentials = Fido2Credentials.Select(f => f.ToFido2CredentialData()).ToList(); } return l; } diff --git a/src/Core/Models/Domain/UsernameGenerationOptions.cs b/src/Core/Models/Domain/UsernameGenerationOptions.cs index deb98521d..554783b66 100644 --- a/src/Core/Models/Domain/UsernameGenerationOptions.cs +++ b/src/Core/Models/Domain/UsernameGenerationOptions.cs @@ -24,6 +24,8 @@ namespace Bit.Core.Models.Domain public string FastMailApiKey { get; set; } public string AnonAddyApiAccessToken { get; set; } public string AnonAddyDomainName { get; set; } + public string ForwardEmailApiAccessToken { get; set; } + public string ForwardEmailDomainName { get; set; } public string EmailWebsite { get; set; } public ForwarderOptions GetForwarderOptions() @@ -49,6 +51,12 @@ namespace Bit.Core.Models.Domain return new ForwarderOptions { ApiKey = FirefoxRelayApiAccessToken }; case ForwardedEmailServiceType.SimpleLogin: return new ForwarderOptions { ApiKey = SimpleLoginApiKey }; + case ForwardedEmailServiceType.ForwardEmail: + return new ForwardEmailForwarderOptions + { + ApiKey = ForwardEmailApiAccessToken, + DomainName = ForwardEmailDomainName + }; default: return null; } diff --git a/src/Core/Models/Request/CipherRequest.cs b/src/Core/Models/Request/CipherRequest.cs index bef11566c..f0b44d402 100644 --- a/src/Core/Models/Request/CipherRequest.cs +++ b/src/Core/Models/Request/CipherRequest.cs @@ -32,7 +32,7 @@ namespace Bit.Core.Models.Request Password = cipher.Login.Password?.EncryptedString, PasswordRevisionDate = cipher.Login.PasswordRevisionDate, Totp = cipher.Login.Totp?.EncryptedString, - Fido2Keys = cipher.Login.Fido2Keys?.Select(f => new Fido2KeyApi(f)).ToList() + Fido2Credentials = cipher.Login.Fido2Credentials?.Select(f => new Fido2CredentialApi(f)).ToList() }; break; case CipherType.Card: diff --git a/src/Core/Models/View/CipherView.cs b/src/Core/Models/View/CipherView.cs index 01c86f450..df8a47eb4 100644 --- a/src/Core/Models/View/CipherView.cs +++ b/src/Core/Models/View/CipherView.cs @@ -121,6 +121,6 @@ namespace Bit.Core.Models.View public bool IsClonable => OrganizationId is null; - public bool HasFido2Key => Type == CipherType.Login && Login?.HasFido2Keys == true; + public bool HasFido2Credential => Type == CipherType.Login && Login?.HasFido2Credentials == true; } } diff --git a/src/Core/Models/View/Fido2KeyView.cs b/src/Core/Models/View/Fido2CredentialView.cs similarity index 62% rename from src/Core/Models/View/Fido2KeyView.cs rename to src/Core/Models/View/Fido2CredentialView.cs index 20a4d0ee1..049d82047 100644 --- a/src/Core/Models/View/Fido2KeyView.cs +++ b/src/Core/Models/View/Fido2CredentialView.cs @@ -1,21 +1,33 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Bit.Core.Enums; +using Bit.Core.Models.Domain; namespace Bit.Core.Models.View { - public class Fido2KeyView : ItemView, ILaunchableView + public class Fido2CredentialView : ItemView, ILaunchableView { + public Fido2CredentialView() + { + } + + public Fido2CredentialView(Fido2Credential fido2Credential) + { + CreationDate = fido2Credential.CreationDate; + } + public string CredentialId { get; set; } public string Discoverable { get; set; } - public string KeyType { get; set; } = Constants.DefaultFido2KeyType; - public string KeyAlgorithm { get; set; } = Constants.DefaultFido2KeyAlgorithm; - public string KeyCurve { get; set; } = Constants.DefaultFido2KeyCurve; + public string KeyType { get; set; } = Constants.DefaultFido2CredentialType; + public string KeyAlgorithm { get; set; } = Constants.DefaultFido2CredentialAlgorithm; + public string KeyCurve { get; set; } = Constants.DefaultFido2CredentialCurve; public string KeyValue { get; set; } public string RpId { get; set; } public string RpName { get; set; } public string UserHandle { get; set; } public string UserName { get; set; } public string Counter { get; set; } + public DateTime CreationDate { get; set; } public override string SubTitle => UserName; public override List> LinkedFieldOptions => new List>(); @@ -23,6 +35,6 @@ namespace Bit.Core.Models.View public bool CanLaunch => !string.IsNullOrEmpty(RpId); public string LaunchUri => $"https://{RpId}"; - public bool IsUniqueAgainst(Fido2KeyView fido2View) => fido2View?.RpId != RpId || fido2View?.UserName != UserName; + public bool IsUniqueAgainst(Fido2CredentialView fido2View) => fido2View?.RpId != RpId || fido2View?.UserName != UserName; } } diff --git a/src/Core/Models/View/LoginView.cs b/src/Core/Models/View/LoginView.cs index bece3a9ce..9993c2f11 100644 --- a/src/Core/Models/View/LoginView.cs +++ b/src/Core/Models/View/LoginView.cs @@ -20,7 +20,7 @@ namespace Bit.Core.Models.View public DateTime? PasswordRevisionDate { get; set; } public string Totp { get; set; } public List Uris { get; set; } - public List Fido2Keys { get; set; } + public List Fido2Credentials { get; set; } public string Uri => HasUris ? Uris[0].Uri : null; public string MaskedPassword => Password != null ? "••••••••" : null; @@ -28,8 +28,8 @@ namespace Bit.Core.Models.View public bool CanLaunch => HasUris && Uris.Any(u => u.CanLaunch); public string LaunchUri => HasUris ? Uris.FirstOrDefault(u => u.CanLaunch)?.LaunchUri : null; public bool HasUris => (Uris?.Count ?? 0) > 0; - public bool HasFido2Keys => Fido2Keys?.Any() == true; - public Fido2KeyView MainFido2Key => HasFido2Keys ? Fido2Keys[0] : null; + public bool HasFido2Credentials => Fido2Credentials?.Any() == true; + public Fido2CredentialView MainFido2Credential => HasFido2Credentials ? Fido2Credentials[0] : null; public override List> LinkedFieldOptions { diff --git a/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml b/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml index 28b67a4e5..910798b97 100644 --- a/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml +++ b/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml @@ -18,15 +18,16 @@ + AutomationId="RememberThisDeviceSwitch" + VerticalOptions="Center" /> + Clicked="LogIn_Clicked" + AutomationId="LogInButton" /> diff --git a/src/Core/Pages/Generator/GeneratorPage.xaml b/src/Core/Pages/Generator/GeneratorPage.xaml index d2343175e..f368e712b 100644 --- a/src/Core/Pages/Generator/GeneratorPage.xaml +++ b/src/Core/Pages/Generator/GeneratorPage.xaml @@ -279,6 +279,15 @@ Text="{Binding AddyIoDomainName}" StyleClass="box-value" AutomationId="AnonAddyDomainNameEntry" /> +