2022-06-08 19:24:01 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AuthenticationServices;
|
2019-09-04 17:52:32 +02:00
|
|
|
|
using Bit.App.Abstractions;
|
2022-06-08 19:24:01 +02:00
|
|
|
|
using Bit.App.Models;
|
|
|
|
|
using Bit.App.Pages;
|
|
|
|
|
using Bit.App.Utilities;
|
|
|
|
|
using Bit.App.Utilities.AccountManagement;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
using Bit.Core.Abstractions;
|
2022-06-08 19:24:01 +02:00
|
|
|
|
using Bit.Core.Enums;
|
2022-07-15 00:17:04 +02:00
|
|
|
|
using Bit.Core.Services;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
using Bit.Core.Utilities;
|
|
|
|
|
using Bit.iOS.Autofill.Models;
|
|
|
|
|
using Bit.iOS.Core.Utilities;
|
2022-06-08 19:24:01 +02:00
|
|
|
|
using Bit.iOS.Core.Views;
|
2022-07-15 00:17:04 +02:00
|
|
|
|
using CoreFoundation;
|
2022-06-08 19:24:01 +02:00
|
|
|
|
using CoreNFC;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
using Foundation;
|
|
|
|
|
using UIKit;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
using Xamarin.Forms;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
|
|
|
|
|
namespace Bit.iOS.Autofill
|
|
|
|
|
{
|
2022-06-08 19:24:01 +02:00
|
|
|
|
public partial class CredentialProviderViewController : ASCredentialProviderViewController, IAccountsManagerHost
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
|
|
|
|
private Context _context;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
private NFCNdefReaderSession _nfcSession = null;
|
|
|
|
|
private Core.NFCReaderDelegate _nfcDelegate = null;
|
2022-06-08 19:24:01 +02:00
|
|
|
|
private IAccountsManager _accountsManager;
|
|
|
|
|
|
|
|
|
|
private readonly LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>("stateService");
|
2019-06-28 14:21:44 +02:00
|
|
|
|
|
|
|
|
|
public CredentialProviderViewController(IntPtr handle)
|
|
|
|
|
: base(handle)
|
2019-10-01 03:17:53 +02:00
|
|
|
|
{
|
|
|
|
|
ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
|
|
|
|
|
public override void ViewDidLoad()
|
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
InitApp();
|
|
|
|
|
base.ViewDidLoad();
|
|
|
|
|
Logo.Image = new UIImage(ThemeHelpers.LightTheme ? "logo.png" : "logo_white.png");
|
|
|
|
|
View.BackgroundColor = ThemeHelpers.SplashBackgroundColor;
|
|
|
|
|
_context = new Context
|
|
|
|
|
{
|
|
|
|
|
ExtContext = ExtensionContext
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
public override async void PrepareCredentialList(ASCredentialServiceIdentifier[] serviceIdentifiers)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
InitAppIfNeeded();
|
|
|
|
|
_context.ServiceIdentifiers = serviceIdentifiers;
|
|
|
|
|
if (serviceIdentifiers.Length > 0)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
var uri = serviceIdentifiers[0].Identifier;
|
|
|
|
|
if (serviceIdentifiers[0].Type == ASCredentialServiceIdentifierType.Domain)
|
|
|
|
|
{
|
|
|
|
|
uri = string.Concat("https://", uri);
|
|
|
|
|
}
|
|
|
|
|
_context.UrlString = uri;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (!await IsAuthed())
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
await _accountsManager.NavigateOnAccountChangeAsync(false);
|
|
|
|
|
}
|
|
|
|
|
else if (await IsLocked())
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("lockPasswordSegue", this);
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (_context.ServiceIdentifiers == null || _context.ServiceIdentifiers.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("loginSearchSegue", this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("loginListSegue", this);
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
public override async void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
InitAppIfNeeded();
|
|
|
|
|
await _stateService.Value.SetPasswordRepromptAutofillAsync(false);
|
|
|
|
|
await _stateService.Value.SetPasswordVerifiedAutofillAsync(false);
|
|
|
|
|
if (!await IsAuthed() || await IsLocked())
|
|
|
|
|
{
|
|
|
|
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
|
|
|
|
Convert.ToInt32(ASExtensionErrorCode.UserInteractionRequired), null);
|
|
|
|
|
ExtensionContext.CancelRequest(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_context.CredentialIdentity = credentialIdentity;
|
|
|
|
|
await ProvideCredentialAsync(false);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
public override async void PrepareInterfaceToProvideCredential(ASPasswordCredentialIdentity credentialIdentity)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
InitAppIfNeeded();
|
|
|
|
|
if (!await IsAuthed())
|
|
|
|
|
{
|
|
|
|
|
await _accountsManager.NavigateOnAccountChangeAsync(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_context.CredentialIdentity = credentialIdentity;
|
|
|
|
|
await CheckLockAsync(async () => await ProvideCredentialAsync());
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
public override async void PrepareInterfaceForExtensionConfiguration()
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
InitAppIfNeeded();
|
|
|
|
|
_context.Configuring = true;
|
|
|
|
|
if (!await IsAuthed())
|
|
|
|
|
{
|
|
|
|
|
await _accountsManager.NavigateOnAccountChangeAsync(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await CheckLockAsync(() => PerformSegue("setupSegue", this));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-22 21:50:59 +02:00
|
|
|
|
public void CompleteRequest(string id = null, string username = null,
|
|
|
|
|
string password = null, string totp = null)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if ((_context?.Configuring ?? true) && string.IsNullOrWhiteSpace(password))
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2019-07-23 03:35:05 +02:00
|
|
|
|
ServiceContainer.Reset();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
ExtensionContext?.CompleteExtensionConfigurationRequest();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (_context == null || string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2019-07-23 03:35:05 +02:00
|
|
|
|
ServiceContainer.Reset();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
|
|
|
|
Convert.ToInt32(ASExtensionErrorCode.UserCanceled), null);
|
|
|
|
|
NSRunLoop.Main.BeginInvokeOnMainThread(() => ExtensionContext?.CancelRequest(err));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(totp))
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
|
|
|
|
UIPasteboard.General.String = totp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var cred = new ASPasswordCredential(username, password);
|
2019-07-23 03:35:05 +02:00
|
|
|
|
NSRunLoop.Main.BeginInvokeOnMainThread(async () =>
|
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(id))
|
2019-07-24 16:42:13 +02:00
|
|
|
|
{
|
|
|
|
|
var eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
|
|
|
|
await eventService.CollectAsync(Bit.Core.Enums.EventType.Cipher_ClientAutofilled, id);
|
|
|
|
|
}
|
2019-07-23 03:35:05 +02:00
|
|
|
|
ServiceContainer.Reset();
|
|
|
|
|
ExtensionContext?.CompleteRequest(cred, null);
|
|
|
|
|
});
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (segue.DestinationViewController is UINavigationController navController)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (navController.TopViewController is LoginListViewController listLoginController)
|
|
|
|
|
{
|
|
|
|
|
listLoginController.Context = _context;
|
|
|
|
|
listLoginController.CPViewController = this;
|
|
|
|
|
segue.DestinationViewController.PresentationController.Delegate =
|
|
|
|
|
new CustomPresentationControllerDelegate(listLoginController.DismissModalAction);
|
|
|
|
|
}
|
|
|
|
|
else if (navController.TopViewController is LoginSearchViewController listSearchController)
|
|
|
|
|
{
|
|
|
|
|
listSearchController.Context = _context;
|
|
|
|
|
listSearchController.CPViewController = this;
|
|
|
|
|
segue.DestinationViewController.PresentationController.Delegate =
|
|
|
|
|
new CustomPresentationControllerDelegate(listSearchController.DismissModalAction);
|
|
|
|
|
}
|
|
|
|
|
else if (navController.TopViewController is LockPasswordViewController passwordViewController)
|
|
|
|
|
{
|
|
|
|
|
passwordViewController.CPViewController = this;
|
|
|
|
|
segue.DestinationViewController.PresentationController.Delegate =
|
|
|
|
|
new CustomPresentationControllerDelegate(passwordViewController.DismissModalAction);
|
|
|
|
|
}
|
|
|
|
|
else if (navController.TopViewController is SetupViewController setupViewController)
|
|
|
|
|
{
|
|
|
|
|
setupViewController.CPViewController = this;
|
|
|
|
|
segue.DestinationViewController.PresentationController.Delegate =
|
|
|
|
|
new CustomPresentationControllerDelegate(setupViewController.DismissModalAction);
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DismissLockAndContinue()
|
|
|
|
|
{
|
|
|
|
|
DismissViewController(false, async () =>
|
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (_context.CredentialIdentity != null)
|
|
|
|
|
{
|
|
|
|
|
await ProvideCredentialAsync();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (_context.Configuring)
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("setupSegue", this);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (_context.ServiceIdentifiers == null || _context.ServiceIdentifiers.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("loginSearchSegue", this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PerformSegue("loginListSegue", this);
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
catch (Exception ex)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 17:57:18 +02:00
|
|
|
|
private async Task ProvideCredentialAsync(bool userInteraction = true)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2021-06-10 17:57:18 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService", true);
|
|
|
|
|
Bit.Core.Models.Domain.Cipher cipher = null;
|
|
|
|
|
var cancel = cipherService == null || _context.CredentialIdentity?.RecordIdentifier == null;
|
|
|
|
|
if (!cancel)
|
|
|
|
|
{
|
|
|
|
|
cipher = await cipherService.GetAsync(_context.CredentialIdentity.RecordIdentifier);
|
|
|
|
|
cancel = cipher == null || cipher.Type != Bit.Core.Enums.CipherType.Login || cipher.Login == null;
|
|
|
|
|
}
|
|
|
|
|
if (cancel)
|
2021-06-10 17:57:18 +02:00
|
|
|
|
{
|
|
|
|
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
2022-07-15 00:17:04 +02:00
|
|
|
|
Convert.ToInt32(ASExtensionErrorCode.CredentialIdentityNotFound), null);
|
2021-06-10 17:57:18 +02:00
|
|
|
|
ExtensionContext?.CancelRequest(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
|
|
|
|
|
var decCipher = await cipher.DecryptAsync();
|
|
|
|
|
if (decCipher.Reprompt != Bit.Core.Enums.CipherRepromptType.None)
|
2021-06-10 17:57:18 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
// Prompt for password using either the lock screen or dialog unless
|
|
|
|
|
// already verified the password.
|
|
|
|
|
if (!userInteraction)
|
2021-06-10 17:57:18 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
await _stateService.Value.SetPasswordRepromptAutofillAsync(true);
|
2021-06-10 17:57:18 +02:00
|
|
|
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
2022-07-15 00:17:04 +02:00
|
|
|
|
Convert.ToInt32(ASExtensionErrorCode.UserInteractionRequired), null);
|
2021-06-10 17:57:18 +02:00
|
|
|
|
ExtensionContext?.CancelRequest(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
else if (!await _stateService.Value.GetPasswordVerifiedAutofillAsync())
|
|
|
|
|
{
|
|
|
|
|
// Add a timeout to resolve keyboard not always showing up.
|
|
|
|
|
await Task.Delay(250);
|
|
|
|
|
var passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
|
|
|
|
if (!await passwordRepromptService.ShowPasswordPromptAsync())
|
|
|
|
|
{
|
|
|
|
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
|
|
|
|
Convert.ToInt32(ASExtensionErrorCode.UserCanceled), null);
|
|
|
|
|
ExtensionContext?.CancelRequest(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-10 17:57:18 +02:00
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
string totpCode = null;
|
|
|
|
|
var disableTotpCopy = await _stateService.Value.GetDisableAutoTotpCopyAsync();
|
|
|
|
|
if (!disableTotpCopy.GetValueOrDefault(false))
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
var canAccessPremiumAsync = await _stateService.Value.CanAccessPremiumAsync();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(decCipher.Login.Totp) &&
|
|
|
|
|
(canAccessPremiumAsync || cipher.OrganizationUseTotp))
|
|
|
|
|
{
|
|
|
|
|
var totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
|
|
|
|
totpCode = await totpService.GetCodeAsync(decCipher.Login.Totp);
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 00:17:04 +02:00
|
|
|
|
CompleteRequest(decCipher.Id, decCipher.Login.Username, decCipher.Login.Password, totpCode);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 00:17:04 +02:00
|
|
|
|
private async Task CheckLockAsync(Action notLockedAction)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-06-08 19:24:01 +02:00
|
|
|
|
if (await IsLocked() || await _stateService.Value.GetPasswordRepromptAutofillAsync())
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
DispatchQueue.MainQueue.DispatchAsync(() => PerformSegue("lockPasswordSegue", this));
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
notLockedAction();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
private Task<bool> IsLocked()
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2020-05-29 18:26:36 +02:00
|
|
|
|
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
2020-06-07 06:15:51 +02:00
|
|
|
|
return vaultTimeoutService.IsLockedAsync();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 06:15:51 +02:00
|
|
|
|
private Task<bool> IsAuthed()
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2022-06-08 19:24:01 +02:00
|
|
|
|
return _stateService.Value.IsAuthenticatedAsync();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 20:14:26 +02:00
|
|
|
|
private void LogoutIfAuthed()
|
|
|
|
|
{
|
|
|
|
|
NSRunLoop.Main.BeginInvokeOnMainThread(async () =>
|
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
try
|
2021-09-24 20:14:26 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
if (await IsAuthed())
|
2021-09-24 20:14:26 +02:00
|
|
|
|
{
|
2022-07-15 00:17:04 +02:00
|
|
|
|
await AppHelpers.LogOutAsync(await _stateService.Value.GetActiveUserIdAsync());
|
|
|
|
|
if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
|
|
|
|
|
{
|
|
|
|
|
await ASCredentialIdentityStore.SharedStore?.RemoveAllCredentialIdentitiesAsync();
|
|
|
|
|
}
|
2021-09-24 20:14:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-15 00:17:04 +02:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
|
|
|
}
|
2021-09-24 20:14:26 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 14:21:44 +02:00
|
|
|
|
private void InitApp()
|
|
|
|
|
{
|
2020-05-29 18:26:36 +02:00
|
|
|
|
// Init Xamarin Forms
|
|
|
|
|
Forms.Init();
|
|
|
|
|
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (ServiceContainer.RegisteredServices.Count > 0)
|
2019-06-28 14:21:44 +02:00
|
|
|
|
{
|
2019-07-03 02:45:54 +02:00
|
|
|
|
ServiceContainer.Reset();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
|
|
|
|
iOSCoreHelpers.RegisterLocalServices();
|
2019-09-04 17:52:32 +02:00
|
|
|
|
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
2020-05-29 18:26:36 +02:00
|
|
|
|
var messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
2020-10-13 21:39:36 +02:00
|
|
|
|
ServiceContainer.Init(deviceActionService.DeviceUserAgent,
|
|
|
|
|
Bit.Core.Constants.iOSAutoFillClearCiphersCacheKey, Bit.Core.Constants.iOSAllClearCipherCacheKeys);
|
2022-05-18 18:59:19 +02:00
|
|
|
|
iOSCoreHelpers.InitLogger();
|
2019-06-28 14:21:44 +02:00
|
|
|
|
iOSCoreHelpers.Bootstrap();
|
2022-06-08 19:24:01 +02:00
|
|
|
|
var appOptions = new AppOptions { IosExtension = true };
|
|
|
|
|
var app = new App.App(appOptions);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2021-10-08 14:47:40 +02:00
|
|
|
|
iOSCoreHelpers.AppearanceAdjustments();
|
2020-05-29 18:26:36 +02:00
|
|
|
|
_nfcDelegate = new Core.NFCReaderDelegate((success, message) =>
|
|
|
|
|
messagingService.Send("gotYubiKeyOTP", message));
|
|
|
|
|
iOSCoreHelpers.SubscribeBroadcastReceiver(this, _nfcSession, _nfcDelegate);
|
2022-06-08 19:24:01 +02:00
|
|
|
|
|
|
|
|
|
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
|
|
|
|
|
_accountsManager.Init(() => appOptions, this);
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
2019-07-22 14:22:02 +02:00
|
|
|
|
|
|
|
|
|
private void InitAppIfNeeded()
|
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (ServiceContainer.RegisteredServices == null || ServiceContainer.RegisteredServices.Count == 0)
|
2019-07-22 14:22:02 +02:00
|
|
|
|
{
|
|
|
|
|
InitApp();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-29 18:26:36 +02:00
|
|
|
|
|
2020-09-03 18:30:40 +02:00
|
|
|
|
private void LaunchHomePage()
|
2020-05-29 18:26:36 +02:00
|
|
|
|
{
|
2020-09-03 18:30:40 +02:00
|
|
|
|
var homePage = new HomePage();
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-09-03 18:30:40 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(homePage);
|
|
|
|
|
if (homePage.BindingContext is HomeViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.StartLoginAction = () => DismissViewController(false, () => LaunchLoginFlow());
|
|
|
|
|
vm.StartRegisterAction = () => DismissViewController(false, () => LaunchRegisterFlow());
|
|
|
|
|
vm.StartSsoLoginAction = () => DismissViewController(false, () => LaunchLoginSsoFlow());
|
|
|
|
|
vm.StartEnvironmentAction = () => DismissViewController(false, () => LaunchEnvironmentFlow());
|
|
|
|
|
vm.CloseAction = () => CompleteRequest();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(homePage);
|
|
|
|
|
var loginController = navigationPage.CreateViewController();
|
|
|
|
|
loginController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(loginController, true, null);
|
2021-09-24 20:14:26 +02:00
|
|
|
|
|
|
|
|
|
LogoutIfAuthed();
|
2020-09-03 18:30:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LaunchEnvironmentFlow()
|
|
|
|
|
{
|
|
|
|
|
var environmentPage = new EnvironmentPage();
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-09-03 18:30:40 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(environmentPage);
|
|
|
|
|
if (environmentPage.BindingContext is EnvironmentPageViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.SubmitSuccessAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(environmentPage);
|
|
|
|
|
var loginController = navigationPage.CreateViewController();
|
|
|
|
|
loginController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(loginController, true, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LaunchRegisterFlow()
|
|
|
|
|
{
|
|
|
|
|
var registerPage = new RegisterPage(null);
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-09-03 18:30:40 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(registerPage);
|
|
|
|
|
if (registerPage.BindingContext is RegisterPageViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.RegistrationSuccess = () => DismissViewController(false, () => LaunchLoginFlow(vm.Email));
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(registerPage);
|
|
|
|
|
var loginController = navigationPage.CreateViewController();
|
|
|
|
|
loginController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(loginController, true, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LaunchLoginFlow(string email = null)
|
|
|
|
|
{
|
|
|
|
|
var loginPage = new LoginPage(email);
|
2020-05-29 21:25:06 +02:00
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-05-29 18:26:36 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(loginPage);
|
|
|
|
|
if (loginPage.BindingContext is LoginPageViewModel vm)
|
|
|
|
|
{
|
2020-09-03 18:30:40 +02:00
|
|
|
|
vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(false));
|
2021-09-24 20:14:26 +02:00
|
|
|
|
vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow());
|
2020-09-03 18:30:40 +02:00
|
|
|
|
vm.LogInSuccessAction = () => DismissLockAndContinue();
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage());
|
2020-05-29 18:26:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(loginPage);
|
|
|
|
|
var loginController = navigationPage.CreateViewController();
|
|
|
|
|
loginController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(loginController, true, null);
|
2021-09-24 20:14:26 +02:00
|
|
|
|
|
|
|
|
|
LogoutIfAuthed();
|
2020-05-29 18:26:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 18:30:40 +02:00
|
|
|
|
private void LaunchLoginSsoFlow()
|
|
|
|
|
{
|
|
|
|
|
var loginPage = new LoginSsoPage();
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-09-03 18:30:40 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(loginPage);
|
|
|
|
|
if (loginPage.BindingContext is LoginSsoPageViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(true));
|
|
|
|
|
vm.StartSetPasswordAction = () => DismissViewController(false, () => LaunchSetPasswordFlow());
|
2021-09-24 20:14:26 +02:00
|
|
|
|
vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow());
|
2020-09-03 18:30:40 +02:00
|
|
|
|
vm.SsoAuthSuccessAction = () => DismissLockAndContinue();
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(loginPage);
|
|
|
|
|
var loginController = navigationPage.CreateViewController();
|
|
|
|
|
loginController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(loginController, true, null);
|
2021-09-24 20:14:26 +02:00
|
|
|
|
|
|
|
|
|
LogoutIfAuthed();
|
2020-09-03 18:30:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LaunchTwoFactorFlow(bool authingWithSso)
|
2020-05-29 18:26:36 +02:00
|
|
|
|
{
|
2020-09-03 18:30:40 +02:00
|
|
|
|
var twoFactorPage = new TwoFactorPage(authingWithSso);
|
2020-05-29 21:25:06 +02:00
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-05-29 18:26:36 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(twoFactorPage);
|
|
|
|
|
if (twoFactorPage.BindingContext is TwoFactorPageViewModel vm)
|
|
|
|
|
{
|
2020-09-03 18:30:40 +02:00
|
|
|
|
vm.TwoFactorAuthSuccessAction = () => DismissLockAndContinue();
|
|
|
|
|
vm.StartSetPasswordAction = () => DismissViewController(false, () => LaunchSetPasswordFlow());
|
|
|
|
|
if (authingWithSso)
|
|
|
|
|
{
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchLoginSsoFlow());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchLoginFlow());
|
|
|
|
|
}
|
2021-09-24 20:14:26 +02:00
|
|
|
|
vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow());
|
2020-05-29 18:26:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(twoFactorPage);
|
|
|
|
|
var twoFactorController = navigationPage.CreateViewController();
|
|
|
|
|
twoFactorController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(twoFactorController, true, null);
|
|
|
|
|
}
|
2020-09-03 18:30:40 +02:00
|
|
|
|
|
|
|
|
|
private void LaunchSetPasswordFlow()
|
|
|
|
|
{
|
|
|
|
|
var setPasswordPage = new SetPasswordPage();
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2020-09-03 18:30:40 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(setPasswordPage);
|
|
|
|
|
if (setPasswordPage.BindingContext is SetPasswordPageViewModel vm)
|
|
|
|
|
{
|
2021-09-24 20:14:26 +02:00
|
|
|
|
vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow());
|
2020-09-03 18:30:40 +02:00
|
|
|
|
vm.SetPasswordSuccessAction = () => DismissLockAndContinue();
|
|
|
|
|
vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(setPasswordPage);
|
|
|
|
|
var setPasswordController = navigationPage.CreateViewController();
|
|
|
|
|
setPasswordController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(setPasswordController, true, null);
|
|
|
|
|
}
|
2021-09-24 20:14:26 +02:00
|
|
|
|
|
|
|
|
|
private void LaunchUpdateTempPasswordFlow()
|
|
|
|
|
{
|
|
|
|
|
var updateTempPasswordPage = new UpdateTempPasswordPage();
|
|
|
|
|
var app = new App.App(new AppOptions { IosExtension = true });
|
2022-02-23 18:40:17 +01:00
|
|
|
|
ThemeManager.SetTheme(app.Resources);
|
2021-09-24 20:14:26 +02:00
|
|
|
|
ThemeManager.ApplyResourcesToPage(updateTempPasswordPage);
|
|
|
|
|
if (updateTempPasswordPage.BindingContext is UpdateTempPasswordPageViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.UpdateTempPasswordSuccessAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
vm.LogOutAction = () => DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var navigationPage = new NavigationPage(updateTempPasswordPage);
|
|
|
|
|
var updateTempPasswordController = navigationPage.CreateViewController();
|
|
|
|
|
updateTempPasswordController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
|
|
|
|
|
PresentViewController(updateTempPasswordController, true, null);
|
|
|
|
|
}
|
2022-06-08 19:24:01 +02:00
|
|
|
|
|
|
|
|
|
public Task SetPreviousPageInfoAsync() => Task.CompletedTask;
|
|
|
|
|
public Task UpdateThemeAsync() => Task.CompletedTask;
|
|
|
|
|
|
|
|
|
|
public void Navigate(NavigationTarget navTarget, INavigationParams navParams = null)
|
|
|
|
|
{
|
|
|
|
|
switch (navTarget)
|
|
|
|
|
{
|
|
|
|
|
case NavigationTarget.HomeLogin:
|
|
|
|
|
DismissViewController(false, () => LaunchHomePage());
|
|
|
|
|
break;
|
|
|
|
|
case NavigationTarget.Login:
|
|
|
|
|
if (navParams is LoginNavigationParams loginParams)
|
|
|
|
|
{
|
|
|
|
|
DismissViewController(false, () => LaunchLoginFlow(loginParams.Email));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DismissViewController(false, () => LaunchLoginFlow());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case NavigationTarget.Lock:
|
|
|
|
|
DismissViewController(false, () => PerformSegue("lockPasswordSegue", this));
|
|
|
|
|
break;
|
|
|
|
|
case NavigationTarget.AutofillCiphers:
|
|
|
|
|
case NavigationTarget.Home:
|
|
|
|
|
DismissViewController(false, () => PerformSegue("loginListSegue", this));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-28 14:21:44 +02:00
|
|
|
|
}
|
2019-08-27 20:55:15 +02:00
|
|
|
|
}
|