From 3c0007a21a0f5ba3c0bf267568d310f172af9f87 Mon Sep 17 00:00:00 2001 From: Dinis Vieira Date: Fri, 22 Mar 2024 15:29:12 +0000 Subject: [PATCH 1/3] [PM-7009] Improved exception messages for the Broadcast Service message callback function (#3091) * Improved exception messages for the Broadcast Service message callback function * Update src/Core/App.xaml.cs Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Additional Null Check Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Additional Null Check Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Additional Null Check Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Additional Null Check Co-authored-by: Federico Maccaroni * Update src/Core/App.xaml.cs Additional Null Check Co-authored-by: Federico Maccaroni --------- Co-authored-by: Federico Maccaroni --- src/Core/App.xaml.cs | 257 +++++++++++++++++++++++-------------------- 1 file changed, 139 insertions(+), 118 deletions(-) diff --git a/src/Core/App.xaml.cs b/src/Core/App.xaml.cs index 2c63c252d..31a3ba8ca 100644 --- a/src/Core/App.xaml.cs +++ b/src/Core/App.xaml.cs @@ -9,6 +9,7 @@ using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Models.Data; +using Bit.Core.Models.Domain; using Bit.Core.Models.Response; using Bit.Core.Pages; using Bit.Core.Services; @@ -167,132 +168,153 @@ namespace Bit.App _accountsManager.Init(() => Options, this); - Bootstrap(); - _broadcasterService.Subscribe(nameof(App), async (message) => - { - try - { - if (message.Command == "showDialog") - { - var details = message.Data as DialogDetails; - var confirmed = true; - var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ? - AppResources.Ok : details.ConfirmText; - await MainThread.InvokeOnMainThreadAsync(async () => - { - if (!string.IsNullOrWhiteSpace(details.CancelText)) - { - confirmed = await MainPage.DisplayAlert(details.Title, details.Text, confirmText, - details.CancelText); - } - else - { - await MainPage.DisplayAlert(details.Title, details.Text, confirmText); - } - _messagingService.Send("showDialogResolve", new Tuple(details.DialogId, confirmed)); - }); - } -#if IOS - else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND) - { - ResumedAsync().FireAndForget(); - } - else if (message.Command == "slept") - { - await SleptAsync(); - } -#endif - else if (message.Command == "migrated") - { - await Task.Delay(1000); - await _accountsManager.NavigateOnAccountChangeAsync(); - } - else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE || - message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE || - message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE || - message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE || - message.Command == DeepLinkContext.NEW_OTP_MESSAGE) - { - if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE) - { - Options.OtpData = new OtpData((string)message.Data); - } + _broadcasterService.Subscribe(nameof(App), BroadcastServiceMessageCallbackAsync); - await MainThread.InvokeOnMainThreadAsync(async () => + Bootstrap(); + } + + private async void BroadcastServiceMessageCallbackAsync(Message message) + { + try + { + ArgumentNullException.ThrowIfNull(message); + if (message.Command == "showDialog") + { + var details = message.Data as DialogDetails; + ArgumentNullException.ThrowIfNull(details); + ArgumentNullException.ThrowIfNull(MainPage); + + var confirmed = true; + var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ? + AppResources.Ok : details.ConfirmText; + await MainThread.InvokeOnMainThreadAsync(ShowDialogAction); + async Task ShowDialogAction() + { + if (!string.IsNullOrWhiteSpace(details.CancelText)) { - if (MainPage is TabsPage tabsPage) + confirmed = await MainPage.DisplayAlert(details.Title, details.Text, confirmText, + details.CancelText); + } + else + { + await MainPage.DisplayAlert(details.Title, details.Text, confirmText); + } + _messagingService.Send("showDialogResolve", new Tuple(details.DialogId, confirmed)); + } + } +#if IOS + else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND) + { + ResumedAsync().FireAndForget(); + } + else if (message.Command == "slept") + { + await SleptAsync(); + } +#endif + else if (message.Command == "migrated") + { + await Task.Delay(1000); + await _accountsManager.NavigateOnAccountChangeAsync(); + } + else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE || + message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE || + message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE || + message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE || + message.Command == DeepLinkContext.NEW_OTP_MESSAGE) + { + if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE) + { + Options.OtpData = new OtpData((string)message.Data); + } + + await MainThread.InvokeOnMainThreadAsync(ExecuteNavigationAction); + async Task ExecuteNavigationAction() + { + if (MainPage is TabsPage tabsPage) + { + ArgumentNullException.ThrowIfNull(tabsPage.Navigation); + ArgumentNullException.ThrowIfNull(tabsPage.Navigation.ModalStack); + while (tabsPage.Navigation.ModalStack.Count > 0) { - while (tabsPage.Navigation.ModalStack.Count > 0) - { - await tabsPage.Navigation.PopModalAsync(false); - } - if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE) - { - MainPage = new NavigationPage(new CipherSelectionPage(Options)); - } - else if (message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE) - { - Options.MyVaultTile = false; - tabsPage.ResetToVaultPage(); - } - else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE) - { - Options.GeneratorTile = false; - tabsPage.ResetToGeneratorPage(); - } - else if (message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE) - { - tabsPage.ResetToSendPage(); - } - else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE) - { - tabsPage.ResetToVaultPage(); - await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options))); - } + await tabsPage.Navigation.PopModalAsync(false); + } + if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE) + { + MainPage = new NavigationPage(new CipherSelectionPage(Options)); + } + else if (message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE) + { + Options.MyVaultTile = false; + tabsPage.ResetToVaultPage(); + } + else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE) + { + Options.GeneratorTile = false; + tabsPage.ResetToGeneratorPage(); + } + else if (message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE) + { + tabsPage.ResetToSendPage(); + } + else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE) + { + tabsPage.ResetToVaultPage(); + ArgumentNullException.ThrowIfNull(tabsPage.Navigation); + await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options))); } - }); - } - else if (message.Command == "convertAccountToKeyConnector") - { - await MainThread.InvokeOnMainThreadAsync(async () => - { - await MainPage.Navigation.PushModalAsync( - new NavigationPage(new RemoveMasterPasswordPage())); - }); - } - else if (message.Command == Constants.ForceUpdatePassword) - { - await MainThread.InvokeOnMainThreadAsync(async () => - { - await MainPage.Navigation.PushModalAsync( - new NavigationPage(new UpdateTempPasswordPage())); - }); - } - else if (message.Command == Constants.ForceSetPassword) - { - await MainThread.InvokeOnMainThreadAsync(() => MainPage.Navigation.PushModalAsync( - new NavigationPage(new SetPasswordPage(orgIdentifier: (string)message.Data)))); - } - else if (message.Command == "syncCompleted") - { - await _configService.GetAsync(true); - } - else if (message.Command == Constants.PasswordlessLoginRequestKey - || message.Command == "unlocked" - || message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED) - { - lock (_processingLoginRequestLock) - { - // lock doesn't allow for async execution - CheckPasswordlessLoginRequestsAsync().Wait(); } } } - catch (Exception ex) + else if (message.Command == "convertAccountToKeyConnector") { - LoggerHelper.LogEvenIfCantBeResolved(ex); + ArgumentNullException.ThrowIfNull(MainPage); + await MainThread.InvokeOnMainThreadAsync(NavigateToRemoveMasterPasswordPageAction); + async Task NavigateToRemoveMasterPasswordPageAction() + { + await MainPage.Navigation.PushModalAsync( + new NavigationPage(new RemoveMasterPasswordPage())); + } } - }); + else if (message.Command == Constants.ForceUpdatePassword) + { + ArgumentNullException.ThrowIfNull(MainPage); + await MainThread.InvokeOnMainThreadAsync(NavigateToUpdateTempPasswordPageAction); + async Task NavigateToUpdateTempPasswordPageAction() + { + await MainPage.Navigation.PushModalAsync( + new NavigationPage(new UpdateTempPasswordPage())); + } + } + else if (message.Command == Constants.ForceSetPassword) + { + ArgumentNullException.ThrowIfNull(MainPage); + await MainThread.InvokeOnMainThreadAsync(NavigateToSetPasswordPageAction); + void NavigateToSetPasswordPageAction() + { + MainPage.Navigation.PushModalAsync( + new NavigationPage(new SetPasswordPage(orgIdentifier: (string)message.Data))); + } + } + else if (message.Command == "syncCompleted") + { + await _configService.GetAsync(true); + } + else if (message.Command == Constants.PasswordlessLoginRequestKey + || message.Command == "unlocked" + || message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED) + { + lock (_processingLoginRequestLock) + { + // lock doesn't allow for async execution + CheckPasswordlessLoginRequestsAsync().Wait(); + } + } + } + catch (Exception ex) + { + LoggerHelper.LogEvenIfCantBeResolved(ex); + } } private async Task CheckPasswordlessLoginRequestsAsync() @@ -307,7 +329,6 @@ namespace Bit.App { return; } - var notification = await _stateService.GetPasswordlessLoginNotificationAsync(); if (notification == null) { From 64775694e0cfb4ad73287c1ec6fabccbbe21f212 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 16:07:23 +0000 Subject: [PATCH 2/3] Autosync the updated translations (#3105) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- src/Core/Resources/Localization/AppResources.ar.resx | 6 +++--- src/Core/Resources/Localization/AppResources.nl.resx | 4 ++-- src/Core/Resources/Localization/AppResources.sv.resx | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Core/Resources/Localization/AppResources.ar.resx b/src/Core/Resources/Localization/AppResources.ar.resx index fdd43741a..932db52cd 100644 --- a/src/Core/Resources/Localization/AppResources.ar.resx +++ b/src/Core/Resources/Localization/AppResources.ar.resx @@ -2878,12 +2878,12 @@ أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك. - Duo two-step login is required for your account. + تسجيل الدخول لـ Duo من خطوتين مطلوب لحسابك. - Follow the steps from Duo to finish logging in. + اتبع الخطوات من Duo لإنهاء تسجيل الدخول. - Launch Duo + تشغيل Duo diff --git a/src/Core/Resources/Localization/AppResources.nl.resx b/src/Core/Resources/Localization/AppResources.nl.resx index 48de603e3..a95e27572 100644 --- a/src/Core/Resources/Localization/AppResources.nl.resx +++ b/src/Core/Resources/Localization/AppResources.nl.resx @@ -371,7 +371,7 @@ Label for a username. - Het {0}-veld is vereist. + Vul het veld {0} in. Validation message for when a form field is left blank and is required to be entered. @@ -996,7 +996,7 @@ Het scannen gebeurt automatisch. Beveiligingscode kopiëren - Kaartummer + Kaartnummer Beveiligingscode diff --git a/src/Core/Resources/Localization/AppResources.sv.resx b/src/Core/Resources/Localization/AppResources.sv.resx index 7c4388a5f..9f9fcda34 100644 --- a/src/Core/Resources/Localization/AppResources.sv.resx +++ b/src/Core/Resources/Localization/AppResources.sv.resx @@ -2879,12 +2879,12 @@ Vill du byta till detta konto? Ställ in ett upplåsningsalternativ för att ändra vad som händer när tidsgränsen uppnås. - Duo two-step login is required for your account. + Duo tvåstegsverifiering krävs för ditt konto. - Follow the steps from Duo to finish logging in. + Följ stegen från Duo för att slutföra inloggningen. - Launch Duo + Starta Duo From f04ff7777aa2aa1d7209e61e6d14bb150b22d814 Mon Sep 17 00:00:00 2001 From: Dinis Vieira Date: Fri, 22 Mar 2024 16:31:15 +0000 Subject: [PATCH 3/3] Added specific try catch in Android launchApp to avoid the app crashing when trying to launch app package name that are not installed on the device. (#3092) --- .../Android/Services/DeviceActionService.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/App/Platforms/Android/Services/DeviceActionService.cs b/src/App/Platforms/Android/Services/DeviceActionService.cs index 102f1de80..0a3498114 100644 --- a/src/App/Platforms/Android/Services/DeviceActionService.cs +++ b/src/App/Platforms/Android/Services/DeviceActionService.cs @@ -72,17 +72,28 @@ namespace Bit.Droid.Services public bool LaunchApp(string appName) { - if ((int)Build.VERSION.SdkInt < 33) + try + { + if ((int)Build.VERSION.SdkInt < 33) + { + // API 33 required to avoid using wildcard app visibility or dangerous permissions + // https://developer.android.com/reference/android/content/pm/PackageManager#getLaunchIntentSenderForPackage(java.lang.String) + return false; + } + var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity; + appName = appName.Replace("androidapp://", string.Empty); + var launchIntentSender = activity?.PackageManager?.GetLaunchIntentSenderForPackage(appName); + launchIntentSender?.SendIntent(activity, Result.Ok, null, null, null); + return launchIntentSender != null; + } + catch (IntentSender.SendIntentException) + { + return false; + } + catch (Android.Util.AndroidException) { - // API 33 required to avoid using wildcard app visibility or dangerous permissions - // https://developer.android.com/reference/android/content/pm/PackageManager#getLaunchIntentSenderForPackage(java.lang.String) return false; } - var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity; - appName = appName.Replace("androidapp://", string.Empty); - var launchIntentSender = activity?.PackageManager?.GetLaunchIntentSenderForPackage(appName); - launchIntentSender?.SendIntent(activity, Result.Ok, null, null, null); - return launchIntentSender != null; } public async Task ShowLoadingAsync(string text)