From 848e62064740c5a8fd922367d7a119da172e57b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Wed, 19 Jul 2023 11:28:47 +0100 Subject: [PATCH] [PM-2297] Add missing action navigations to iOS extensions --- .../Accounts/LoginApproveDevicePage.xaml.cs | 2 +- .../Accounts/LoginApproveDeviceViewModel.cs | 4 +-- src/App/Pages/Accounts/LoginSsoPage.xaml.cs | 8 ++++++ .../Pages/Accounts/LoginSsoPageViewModel.cs | 27 ++++++++++-------- .../CredentialProviderViewController.cs | 28 +++++++++++++++++-- src/iOS.Extension/LoadingViewController.cs | 27 ++++++++++++++++-- .../LoadingViewController.cs | 27 ++++++++++++++++-- 7 files changed, 100 insertions(+), 23 deletions(-) diff --git a/src/App/Pages/Accounts/LoginApproveDevicePage.xaml.cs b/src/App/Pages/Accounts/LoginApproveDevicePage.xaml.cs index 35c15313f..71b66b4ae 100644 --- a/src/App/Pages/Accounts/LoginApproveDevicePage.xaml.cs +++ b/src/App/Pages/Accounts/LoginApproveDevicePage.xaml.cs @@ -19,7 +19,7 @@ namespace Bit.App.Pages { InitializeComponent(); _vm = BindingContext as LoginApproveDeviceViewModel; - _vm.LogInWithMasterPassword = () => StartLogInWithMasterPassword().FireAndForget(); + _vm.LogInWithMasterPasswordAction = () => StartLogInWithMasterPassword().FireAndForget(); _vm.LogInWithDeviceAction = () => StartLoginWithDeviceAsync().FireAndForget(); _vm.RequestAdminApprovalAction = () => RequestAdminApprovalAsync().FireAndForget(); _vm.CloseAction = () => { Navigation.PopModalAsync(); }; diff --git a/src/App/Pages/Accounts/LoginApproveDeviceViewModel.cs b/src/App/Pages/Accounts/LoginApproveDeviceViewModel.cs index 74a42e88d..f25aeb8cf 100644 --- a/src/App/Pages/Accounts/LoginApproveDeviceViewModel.cs +++ b/src/App/Pages/Accounts/LoginApproveDeviceViewModel.cs @@ -32,7 +32,7 @@ namespace Bit.App.Pages public ICommand ApproveWithMasterPasswordCommand { get; } public ICommand ContinueCommand { get; } - public Action LogInWithMasterPassword { get; set; } + public Action LogInWithMasterPasswordAction { get; set; } public Action LogInWithDeviceAction { get; set; } public Action RequestAdminApprovalAction { get; set; } public Action CloseAction { get; set; } @@ -53,7 +53,7 @@ namespace Bit.App.Pages onException: ex => HandleException(ex), allowsMultipleExecutions: false); - ApproveWithMasterPasswordCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPassword), + ApproveWithMasterPasswordCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction), onException: ex => HandleException(ex), allowsMultipleExecutions: false); diff --git a/src/App/Pages/Accounts/LoginSsoPage.xaml.cs b/src/App/Pages/Accounts/LoginSsoPage.xaml.cs index 6abdfa88d..f8a145b4a 100644 --- a/src/App/Pages/Accounts/LoginSsoPage.xaml.cs +++ b/src/App/Pages/Accounts/LoginSsoPage.xaml.cs @@ -29,6 +29,8 @@ namespace Bit.App.Pages _vm.SsoAuthSuccessAction = () => Device.BeginInvokeOnMainThread(async () => await SsoAuthSuccessAsync()); _vm.UpdateTempPasswordAction = () => Device.BeginInvokeOnMainThread(async () => await UpdateTempPasswordAsync()); + _vm.StartDeviceApprovalOptionsAction = + () => Device.BeginInvokeOnMainThread(async () => await StartDeviceApprovalOptionsAsync()); _vm.CloseAction = async () => { await Navigation.PopModalAsync(); @@ -106,6 +108,12 @@ namespace Bit.App.Pages await Navigation.PushModalAsync(new NavigationPage(page)); } + private async Task StartDeviceApprovalOptionsAsync() + { + var page = new LoginApproveDevicePage(); + await Navigation.PushModalAsync(new NavigationPage(page)); + } + private async Task SsoAuthSuccessAsync() { RestoreAppOptionsFromCopy(); diff --git a/src/App/Pages/Accounts/LoginSsoPageViewModel.cs b/src/App/Pages/Accounts/LoginSsoPageViewModel.cs index d805a579b..91a039a54 100644 --- a/src/App/Pages/Accounts/LoginSsoPageViewModel.cs +++ b/src/App/Pages/Accounts/LoginSsoPageViewModel.cs @@ -65,6 +65,7 @@ namespace Bit.App.Pages public Action StartTwoFactorAction { get; set; } public Action StartSetPasswordAction { get; set; } public Action SsoAuthSuccessAction { get; set; } + public Action StartDeviceApprovalOptionsAction { get; set; } public Action CloseAction { get; set; } public Action UpdateTempPasswordAction { get; set; } @@ -219,16 +220,6 @@ namespace Bit.App.Pages } else if (decryptOptions.TrustedDeviceOption != null) { - // TODO MOVE THIS CODE TO AUTH SERVICE - //var task = Task.Run(async () => await _syncService.FullSyncAsync(true)); - //if (await _deviceTrustCryptoService.IsDeviceTrustedAsync() && decryptOptions?.TrustedDeviceOption != null) - //{ - // var key = await _deviceTrustCryptoService.DecryptUserKeyWithDeviceKeyAsync(decryptOptions?.TrustedDeviceOption.EncryptedPrivateKey, decryptOptions?.TrustedDeviceOption.EncryptedUserKey); - // if (key != null) - // { - // await _cryptoService.SetEncKeyAsync(key); - // } - //} // If user doesn't have a MP, but has reset password permission, they must set a MP if (!decryptOptions.HasMasterPassword && decryptOptions.TrustedDeviceOption.HasManageResetPasswordPermission) @@ -239,9 +230,23 @@ namespace Bit.App.Pages { UpdateTempPasswordAction?.Invoke(); } + else if (await _deviceTrustCryptoService.IsDeviceTrustedAsync()) + { + // TODO MOVE THIS CODE TO AUTH SERVICE + //if (await _deviceTrustCryptoService.IsDeviceTrustedAsync() && decryptOptions?.TrustedDeviceOption != null) + //{ + // var key = await _deviceTrustCryptoService.DecryptUserKeyWithDeviceKeyAsync(decryptOptions?.TrustedDeviceOption.EncryptedPrivateKey, decryptOptions?.TrustedDeviceOption.EncryptedUserKey); + // if (key != null) + // { + // await _cryptoService.SetEncKeyAsync(key); + // } + //} + var task = Task.Run(async () => await _syncService.FullSyncAsync(true)); + SsoAuthSuccessAction?.Invoke(); + } else { - SsoAuthSuccessAction?.Invoke(); + StartDeviceApprovalOptionsAction?.Invoke(); } } else diff --git a/src/iOS.Autofill/CredentialProviderViewController.cs b/src/iOS.Autofill/CredentialProviderViewController.cs index 71c8cf660..ab77da33f 100644 --- a/src/iOS.Autofill/CredentialProviderViewController.cs +++ b/src/iOS.Autofill/CredentialProviderViewController.cs @@ -17,6 +17,7 @@ using CoreFoundation; using CoreNFC; using Foundation; using UIKit; +using Xamarin.Essentials; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; @@ -498,7 +499,7 @@ namespace Bit.iOS.Autofill vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(false)); vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow()); vm.StartSsoLoginAction = () => DismissViewController(false, () => LaunchLoginSsoFlow()); - vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(email)); + vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, email)); vm.LogInSuccessAction = () => DismissLockAndContinue(); vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); } @@ -511,11 +512,11 @@ namespace Bit.iOS.Autofill LogoutIfAuthed(); } - private void LaunchLoginWithDevice(string email = null) + private void LaunchLoginWithDevice(AuthRequestType authRequestType, string email = null) { var appOptions = new AppOptions { IosExtension = true }; var app = new App.App(appOptions); - var loginWithDevicePage = new LoginPasswordlessRequestPage(email, AuthRequestType.AuthenticateAndUnlock, appOptions); + var loginWithDevicePage = new LoginPasswordlessRequestPage(email, authRequestType, appOptions); ThemeManager.SetTheme(app.Resources); ThemeManager.ApplyResourcesTo(loginWithDevicePage); if (loginWithDevicePage.BindingContext is LoginPasswordlessRequestViewModel vm) @@ -545,6 +546,7 @@ namespace Bit.iOS.Autofill vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(true)); vm.StartSetPasswordAction = () => DismissViewController(false, () => LaunchSetPasswordFlow()); vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow()); + vm.StartDeviceApprovalOptionsAction = () => DismissViewController(false, () => LaunchDeviceApprovalOptionsFlow()); vm.SsoAuthSuccessAction = () => DismissLockAndContinue(); vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); } @@ -621,6 +623,26 @@ namespace Bit.iOS.Autofill PresentViewController(updateTempPasswordController, true, null); } + private void LaunchDeviceApprovalOptionsFlow() + { + var loginApproveDevicePage = new LoginApproveDevicePage(); + var app = new App.App(new AppOptions { IosExtension = true }); + ThemeManager.SetTheme(app.Resources); + ThemeManager.ApplyResourcesTo(loginApproveDevicePage); + if (loginApproveDevicePage.BindingContext is LoginApproveDeviceViewModel vm) + { + vm.LogInWithMasterPasswordAction = () => DismissViewController(false, () => PerformSegue("lockPasswordSegue", this)); + vm.RequestAdminApprovalAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AdminApproval, vm.Email)); + vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, vm.Email)); + vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); + } + + var navigationPage = new NavigationPage(loginApproveDevicePage); + var loginApproveDeviceController = navigationPage.CreateViewController(); + loginApproveDeviceController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; + PresentViewController(loginApproveDeviceController, true, null); + } + public Task SetPreviousPageInfoAsync() => Task.CompletedTask; public Task UpdateThemeAsync() => Task.CompletedTask; diff --git a/src/iOS.Extension/LoadingViewController.cs b/src/iOS.Extension/LoadingViewController.cs index f9e2bfd3d..597ee90ff 100644 --- a/src/iOS.Extension/LoadingViewController.cs +++ b/src/iOS.Extension/LoadingViewController.cs @@ -520,7 +520,7 @@ namespace Bit.iOS.Extension vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(false)); vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow()); vm.StartSsoLoginAction = () => DismissViewController(false, () => LaunchLoginSsoFlow()); - vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(email)); + vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, email)); vm.LogInSuccessAction = () => DismissLockAndContinue(); vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); } @@ -533,11 +533,11 @@ namespace Bit.iOS.Extension LogoutIfAuthed(); } - private void LaunchLoginWithDevice(string email = null) + private void LaunchLoginWithDevice(AuthRequestType authRequestType,string email = null) { var appOptions = new AppOptions { IosExtension = true }; var app = new App.App(appOptions); - var loginWithDevicePage = new LoginPasswordlessRequestPage(email, AuthRequestType.AuthenticateAndUnlock, appOptions); + var loginWithDevicePage = new LoginPasswordlessRequestPage(email, authRequestType, appOptions); ThemeManager.SetTheme(app.Resources); ThemeManager.ApplyResourcesTo(loginWithDevicePage); if (loginWithDevicePage.BindingContext is LoginPasswordlessRequestViewModel vm) @@ -567,6 +567,7 @@ namespace Bit.iOS.Extension vm.StartTwoFactorAction = () => DismissViewController(false, () => LaunchTwoFactorFlow(true)); vm.StartSetPasswordAction = () => DismissViewController(false, () => LaunchSetPasswordFlow()); vm.UpdateTempPasswordAction = () => DismissViewController(false, () => LaunchUpdateTempPasswordFlow()); + vm.StartDeviceApprovalOptionsAction = () => DismissViewController(false, () => LaunchDeviceApprovalOptionsFlow()); vm.SsoAuthSuccessAction = () => DismissLockAndContinue(); vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); } @@ -642,5 +643,25 @@ namespace Bit.iOS.Extension updateTempPasswordController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; PresentViewController(updateTempPasswordController, true, null); } + + private void LaunchDeviceApprovalOptionsFlow() + { + var loginApproveDevicePage = new LoginApproveDevicePage(); + var app = new App.App(new AppOptions { IosExtension = true }); + ThemeManager.SetTheme(app.Resources); + ThemeManager.ApplyResourcesTo(loginApproveDevicePage); + if (loginApproveDevicePage.BindingContext is LoginApproveDeviceViewModel vm) + { + vm.LogInWithMasterPasswordAction = () => DismissViewController(false, () => PerformSegue("lockPasswordSegue", this)); + vm.RequestAdminApprovalAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AdminApproval, vm.Email)); + vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, vm.Email)); + vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); + } + + var navigationPage = new NavigationPage(loginApproveDevicePage); + var loginApproveDeviceController = navigationPage.CreateViewController(); + loginApproveDeviceController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; + PresentViewController(loginApproveDeviceController, true, null); + } } } diff --git a/src/iOS.ShareExtension/LoadingViewController.cs b/src/iOS.ShareExtension/LoadingViewController.cs index 46629d457..95b753b08 100644 --- a/src/iOS.ShareExtension/LoadingViewController.cs +++ b/src/iOS.ShareExtension/LoadingViewController.cs @@ -339,7 +339,7 @@ namespace Bit.iOS.ShareExtension vm.StartTwoFactorAction = () => DismissAndLaunch(() => LaunchTwoFactorFlow(false)); vm.UpdateTempPasswordAction = () => DismissAndLaunch(() => LaunchUpdateTempPasswordFlow()); vm.StartSsoLoginAction = () => DismissAndLaunch(() => LaunchLoginSsoFlow()); - vm.LogInWithDeviceAction = () => DismissAndLaunch(() => LaunchLoginWithDevice(email)); + vm.LogInWithDeviceAction = () => DismissAndLaunch(() => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, email)); vm.LogInSuccessAction = () => { DismissLockAndContinue(); }; vm.CloseAction = () => DismissAndLaunch(() => LaunchHomePage()); } @@ -348,9 +348,9 @@ namespace Bit.iOS.ShareExtension LogoutIfAuthed(); } - private void LaunchLoginWithDevice(string email = null) + private void LaunchLoginWithDevice(AuthRequestType authRequestType, string email = null) { - var loginWithDevicePage = new LoginPasswordlessRequestPage(email, AuthRequestType.AuthenticateAndUnlock, _appOptions.Value); + var loginWithDevicePage = new LoginPasswordlessRequestPage(email, authRequestType, _appOptions.Value); SetupAppAndApplyResources(loginWithDevicePage); if (loginWithDevicePage.BindingContext is LoginPasswordlessRequestViewModel vm) { @@ -373,6 +373,7 @@ namespace Bit.iOS.ShareExtension vm.StartTwoFactorAction = () => DismissAndLaunch(() => LaunchTwoFactorFlow(true)); vm.StartSetPasswordAction = () => DismissAndLaunch(() => LaunchSetPasswordFlow()); vm.UpdateTempPasswordAction = () => DismissAndLaunch(() => LaunchUpdateTempPasswordFlow()); + vm.StartDeviceApprovalOptionsAction = () => DismissViewController(false, () => LaunchDeviceApprovalOptionsFlow()); vm.SsoAuthSuccessAction = () => DismissLockAndContinue(); vm.CloseAction = () => DismissAndLaunch(() => LaunchHomePage()); } @@ -427,6 +428,26 @@ namespace Bit.iOS.ShareExtension NavigateToPage(updateTempPasswordPage); } + private void LaunchDeviceApprovalOptionsFlow() + { + var loginApproveDevicePage = new LoginApproveDevicePage(); + var app = new App.App(new AppOptions { IosExtension = true }); + ThemeManager.SetTheme(app.Resources); + ThemeManager.ApplyResourcesTo(loginApproveDevicePage); + if (loginApproveDevicePage.BindingContext is LoginApproveDeviceViewModel vm) + { + vm.LogInWithMasterPasswordAction = () => DismissViewController(false, () => PerformSegue("lockPasswordSegue", this)); + vm.RequestAdminApprovalAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AdminApproval, vm.Email)); + vm.LogInWithDeviceAction = () => DismissViewController(false, () => LaunchLoginWithDevice(AuthRequestType.AuthenticateAndUnlock, vm.Email)); + vm.CloseAction = () => DismissViewController(false, () => LaunchHomePage()); + } + + var navigationPage = new NavigationPage(loginApproveDevicePage); + var loginApproveDeviceController = navigationPage.CreateViewController(); + loginApproveDeviceController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; + PresentViewController(loginApproveDeviceController, true, null); + } + public void Navigate(NavigationTarget navTarget, INavigationParams navParams = null) { if (ExtNavigationController?.ViewControllers?.Any() ?? false)