mirror of
https://github.com/bitwarden/mobile
synced 2025-12-11 05:43:30 +00:00
Merge branch 'main' into feature/maui-migration-passkeys
This commit is contained in:
@@ -73,17 +73,28 @@ namespace Bit.Droid.Services
|
|||||||
|
|
||||||
public bool LaunchApp(string appName)
|
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;
|
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)
|
public async Task ShowLoadingAsync(string text)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Bit.Core;
|
|||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Models.Response;
|
using Bit.Core.Models.Response;
|
||||||
using Bit.Core.Pages;
|
using Bit.Core.Pages;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
@@ -167,132 +168,153 @@ namespace Bit.App
|
|||||||
|
|
||||||
_accountsManager.Init(() => Options, this);
|
_accountsManager.Init(() => Options, this);
|
||||||
|
|
||||||
Bootstrap();
|
_broadcasterService.Subscribe(nameof(App), BroadcastServiceMessageCallbackAsync);
|
||||||
_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<int, bool>(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(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<int, bool>(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);
|
||||||
{
|
}
|
||||||
await tabsPage.Navigation.PopModalAsync(false);
|
if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE)
|
||||||
}
|
{
|
||||||
if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE)
|
MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
||||||
{
|
}
|
||||||
MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
else if (message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE)
|
||||||
}
|
{
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE)
|
Options.MyVaultTile = false;
|
||||||
{
|
tabsPage.ResetToVaultPage();
|
||||||
Options.MyVaultTile = false;
|
}
|
||||||
tabsPage.ResetToVaultPage();
|
else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE)
|
||||||
}
|
{
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE)
|
Options.GeneratorTile = false;
|
||||||
{
|
tabsPage.ResetToGeneratorPage();
|
||||||
Options.GeneratorTile = false;
|
}
|
||||||
tabsPage.ResetToGeneratorPage();
|
else if (message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE)
|
||||||
}
|
{
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE)
|
tabsPage.ResetToSendPage();
|
||||||
{
|
}
|
||||||
tabsPage.ResetToSendPage();
|
else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
||||||
}
|
{
|
||||||
else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
tabsPage.ResetToVaultPage();
|
||||||
{
|
ArgumentNullException.ThrowIfNull(tabsPage.Navigation);
|
||||||
tabsPage.ResetToVaultPage();
|
await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options)));
|
||||||
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()
|
private async Task CheckPasswordlessLoginRequestsAsync()
|
||||||
@@ -307,7 +329,6 @@ namespace Bit.App
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var notification = await _stateService.GetPasswordlessLoginNotificationAsync();
|
var notification = await _stateService.GetPasswordlessLoginNotificationAsync();
|
||||||
if (notification == null)
|
if (notification == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2878,12 +2878,12 @@
|
|||||||
<value>أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك.</value>
|
<value>أعدنّ ميزة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||||
<value>Duo two-step login is required for your account. </value>
|
<value>تسجيل الدخول لـ Duo من خطوتين مطلوب لحسابك. </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
|
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
|
||||||
<value>Follow the steps from Duo to finish logging in.</value>
|
<value>اتبع الخطوات من Duo لإنهاء تسجيل الدخول.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LaunchDuo" xml:space="preserve">
|
<data name="LaunchDuo" xml:space="preserve">
|
||||||
<value>Launch Duo</value>
|
<value>تشغيل Duo</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -371,7 +371,7 @@
|
|||||||
<comment>Label for a username.</comment>
|
<comment>Label for a username.</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="ValidationFieldRequired" xml:space="preserve">
|
<data name="ValidationFieldRequired" xml:space="preserve">
|
||||||
<value>Het {0}-veld is vereist.</value>
|
<value>Vul het veld {0} in.</value>
|
||||||
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
|
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="ValueHasBeenCopied" xml:space="preserve">
|
<data name="ValueHasBeenCopied" xml:space="preserve">
|
||||||
@@ -996,7 +996,7 @@ Het scannen gebeurt automatisch.</value>
|
|||||||
<value>Beveiligingscode kopiëren</value>
|
<value>Beveiligingscode kopiëren</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Number" xml:space="preserve">
|
<data name="Number" xml:space="preserve">
|
||||||
<value>Kaartummer</value>
|
<value>Kaartnummer</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SecurityCode" xml:space="preserve">
|
<data name="SecurityCode" xml:space="preserve">
|
||||||
<value>Beveiligingscode</value>
|
<value>Beveiligingscode</value>
|
||||||
|
|||||||
@@ -2879,12 +2879,12 @@ Vill du byta till detta konto?</value>
|
|||||||
<value>Ställ in ett upplåsningsalternativ för att ändra vad som händer när tidsgränsen uppnås.</value>
|
<value>Ställ in ett upplåsningsalternativ för att ändra vad som händer när tidsgränsen uppnås.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
<data name="DuoTwoStepLoginIsRequiredForYourAccount" xml:space="preserve">
|
||||||
<value>Duo two-step login is required for your account. </value>
|
<value>Duo tvåstegsverifiering krävs för ditt konto. </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
|
<data name="FollowTheStepsFromDuoToFinishLoggingIn" xml:space="preserve">
|
||||||
<value>Follow the steps from Duo to finish logging in.</value>
|
<value>Följ stegen från Duo för att slutföra inloggningen.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LaunchDuo" xml:space="preserve">
|
<data name="LaunchDuo" xml:space="preserve">
|
||||||
<value>Launch Duo</value>
|
<value>Starta Duo</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
Reference in New Issue
Block a user