mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 23:25:45 +03:00
refactor message center use to services
This commit is contained in:
parent
b48e8eeb0e
commit
3b44ede67e
24 changed files with 439 additions and 379 deletions
|
@ -13,16 +13,10 @@ using System.Reflection;
|
||||||
using Xamarin.Forms.Platform.Android;
|
using Xamarin.Forms.Platform.Android;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Models.Page;
|
|
||||||
using Bit.App;
|
using Bit.App;
|
||||||
using Android.Nfc;
|
using Android.Nfc;
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Android.Views.Autofill;
|
|
||||||
using Android.App.Assist;
|
|
||||||
using Bit.Android.Autofill;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.App.Enums;
|
using Bit.App.Enums;
|
||||||
|
|
||||||
|
@ -35,7 +29,6 @@ namespace Bit.Android
|
||||||
public class MainActivity : FormsAppCompatActivity
|
public class MainActivity : FormsAppCompatActivity
|
||||||
{
|
{
|
||||||
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
|
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
|
||||||
private DateTime? _lastAction;
|
|
||||||
private Java.Util.Regex.Pattern _otpPattern = Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
|
private Java.Util.Regex.Pattern _otpPattern = Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
|
||||||
private IDeviceActionService _deviceActionService;
|
private IDeviceActionService _deviceActionService;
|
||||||
private ISettings _settings;
|
private ISettings _settings;
|
||||||
|
@ -97,105 +90,11 @@ namespace Bit.Android
|
||||||
|
|
||||||
if(_appOptions?.Uri == null)
|
if(_appOptions?.Uri == null)
|
||||||
{
|
{
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
|
||||||
"DismissKeyboard", (sender) => DismissKeyboard());
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
|
||||||
"RateApp", (sender) => RateApp());
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
|
||||||
"Accessibility", (sender) => OpenAccessibilitySettings());
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, string>(Xamarin.Forms.Application.Current,
|
|
||||||
"LaunchApp", (sender, args) => LaunchApp(args));
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, bool>(Xamarin.Forms.Application.Current,
|
MessagingCenter.Subscribe<Xamarin.Forms.Application, bool>(Xamarin.Forms.Application.Current,
|
||||||
"ListenYubiKeyOTP", (sender, listen) => ListenYubiKey(listen));
|
"ListenYubiKeyOTP", (sender, listen) => ListenYubiKey(listen));
|
||||||
}
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, VaultListPageModel.Cipher>(
|
|
||||||
Xamarin.Forms.Application.Current, "Autofill", (sender, args) => ReturnCredentials(args));
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
||||||
"BackgroundApp", (sender) =>
|
"FinishMainActivity", (sender) => Finish());
|
||||||
{
|
|
||||||
if(Intent.GetBooleanExtra("autofillFramework", false))
|
|
||||||
{
|
|
||||||
SetResult(Result.Canceled);
|
|
||||||
Finish();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MoveTaskToBack(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReturnCredentials(VaultListPageModel.Cipher cipher)
|
|
||||||
{
|
|
||||||
if(Intent.GetBooleanExtra("autofillFramework", false))
|
|
||||||
{
|
|
||||||
if(cipher == null)
|
|
||||||
{
|
|
||||||
SetResult(Result.Canceled);
|
|
||||||
Finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var structure = Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure) as AssistStructure;
|
|
||||||
if(structure == null)
|
|
||||||
{
|
|
||||||
SetResult(Result.Canceled);
|
|
||||||
Finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var parser = new Parser(structure);
|
|
||||||
parser.Parse();
|
|
||||||
if(!parser.FieldCollection.Fields.Any() || string.IsNullOrWhiteSpace(parser.Uri))
|
|
||||||
{
|
|
||||||
SetResult(Result.Canceled);
|
|
||||||
Finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var dataset = AutofillHelpers.BuildDataset(this, parser.FieldCollection, new FilledItem(cipher.CipherModel));
|
|
||||||
var replyIntent = new Intent();
|
|
||||||
replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, dataset);
|
|
||||||
SetResult(Result.Ok, replyIntent);
|
|
||||||
Finish();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var data = new Intent();
|
|
||||||
if(cipher == null)
|
|
||||||
{
|
|
||||||
data.PutExtra("canceled", "true");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false;
|
|
||||||
var autoCopyEnabled = !_settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false);
|
|
||||||
if(isPremium && autoCopyEnabled && _deviceActionService != null && cipher.LoginTotp?.Value != null)
|
|
||||||
{
|
|
||||||
_deviceActionService.CopyToClipboard(App.Utilities.Crypto.Totp(cipher.LoginTotp.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
data.PutExtra("uri", cipher.LoginUri);
|
|
||||||
data.PutExtra("username", cipher.LoginUsername);
|
|
||||||
data.PutExtra("password", cipher.LoginPassword?.Value ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Parent == null)
|
|
||||||
{
|
|
||||||
SetResult(Result.Ok, data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Parent.SetResult(Result.Ok, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,65 +201,6 @@ namespace Bit.Android
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RateApp()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var rateIntent = RateIntentForUrl("market://details");
|
|
||||||
StartActivity(rateIntent);
|
|
||||||
}
|
|
||||||
catch(ActivityNotFoundException)
|
|
||||||
{
|
|
||||||
var rateIntent = RateIntentForUrl("https://play.google.com/store/apps/details");
|
|
||||||
StartActivity(rateIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Intent RateIntentForUrl(string url)
|
|
||||||
{
|
|
||||||
var intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse($"{url}?id={PackageName}"));
|
|
||||||
var flags = ActivityFlags.NoHistory | ActivityFlags.MultipleTask;
|
|
||||||
if((int)Build.VERSION.SdkInt >= 21)
|
|
||||||
{
|
|
||||||
flags |= ActivityFlags.NewDocument;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// noinspection deprecation
|
|
||||||
flags |= ActivityFlags.ClearWhenTaskReset;
|
|
||||||
}
|
|
||||||
|
|
||||||
intent.AddFlags(flags);
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenAccessibilitySettings()
|
|
||||||
{
|
|
||||||
var intent = new Intent(global::Android.Provider.Settings.ActionAccessibilitySettings);
|
|
||||||
StartActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LaunchApp(string packageName)
|
|
||||||
{
|
|
||||||
if(_lastAction.LastActionWasRecent())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_lastAction = DateTime.UtcNow;
|
|
||||||
|
|
||||||
packageName = packageName.Replace("androidapp://", string.Empty);
|
|
||||||
var launchIntent = PackageManager.GetLaunchIntentForPackage(packageName);
|
|
||||||
if(launchIntent == null)
|
|
||||||
{
|
|
||||||
var dialog = Resolver.Resolve<IUserDialogs>();
|
|
||||||
dialog.Alert(string.Format(App.Resources.AppResources.CannotOpenApp, packageName));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StartActivity(launchIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ListenYubiKey(bool listen)
|
private void ListenYubiKey(bool listen)
|
||||||
{
|
{
|
||||||
if(!Utilities.NfcEnabled())
|
if(!Utilities.NfcEnabled())
|
||||||
|
@ -405,16 +245,6 @@ namespace Bit.Android
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DismissKeyboard()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var imm = (InputMethodManager)GetSystemService(InputMethodService);
|
|
||||||
imm.HideSoftInputFromWindow(CurrentFocus.WindowToken, 0);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private AppOptions GetOptions()
|
private AppOptions GetOptions()
|
||||||
{
|
{
|
||||||
var options = new AppOptions
|
var options = new AppOptions
|
||||||
|
|
|
@ -15,18 +15,32 @@ using System.Collections.Generic;
|
||||||
using Android;
|
using Android;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using Android.Support.V4.App;
|
using Android.Support.V4.App;
|
||||||
|
using Bit.App.Models.Page;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Views.Autofill;
|
||||||
|
using Android.App.Assist;
|
||||||
|
using Bit.Android.Autofill;
|
||||||
|
using System.Linq;
|
||||||
|
using Plugin.Settings.Abstractions;
|
||||||
|
using Acr.UserDialogs;
|
||||||
|
using Android.Views.InputMethods;
|
||||||
|
|
||||||
namespace Bit.Android.Services
|
namespace Bit.Android.Services
|
||||||
{
|
{
|
||||||
public class DeviceActionService : IDeviceActionService
|
public class DeviceActionService : IDeviceActionService
|
||||||
{
|
{
|
||||||
private readonly IAppSettingsService _appSettingsService;
|
private readonly IAppSettingsService _appSettingsService;
|
||||||
|
private readonly IUserDialogs _userDialogs;
|
||||||
private bool _cameraPermissionsDenied;
|
private bool _cameraPermissionsDenied;
|
||||||
|
private DateTime? _lastAction;
|
||||||
|
|
||||||
public DeviceActionService(
|
public DeviceActionService(
|
||||||
IAppSettingsService appSettingsService)
|
IAppSettingsService appSettingsService,
|
||||||
|
IUserDialogs userDialogs)
|
||||||
{
|
{
|
||||||
_appSettingsService = appSettingsService;
|
_appSettingsService = appSettingsService;
|
||||||
|
_userDialogs = userDialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyToClipboard(string text)
|
public void CopyToClipboard(string text)
|
||||||
|
@ -109,34 +123,10 @@ namespace Bit.Android.Services
|
||||||
catch(Exception) { }
|
catch(Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeleteDir(Java.IO.File dir)
|
|
||||||
{
|
|
||||||
if(dir != null && dir.IsDirectory)
|
|
||||||
{
|
|
||||||
var children = dir.List();
|
|
||||||
for(int i = 0; i < children.Length; i++)
|
|
||||||
{
|
|
||||||
var success = DeleteDir(new Java.IO.File(dir, children[i]));
|
|
||||||
if(!success)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir.Delete();
|
|
||||||
}
|
|
||||||
else if(dir != null && dir.IsFile)
|
|
||||||
{
|
|
||||||
return dir.Delete();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task SelectFileAsync()
|
public Task SelectFileAsync()
|
||||||
{
|
{
|
||||||
MessagingCenter.Unsubscribe<Application>(Application.Current, "SelectFileCameraPermissionDenied");
|
MessagingCenter.Unsubscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
||||||
|
"SelectFileCameraPermissionDenied");
|
||||||
|
|
||||||
var hasStorageWritePermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.WriteExternalStorage);
|
var hasStorageWritePermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.WriteExternalStorage);
|
||||||
|
|
||||||
|
@ -189,6 +179,195 @@ namespace Bit.Android.Services
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Autofill(VaultListPageModel.Cipher cipher)
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
if(activity.Intent.GetBooleanExtra("autofillFramework", false))
|
||||||
|
{
|
||||||
|
if(cipher == null)
|
||||||
|
{
|
||||||
|
activity.SetResult(Result.Canceled);
|
||||||
|
activity.Finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var structure = activity.Intent.GetParcelableExtra(
|
||||||
|
AutofillManager.ExtraAssistStructure) as AssistStructure;
|
||||||
|
if(structure == null)
|
||||||
|
{
|
||||||
|
activity.SetResult(Result.Canceled);
|
||||||
|
activity.Finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parser = new Parser(structure);
|
||||||
|
parser.Parse();
|
||||||
|
if(!parser.FieldCollection.Fields.Any() || string.IsNullOrWhiteSpace(parser.Uri))
|
||||||
|
{
|
||||||
|
activity.SetResult(Result.Canceled);
|
||||||
|
activity.Finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataset = AutofillHelpers.BuildDataset(activity, parser.FieldCollection,
|
||||||
|
new FilledItem(cipher.CipherModel));
|
||||||
|
var replyIntent = new Intent();
|
||||||
|
replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, dataset);
|
||||||
|
activity.SetResult(Result.Ok, replyIntent);
|
||||||
|
activity.Finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var data = new Intent();
|
||||||
|
if(cipher == null)
|
||||||
|
{
|
||||||
|
data.PutExtra("canceled", "true");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false;
|
||||||
|
var settings = Resolver.Resolve<ISettings>();
|
||||||
|
var autoCopyEnabled = !settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false);
|
||||||
|
if(isPremium && autoCopyEnabled && cipher.LoginTotp?.Value != null)
|
||||||
|
{
|
||||||
|
CopyToClipboard(App.Utilities.Crypto.Totp(cipher.LoginTotp.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.PutExtra("uri", cipher.LoginUri);
|
||||||
|
data.PutExtra("username", cipher.LoginUsername);
|
||||||
|
data.PutExtra("password", cipher.LoginPassword?.Value ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(activity.Parent == null)
|
||||||
|
{
|
||||||
|
activity.SetResult(Result.Ok, data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activity.Parent.SetResult(Result.Ok, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.Finish();
|
||||||
|
MessagingCenter.Send(Xamarin.Forms.Application.Current, "FinishMainActivity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseAutofill()
|
||||||
|
{
|
||||||
|
Autofill(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Background()
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
if(activity.Intent.GetBooleanExtra("autofillFramework", false))
|
||||||
|
{
|
||||||
|
activity.SetResult(Result.Canceled);
|
||||||
|
activity.Finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activity.MoveTaskToBack(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RateApp()
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rateIntent = RateIntentForUrl("market://details", activity);
|
||||||
|
activity.StartActivity(rateIntent);
|
||||||
|
}
|
||||||
|
catch(ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
var rateIntent = RateIntentForUrl("https://play.google.com/store/apps/details", activity);
|
||||||
|
activity.StartActivity(rateIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DismissKeyboard()
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var imm = (InputMethodManager)activity.GetSystemService(Context.InputMethodService);
|
||||||
|
imm.HideSoftInputFromWindow(activity.CurrentFocus.WindowToken, 0);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenAccessibilitySettings()
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
var intent = new Intent(Settings.ActionAccessibilitySettings);
|
||||||
|
activity.StartActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LaunchApp(string appName)
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)Forms.Context;
|
||||||
|
if(_lastAction.LastActionWasRecent())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_lastAction = DateTime.UtcNow;
|
||||||
|
|
||||||
|
appName = appName.Replace("androidapp://", string.Empty);
|
||||||
|
var launchIntent = activity.PackageManager.GetLaunchIntentForPackage(appName);
|
||||||
|
if(launchIntent == null)
|
||||||
|
{
|
||||||
|
_userDialogs.Alert(string.Format(AppResources.CannotOpenApp, appName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activity.StartActivity(launchIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Intent RateIntentForUrl(string url, Activity activity)
|
||||||
|
{
|
||||||
|
var intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse($"{url}?id={activity.PackageName}"));
|
||||||
|
var flags = ActivityFlags.NoHistory | ActivityFlags.MultipleTask;
|
||||||
|
if((int)Build.VERSION.SdkInt >= 21)
|
||||||
|
{
|
||||||
|
flags |= ActivityFlags.NewDocument;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// noinspection deprecation
|
||||||
|
flags |= ActivityFlags.ClearWhenTaskReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.AddFlags(flags);
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DeleteDir(Java.IO.File dir)
|
||||||
|
{
|
||||||
|
if(dir != null && dir.IsDirectory)
|
||||||
|
{
|
||||||
|
var children = dir.List();
|
||||||
|
for(int i = 0; i < children.Length; i++)
|
||||||
|
{
|
||||||
|
var success = DeleteDir(new Java.IO.File(dir, children[i]));
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dir.Delete();
|
||||||
|
}
|
||||||
|
else if(dir != null && dir.IsFile)
|
||||||
|
{
|
||||||
|
return dir.Delete();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<IParcelable> GetCameraIntents(global::Android.Net.Uri outputUri)
|
private List<IParcelable> GetCameraIntents(global::Android.Net.Uri outputUri)
|
||||||
{
|
{
|
||||||
var intents = new List<IParcelable>();
|
var intents = new List<IParcelable>();
|
||||||
|
@ -214,7 +393,8 @@ namespace Bit.Android.Services
|
||||||
|
|
||||||
private void AskCameraPermission(string permission)
|
private void AskCameraPermission(string permission)
|
||||||
{
|
{
|
||||||
MessagingCenter.Subscribe<Application>(Application.Current, "SelectFileCameraPermissionDenied", (sender) =>
|
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
|
||||||
|
"SelectFileCameraPermissionDenied", (sender) =>
|
||||||
{
|
{
|
||||||
_cameraPermissionsDenied = true;
|
_cameraPermissionsDenied = true;
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,17 +10,13 @@ namespace Bit.Android.Services
|
||||||
public class GoogleAnalyticsService : IGoogleAnalyticsService
|
public class GoogleAnalyticsService : IGoogleAnalyticsService
|
||||||
{
|
{
|
||||||
private readonly GoogleAnalytics _instance;
|
private readonly GoogleAnalytics _instance;
|
||||||
private readonly IAuthService _authService;
|
|
||||||
private readonly Tracker _tracker;
|
private readonly Tracker _tracker;
|
||||||
|
|
||||||
public GoogleAnalyticsService(
|
public GoogleAnalyticsService(
|
||||||
Context appContext,
|
Context appContext,
|
||||||
IAppIdService appIdService,
|
IAppIdService appIdService,
|
||||||
IAuthService authService,
|
|
||||||
ISettings settings)
|
ISettings settings)
|
||||||
{
|
{
|
||||||
_authService = authService;
|
|
||||||
|
|
||||||
_instance = GoogleAnalytics.GetInstance(appContext.ApplicationContext);
|
_instance = GoogleAnalytics.GetInstance(appContext.ApplicationContext);
|
||||||
_instance.SetLocalDispatchPeriod(10);
|
_instance.SetLocalDispatchPeriod(10);
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,8 @@ namespace Bit.App.Abstractions
|
||||||
bool UserIdChanged { get; }
|
bool UserIdChanged { get; }
|
||||||
string Email { get; set; }
|
string Email { get; set; }
|
||||||
string PIN { get; set; }
|
string PIN { get; set; }
|
||||||
|
|
||||||
bool BelongsToOrganization(string orgId);
|
bool BelongsToOrganization(string orgId);
|
||||||
void LogOut();
|
void LogOut(string logoutMessage = null);
|
||||||
Task<FullLoginResult> TokenPostAsync(string email, string masterPassword);
|
Task<FullLoginResult> TokenPostAsync(string email, string masterPassword);
|
||||||
Task<LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember, string email,
|
Task<LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember, string email,
|
||||||
string masterPasswordHash, SymmetricCryptoKey key);
|
string masterPasswordHash, SymmetricCryptoKey key);
|
||||||
|
|
|
@ -10,5 +10,12 @@ namespace Bit.App.Abstractions
|
||||||
bool CanOpenFile(string fileName);
|
bool CanOpenFile(string fileName);
|
||||||
Task SelectFileAsync();
|
Task SelectFileAsync();
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
void Autofill(Models.Page.VaultListPageModel.Cipher cipher);
|
||||||
|
void CloseAutofill();
|
||||||
|
void Background();
|
||||||
|
void RateApp();
|
||||||
|
void DismissKeyboard();
|
||||||
|
void OpenAccessibilitySettings();
|
||||||
|
void LaunchApp(string appName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,5 +8,7 @@ namespace Bit.App.Abstractions
|
||||||
{
|
{
|
||||||
void UpdateLastActivity(DateTime? activityDate = null);
|
void UpdateLastActivity(DateTime? activityDate = null);
|
||||||
Task<LockType> GetLockTypeAsync(bool forceLock);
|
Task<LockType> GetLockTypeAsync(bool forceLock);
|
||||||
|
Task CheckLockAsync(bool forceLock);
|
||||||
|
bool TopPageIsLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -86,27 +86,20 @@ namespace Bit.App
|
||||||
MainPage = new ExtendedNavigationPage(new HomePage());
|
MainPage = new ExtendedNavigationPage(new HomePage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Device.RuntimePlatform == Device.iOS)
|
||||||
|
{
|
||||||
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(async () => await CheckLockAsync(args));
|
Device.BeginInvokeOnMainThread(async () => await _lockService.CheckLockAsync(args));
|
||||||
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
|
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", (sender, args) =>
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(async () => await CheckLockAsync(args));
|
|
||||||
});
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Application, string>(Current, "Logout", (sender, args) =>
|
|
||||||
{
|
|
||||||
Logout(args);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async override void OnStart()
|
protected async override void OnStart()
|
||||||
{
|
{
|
||||||
// Handle when your app starts
|
// Handle when your app starts
|
||||||
await CheckLockAsync(false);
|
await _lockService.CheckLockAsync(false);
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(_options.Uri))
|
if(string.IsNullOrWhiteSpace(_options.Uri))
|
||||||
{
|
{
|
||||||
|
@ -132,7 +125,7 @@ namespace Bit.App
|
||||||
|
|
||||||
SetMainPageFromAutofill();
|
SetMainPageFromAutofill();
|
||||||
|
|
||||||
if(Device.RuntimePlatform == Device.Android && !TopPageIsLock())
|
if(Device.RuntimePlatform == Device.Android && !_lockService.TopPageIsLock())
|
||||||
{
|
{
|
||||||
_lockService.UpdateLastActivity();
|
_lockService.UpdateLastActivity();
|
||||||
}
|
}
|
||||||
|
@ -151,7 +144,7 @@ namespace Bit.App
|
||||||
|
|
||||||
if(Device.RuntimePlatform == Device.Android)
|
if(Device.RuntimePlatform == Device.Android)
|
||||||
{
|
{
|
||||||
await CheckLockAsync(false);
|
await _lockService.CheckLockAsync(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
||||||
|
@ -227,73 +220,6 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Logout(string logoutMessage)
|
|
||||||
{
|
|
||||||
_authService.LogOut();
|
|
||||||
|
|
||||||
var deviceApiRepository = Resolver.Resolve<IDeviceApiRepository>();
|
|
||||||
var appIdService = Resolver.Resolve<IAppIdService>();
|
|
||||||
Task.Run(async () => await deviceApiRepository.PutClearTokenAsync(appIdService.AppId));
|
|
||||||
|
|
||||||
_googleAnalyticsService.TrackAppEvent("LoggedOut");
|
|
||||||
|
|
||||||
Device.BeginInvokeOnMainThread(() => Current.MainPage = new ExtendedNavigationPage(new HomePage()));
|
|
||||||
if(!string.IsNullOrWhiteSpace(logoutMessage))
|
|
||||||
{
|
|
||||||
_userDialogs.Toast(logoutMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CheckLockAsync(bool forceLock)
|
|
||||||
{
|
|
||||||
if(TopPageIsLock())
|
|
||||||
{
|
|
||||||
// already locked
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lockType = await _lockService.GetLockTypeAsync(forceLock);
|
|
||||||
if(lockType == Enums.LockType.None)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_appSettingsService.Locked = true;
|
|
||||||
switch(lockType)
|
|
||||||
{
|
|
||||||
case Enums.LockType.Fingerprint:
|
|
||||||
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockFingerprintPage(!forceLock)), false);
|
|
||||||
break;
|
|
||||||
case Enums.LockType.PIN:
|
|
||||||
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockPinPage()), false);
|
|
||||||
break;
|
|
||||||
case Enums.LockType.Password:
|
|
||||||
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockPasswordPage()), false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TopPageIsLock()
|
|
||||||
{
|
|
||||||
var currentPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as ExtendedNavigationPage;
|
|
||||||
if((currentPage?.CurrentPage as LockFingerprintPage) != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if((currentPage?.CurrentPage as LockPinPage) != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if((currentPage?.CurrentPage as LockPasswordPage) != null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetStyles()
|
private void SetStyles()
|
||||||
{
|
{
|
||||||
var gray = Color.FromHex("333333");
|
var gray = Color.FromHex("333333");
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Plugin.Settings.Abstractions;
|
|
||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
@ -11,6 +9,7 @@ namespace Bit.App.Controls
|
||||||
private ISyncService _syncService;
|
private ISyncService _syncService;
|
||||||
private IGoogleAnalyticsService _googleAnalyticsService;
|
private IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private ILockService _lockService;
|
private ILockService _lockService;
|
||||||
|
private IDeviceActionService _deviceActionService;
|
||||||
private bool _syncIndicator;
|
private bool _syncIndicator;
|
||||||
private bool _updateActivity;
|
private bool _updateActivity;
|
||||||
|
|
||||||
|
@ -21,25 +20,21 @@ namespace Bit.App.Controls
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||||
_lockService = Resolver.Resolve<ILockService>();
|
_lockService = Resolver.Resolve<ILockService>();
|
||||||
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
||||||
BackgroundColor = Color.FromHex("efeff4");
|
BackgroundColor = Color.FromHex("efeff4");
|
||||||
|
|
||||||
if(_syncIndicator)
|
|
||||||
{
|
|
||||||
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted", (sender, success) =>
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(() => IsBusy = _syncService.SyncInProgress);
|
|
||||||
});
|
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Application>(Application.Current, "SyncStarted", (sender) =>
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(() => IsBusy = _syncService.SyncInProgress);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
|
if(_syncIndicator)
|
||||||
|
{
|
||||||
|
MessagingCenter.Subscribe<ISyncService, bool>(_syncService, "SyncCompleted",
|
||||||
|
(sender, success) => Device.BeginInvokeOnMainThread(() => IsBusy = _syncService.SyncInProgress));
|
||||||
|
MessagingCenter.Subscribe<ISyncService>(_syncService, "SyncStarted",
|
||||||
|
(sender) => Device.BeginInvokeOnMainThread(() => IsBusy = _syncService.SyncInProgress));
|
||||||
|
}
|
||||||
|
|
||||||
if(_syncIndicator)
|
if(_syncIndicator)
|
||||||
{
|
{
|
||||||
IsBusy = _syncService.SyncInProgress;
|
IsBusy = _syncService.SyncInProgress;
|
||||||
|
@ -51,6 +46,12 @@ namespace Bit.App.Controls
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
|
if(_syncIndicator)
|
||||||
|
{
|
||||||
|
MessagingCenter.Unsubscribe<ISyncService, bool>(_syncService, "SyncCompleted");
|
||||||
|
MessagingCenter.Unsubscribe<ISyncService>(_syncService, "SyncStarted");
|
||||||
|
}
|
||||||
|
|
||||||
if(_syncIndicator)
|
if(_syncIndicator)
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
|
@ -62,7 +63,7 @@ namespace Bit.App.Controls
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
MessagingCenter.Send(Application.Current, "DismissKeyboard");
|
_deviceActionService.DismissKeyboard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,28 @@ using Bit.App.Controls;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class BaseLockPage : ExtendedContentPage
|
public class BaseLockPage : ExtendedContentPage
|
||||||
{
|
{
|
||||||
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
|
|
||||||
public BaseLockPage()
|
public BaseLockPage()
|
||||||
: base(false, false)
|
: base(false, false)
|
||||||
{
|
{
|
||||||
|
|
||||||
UserDialogs = Resolver.Resolve<IUserDialogs>();
|
UserDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
|
AuthService = Resolver.Resolve<IAuthService>();
|
||||||
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IUserDialogs UserDialogs { get; set; }
|
protected IUserDialogs UserDialogs { get; set; }
|
||||||
|
protected IAuthService AuthService { get; set; }
|
||||||
|
|
||||||
protected override bool OnBackButtonPressed()
|
protected override bool OnBackButtonPressed()
|
||||||
{
|
{
|
||||||
if(Device.RuntimePlatform == Device.Android)
|
_deviceActionService.Background();
|
||||||
{
|
|
||||||
MessagingCenter.Send(Application.Current, "BackgroundApp");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +35,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AuthService.LogOut();
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
else if(result.Status == FingerprintAuthenticationResultStatus.FallbackRequested)
|
else if(result.Status == FingerprintAuthenticationResultStatus.FallbackRequested)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
AuthService.LogOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace Bit.App.Pages
|
||||||
private IUserDialogs _userDialogs;
|
private IUserDialogs _userDialogs;
|
||||||
private ISyncService _syncService;
|
private ISyncService _syncService;
|
||||||
private IDeviceInfoService _deviceInfoService;
|
private IDeviceInfoService _deviceInfoService;
|
||||||
|
private IDeviceActionService _deviceActionService;
|
||||||
private IGoogleAnalyticsService _googleAnalyticsService;
|
private IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private ITwoFactorApiRepository _twoFactorApiRepository;
|
private ITwoFactorApiRepository _twoFactorApiRepository;
|
||||||
private IPushNotificationService _pushNotification;
|
private IPushNotificationService _pushNotification;
|
||||||
|
@ -45,6 +46,7 @@ namespace Bit.App.Pages
|
||||||
_providers = result.TwoFactorProviders;
|
_providers = result.TwoFactorProviders;
|
||||||
_providerType = type ?? GetDefaultProvider();
|
_providerType = type ?? GetDefaultProvider();
|
||||||
|
|
||||||
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
_authService = Resolver.Resolve<IAuthService>();
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
|
@ -266,7 +268,7 @@ namespace Bit.App.Pages
|
||||||
InitEvents();
|
InitEvents();
|
||||||
if(TokenCell == null && Device.RuntimePlatform == Device.Android)
|
if(TokenCell == null && Device.RuntimePlatform == Device.Android)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "DismissKeyboard");
|
_deviceActionService.DismissKeyboard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ namespace Bit.App.Pages
|
||||||
private readonly IFingerprint _fingerprint;
|
private readonly IFingerprint _fingerprint;
|
||||||
private readonly IPushNotificationService _pushNotification;
|
private readonly IPushNotificationService _pushNotification;
|
||||||
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private readonly IDeviceInfoService _deviceInfoService;
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
|
private readonly ILockService _lockService;
|
||||||
|
|
||||||
// TODO: Model binding context?
|
// TODO: Model binding context?
|
||||||
|
|
||||||
|
@ -31,7 +32,8 @@ namespace Bit.App.Pages
|
||||||
_fingerprint = Resolver.Resolve<IFingerprint>();
|
_fingerprint = Resolver.Resolve<IFingerprint>();
|
||||||
_pushNotification = Resolver.Resolve<IPushNotificationService>();
|
_pushNotification = Resolver.Resolve<IPushNotificationService>();
|
||||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
_lockService = Resolver.Resolve<ILockService>();
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
@ -327,22 +329,7 @@ namespace Bit.App.Pages
|
||||||
private void RateCell_Tapped(object sender, EventArgs e)
|
private void RateCell_Tapped(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_googleAnalyticsService.TrackAppEvent("OpenedSetting", "RateApp");
|
_googleAnalyticsService.TrackAppEvent("OpenedSetting", "RateApp");
|
||||||
if(Device.RuntimePlatform == Device.iOS)
|
_deviceActionService.RateApp();
|
||||||
{
|
|
||||||
if(_deviceInfoService.Version < 11)
|
|
||||||
{
|
|
||||||
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
|
|
||||||
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/us/app/id1137397744?action=write-review"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
MessagingCenter.Send(Application.Current, "RateApp");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HelpCell_Tapped(object sender, EventArgs e)
|
private void HelpCell_Tapped(object sender, EventArgs e)
|
||||||
|
@ -353,7 +340,7 @@ namespace Bit.App.Pages
|
||||||
private void LockCell_Tapped(object sender, EventArgs e)
|
private void LockCell_Tapped(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_googleAnalyticsService.TrackAppEvent("Locked");
|
_googleAnalyticsService.TrackAppEvent("Locked");
|
||||||
MessagingCenter.Send(Application.Current, "Lock", true);
|
Device.BeginInvokeOnMainThread(async () => await _lockService.CheckLockAsync(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void LogOutCell_Tapped(object sender, EventArgs e)
|
private async void LogOutCell_Tapped(object sender, EventArgs e)
|
||||||
|
@ -363,7 +350,7 @@ namespace Bit.App.Pages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ChangeMasterPasswordCell_Tapped(object sender, EventArgs e)
|
private async void ChangeMasterPasswordCell_Tapped(object sender, EventArgs e)
|
||||||
|
|
|
@ -12,12 +12,14 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private readonly IAppInfoService _appInfoService;
|
private readonly IAppInfoService _appInfoService;
|
||||||
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private bool _pageDisappeared = false;
|
private bool _pageDisappeared = false;
|
||||||
|
|
||||||
public ToolsAutofillServicePage()
|
public ToolsAutofillServicePage()
|
||||||
{
|
{
|
||||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||||
_appInfoService = Resolver.Resolve<IAppInfoService>();
|
_appInfoService = Resolver.Resolve<IAppInfoService>();
|
||||||
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
@ -221,7 +223,7 @@ namespace Bit.App.Pages
|
||||||
Command = new Command(() =>
|
Command = new Command(() =>
|
||||||
{
|
{
|
||||||
_googleAnalyticsService.TrackAppEvent("OpenAccessibilitySettings");
|
_googleAnalyticsService.TrackAppEvent("OpenAccessibilitySettings");
|
||||||
MessagingCenter.Send(Application.Current, "Accessibility");
|
_deviceActionService.OpenAccessibilitySettings();
|
||||||
}),
|
}),
|
||||||
VerticalOptions = LayoutOptions.End,
|
VerticalOptions = LayoutOptions.End,
|
||||||
HorizontalOptions = LayoutOptions.Fill,
|
HorizontalOptions = LayoutOptions.Fill,
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace Bit.App.Pages
|
||||||
private readonly ISettings _settings;
|
private readonly ISettings _settings;
|
||||||
private readonly IAppInfoService _appInfoService;
|
private readonly IAppInfoService _appInfoService;
|
||||||
private readonly IDeviceInfoService _deviceInfo;
|
private readonly IDeviceInfoService _deviceInfo;
|
||||||
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private readonly string _defaultUri;
|
private readonly string _defaultUri;
|
||||||
private readonly string _defaultName;
|
private readonly string _defaultName;
|
||||||
private readonly string _defaultUsername;
|
private readonly string _defaultUsername;
|
||||||
|
@ -75,6 +76,7 @@ namespace Bit.App.Pages
|
||||||
_settings = Resolver.Resolve<ISettings>();
|
_settings = Resolver.Resolve<ISettings>();
|
||||||
_appInfoService = Resolver.Resolve<IAppInfoService>();
|
_appInfoService = Resolver.Resolve<IAppInfoService>();
|
||||||
_deviceInfo = Resolver.Resolve<IDeviceInfoService>();
|
_deviceInfo = Resolver.Resolve<IDeviceInfoService>();
|
||||||
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
||||||
if(doInit)
|
if(doInit)
|
||||||
{
|
{
|
||||||
|
@ -751,7 +753,7 @@ namespace Bit.App.Pages
|
||||||
if(_fromAutofillFramework)
|
if(_fromAutofillFramework)
|
||||||
{
|
{
|
||||||
// close and go back to app
|
// close and go back to app
|
||||||
MessagingCenter.Send(Application.Current, "Autofill", (VaultListPageModel.Cipher)null);
|
_deviceActionService.CloseAutofill();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IDeviceInfoService _deviceInfoService;
|
private readonly IDeviceInfoService _deviceInfoService;
|
||||||
private readonly IDeviceActionService _clipboardService;
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
private readonly IAppSettingsService _appSettingsService;
|
private readonly IAppSettingsService _appSettingsService;
|
||||||
private CancellationTokenSource _filterResultsCancellationTokenSource;
|
private CancellationTokenSource _filterResultsCancellationTokenSource;
|
||||||
|
@ -44,7 +44,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
_cipherService = Resolver.Resolve<ICipherService>();
|
_cipherService = Resolver.Resolve<ICipherService>();
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||||
_clipboardService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
_settingsService = Resolver.Resolve<ISettingsService>();
|
_settingsService = Resolver.Resolve<ISettingsService>();
|
||||||
UserDialogs = Resolver.Resolve<IUserDialogs>();
|
UserDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_appSettingsService = Resolver.Resolve<IAppSettingsService>();
|
_appSettingsService = Resolver.Resolve<IAppSettingsService>();
|
||||||
|
@ -141,7 +141,7 @@ namespace Bit.App.Pages
|
||||||
protected override bool OnBackButtonPressed()
|
protected override bool OnBackButtonPressed()
|
||||||
{
|
{
|
||||||
GoogleAnalyticsService.TrackExtensionEvent("BackClosed", Uri.StartsWith("http") ? "Website" : "App");
|
GoogleAnalyticsService.TrackExtensionEvent("BackClosed", Uri.StartsWith("http") ? "Website" : "App");
|
||||||
MessagingCenter.Send(Application.Current, "Autofill", (VaultListPageModel.Cipher)null);
|
_deviceActionService.CloseAutofill();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ namespace Bit.App.Pages
|
||||||
if(doAutofill)
|
if(doAutofill)
|
||||||
{
|
{
|
||||||
GoogleAnalyticsService.TrackExtensionEvent("AutoFilled", Uri.StartsWith("http") ? "Website" : "App");
|
GoogleAnalyticsService.TrackExtensionEvent("AutoFilled", Uri.StartsWith("http") ? "Website" : "App");
|
||||||
MessagingCenter.Send(Application.Current, "Autofill", cipher as VaultListPageModel.Cipher);
|
_deviceActionService.Autofill(cipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private void Copy(string copyText, string alertLabel)
|
private void Copy(string copyText, string alertLabel)
|
||||||
{
|
{
|
||||||
_clipboardService.CopyToClipboard(copyText);
|
_deviceActionService.CopyToClipboard(copyText);
|
||||||
UserDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
UserDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Bit.App.Pages
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IUserDialogs _userDialogs;
|
private readonly IUserDialogs _userDialogs;
|
||||||
private readonly IConnectivity _connectivity;
|
private readonly IConnectivity _connectivity;
|
||||||
private readonly IDeviceActionService _clipboardService;
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private readonly ISyncService _syncService;
|
private readonly ISyncService _syncService;
|
||||||
private readonly IPushNotificationService _pushNotification;
|
private readonly IPushNotificationService _pushNotification;
|
||||||
private readonly IDeviceInfoService _deviceInfoService;
|
private readonly IDeviceInfoService _deviceInfoService;
|
||||||
|
@ -42,7 +42,7 @@ namespace Bit.App.Pages
|
||||||
_cipherService = Resolver.Resolve<ICipherService>();
|
_cipherService = Resolver.Resolve<ICipherService>();
|
||||||
_connectivity = Resolver.Resolve<IConnectivity>();
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_clipboardService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
_pushNotification = Resolver.Resolve<IPushNotificationService>();
|
_pushNotification = Resolver.Resolve<IPushNotificationService>();
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||||
|
@ -71,14 +71,6 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted", (sender, success) =>
|
|
||||||
{
|
|
||||||
if(success)
|
|
||||||
{
|
|
||||||
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!_favorites)
|
if(!_favorites)
|
||||||
{
|
{
|
||||||
AddCipherItem = new AddCipherToolBarItem(this);
|
AddCipherItem = new AddCipherToolBarItem(this);
|
||||||
|
@ -232,6 +224,14 @@ namespace Bit.App.Pages
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
MessagingCenter.Subscribe<ISyncService, bool>(_syncService, "SyncCompleted", (sender, success) =>
|
||||||
|
{
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ListView.ItemSelected += CipherSelected;
|
ListView.ItemSelected += CipherSelected;
|
||||||
Search.TextChanged += SearchBar_TextChanged;
|
Search.TextChanged += SearchBar_TextChanged;
|
||||||
Search.SearchButtonPressed += SearchBar_SearchButtonPressed;
|
Search.SearchButtonPressed += SearchBar_SearchButtonPressed;
|
||||||
|
@ -274,6 +274,8 @@ namespace Bit.App.Pages
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
|
MessagingCenter.Unsubscribe<ISyncService, bool>(_syncService, "SyncCompleted");
|
||||||
|
|
||||||
ListView.ItemSelected -= CipherSelected;
|
ListView.ItemSelected -= CipherSelected;
|
||||||
Search.TextChanged -= SearchBar_TextChanged;
|
Search.TextChanged -= SearchBar_TextChanged;
|
||||||
Search.SearchButtonPressed -= SearchBar_SearchButtonPressed;
|
Search.SearchButtonPressed -= SearchBar_SearchButtonPressed;
|
||||||
|
@ -288,7 +290,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
_googleAnalyticsService.TrackExtensionEvent("BackClosed", Uri.StartsWith("http") ? "Website" : "App");
|
_googleAnalyticsService.TrackExtensionEvent("BackClosed", Uri.StartsWith("http") ? "Website" : "App");
|
||||||
MessagingCenter.Send(Application.Current, "Autofill", (VaultListPageModel.Cipher)null);
|
_deviceActionService.CloseAutofill();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +419,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
_googleAnalyticsService.TrackExtensionEvent("AutoFilled",
|
_googleAnalyticsService.TrackExtensionEvent("AutoFilled",
|
||||||
Uri.StartsWith("http") ? "Website" : "App");
|
Uri.StartsWith("http") ? "Website" : "App");
|
||||||
MessagingCenter.Send(Application.Current, "Autofill", cipher);
|
_deviceActionService.Autofill(cipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +494,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private void Copy(string copyText, string alertLabel)
|
private void Copy(string copyText, string alertLabel)
|
||||||
{
|
{
|
||||||
_clipboardService.CopyToClipboard(copyText);
|
_deviceActionService.CopyToClipboard(copyText);
|
||||||
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if(Device.RuntimePlatform == Device.Android && Model.LoginUri.StartsWith("androidapp://"))
|
if(Device.RuntimePlatform == Device.Android && Model.LoginUri.StartsWith("androidapp://"))
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "LaunchApp", Model.LoginUri);
|
_deviceActionService.LaunchApp(Model.LoginUri);
|
||||||
}
|
}
|
||||||
else if(Model.LoginUri.StartsWith("http://") || Model.LoginUri.StartsWith("https://"))
|
else if(Model.LoginUri.StartsWith("http://") || Model.LoginUri.StartsWith("https://"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,10 @@ using Plugin.Settings.Abstractions;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Bit.App.Enums;
|
using Bit.App.Enums;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Bit.App.Pages;
|
||||||
|
using Bit.App.Controls;
|
||||||
|
using Acr.UserDialogs;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
|
@ -25,6 +29,9 @@ namespace Bit.App.Services
|
||||||
private readonly IAccountsApiRepository _accountsApiRepository;
|
private readonly IAccountsApiRepository _accountsApiRepository;
|
||||||
private readonly IAppIdService _appIdService;
|
private readonly IAppIdService _appIdService;
|
||||||
private readonly IDeviceInfoService _deviceInfoService;
|
private readonly IDeviceInfoService _deviceInfoService;
|
||||||
|
private readonly IDeviceApiRepository _deviceApiRepository;
|
||||||
|
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
|
private readonly IUserDialogs _userDialogs;
|
||||||
|
|
||||||
private string _email;
|
private string _email;
|
||||||
private string _userId;
|
private string _userId;
|
||||||
|
@ -39,7 +46,10 @@ namespace Bit.App.Services
|
||||||
IConnectApiRepository connectApiRepository,
|
IConnectApiRepository connectApiRepository,
|
||||||
IAccountsApiRepository accountsApiRepository,
|
IAccountsApiRepository accountsApiRepository,
|
||||||
IAppIdService appIdService,
|
IAppIdService appIdService,
|
||||||
IDeviceInfoService deviceInfoService)
|
IDeviceInfoService deviceInfoService,
|
||||||
|
IDeviceApiRepository deviceApiRepository,
|
||||||
|
IGoogleAnalyticsService googleAnalyticsService,
|
||||||
|
IUserDialogs userDialogs)
|
||||||
{
|
{
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = secureStorage;
|
||||||
_tokenService = tokenService;
|
_tokenService = tokenService;
|
||||||
|
@ -49,6 +59,9 @@ namespace Bit.App.Services
|
||||||
_accountsApiRepository = accountsApiRepository;
|
_accountsApiRepository = accountsApiRepository;
|
||||||
_appIdService = appIdService;
|
_appIdService = appIdService;
|
||||||
_deviceInfoService = deviceInfoService;
|
_deviceInfoService = deviceInfoService;
|
||||||
|
_deviceApiRepository = deviceApiRepository;
|
||||||
|
_googleAnalyticsService = googleAnalyticsService;
|
||||||
|
_userDialogs = userDialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UserId
|
public string UserId
|
||||||
|
@ -194,7 +207,7 @@ namespace Bit.App.Services
|
||||||
return !string.IsNullOrWhiteSpace(orgId) && (_cryptoService.OrgKeys?.ContainsKey(orgId) ?? false);
|
return !string.IsNullOrWhiteSpace(orgId) && (_cryptoService.OrgKeys?.ContainsKey(orgId) ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogOut()
|
public void LogOut(string logoutMessage = null)
|
||||||
{
|
{
|
||||||
_tokenService.Token = null;
|
_tokenService.Token = null;
|
||||||
_tokenService.RefreshToken = null;
|
_tokenService.RefreshToken = null;
|
||||||
|
@ -204,6 +217,16 @@ namespace Bit.App.Services
|
||||||
_settings.Remove(Constants.SecurityStamp);
|
_settings.Remove(Constants.SecurityStamp);
|
||||||
_settings.Remove(Constants.PushLastRegistrationDate);
|
_settings.Remove(Constants.PushLastRegistrationDate);
|
||||||
_settings.Remove(Constants.Locked);
|
_settings.Remove(Constants.Locked);
|
||||||
|
|
||||||
|
Task.Run(async () => await _deviceApiRepository.PutClearTokenAsync(_appIdService.AppId));
|
||||||
|
|
||||||
|
_googleAnalyticsService.TrackAppEvent("LoggedOut");
|
||||||
|
|
||||||
|
Device.BeginInvokeOnMainThread(() => Application.Current.MainPage = new ExtendedNavigationPage(new HomePage()));
|
||||||
|
if(!string.IsNullOrWhiteSpace(logoutMessage))
|
||||||
|
{
|
||||||
|
_userDialogs.Toast(logoutMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FullLoginResult> TokenPostAsync(string email, string masterPassword)
|
public async Task<FullLoginResult> TokenPostAsync(string email, string masterPassword)
|
||||||
|
@ -249,10 +272,10 @@ namespace Bit.App.Services
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember,
|
public async Task<Models.LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember,
|
||||||
string email, string masterPasswordHash, SymmetricCryptoKey key)
|
string email, string masterPasswordHash, SymmetricCryptoKey key)
|
||||||
{
|
{
|
||||||
var result = new LoginResult();
|
var result = new Models.LoginResult();
|
||||||
|
|
||||||
var request = new TokenRequest
|
var request = new TokenRequest
|
||||||
{
|
{
|
||||||
|
|
|
@ -250,7 +250,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -272,7 +272,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -334,7 +334,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -359,7 +359,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -91,7 +91,7 @@ namespace Bit.App.Services
|
||||||
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -4,6 +4,10 @@ using Plugin.Settings.Abstractions;
|
||||||
using Plugin.Fingerprint.Abstractions;
|
using Plugin.Fingerprint.Abstractions;
|
||||||
using Bit.App.Enums;
|
using Bit.App.Enums;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Controls;
|
||||||
|
using Bit.App.Pages;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
|
@ -79,5 +83,58 @@ namespace Bit.App.Services
|
||||||
return LockType.Password;
|
return LockType.Password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CheckLockAsync(bool forceLock)
|
||||||
|
{
|
||||||
|
if(TopPageIsLock())
|
||||||
|
{
|
||||||
|
// already locked
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lockType = await GetLockTypeAsync(forceLock);
|
||||||
|
if(lockType == LockType.None)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_appSettings.Locked = true;
|
||||||
|
switch(lockType)
|
||||||
|
{
|
||||||
|
case LockType.Fingerprint:
|
||||||
|
await Application.Current.MainPage.Navigation.PushModalAsync(
|
||||||
|
new ExtendedNavigationPage(new LockFingerprintPage(!forceLock)), false);
|
||||||
|
break;
|
||||||
|
case LockType.PIN:
|
||||||
|
await Application.Current.MainPage.Navigation.PushModalAsync(
|
||||||
|
new ExtendedNavigationPage(new LockPinPage()), false);
|
||||||
|
break;
|
||||||
|
case LockType.Password:
|
||||||
|
await Application.Current.MainPage.Navigation.PushModalAsync(
|
||||||
|
new ExtendedNavigationPage(new LockPasswordPage()), false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TopPageIsLock()
|
||||||
|
{
|
||||||
|
var currentPage = Application.Current.MainPage.Navigation.ModalStack.LastOrDefault() as ExtendedNavigationPage;
|
||||||
|
if((currentPage?.CurrentPage as LockFingerprintPage) != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if((currentPage?.CurrentPage as LockPinPage) != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if((currentPage?.CurrentPage as LockPasswordPage) != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ namespace Bit.App.Services
|
||||||
if(Application.Current != null && (accountRevisionDate.StatusCode == System.Net.HttpStatusCode.Forbidden
|
if(Application.Current != null && (accountRevisionDate.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||||
|| accountRevisionDate.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
|| accountRevisionDate.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -477,7 +477,7 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncInProgress = true;
|
SyncInProgress = true;
|
||||||
MessagingCenter.Send(Application.Current, "SyncStarted");
|
MessagingCenter.Send(this, "SyncStarted");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SyncCompleted(bool successfully)
|
private void SyncCompleted(bool successfully)
|
||||||
|
@ -488,7 +488,7 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncInProgress = false;
|
SyncInProgress = false;
|
||||||
MessagingCenter.Send(Application.Current, "SyncCompleted", successfully);
|
MessagingCenter.Send(this, "SyncCompleted", successfully);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckSuccess<T>(ApiResult<T> result, bool logout = false)
|
private bool CheckSuccess<T>(ApiResult<T> result, bool logout = false)
|
||||||
|
@ -501,7 +501,7 @@ namespace Bit.App.Services
|
||||||
result.StatusCode == System.Net.HttpStatusCode.Forbidden ||
|
result.StatusCode == System.Net.HttpStatusCode.Forbidden ||
|
||||||
result.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
result.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
_authService.LogOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -8,15 +8,11 @@ namespace Bit.iOS.Core.Services
|
||||||
public class GoogleAnalyticsService : IGoogleAnalyticsService
|
public class GoogleAnalyticsService : IGoogleAnalyticsService
|
||||||
{
|
{
|
||||||
private readonly ITracker _tracker;
|
private readonly ITracker _tracker;
|
||||||
private readonly IAuthService _authService;
|
|
||||||
|
|
||||||
public GoogleAnalyticsService(
|
public GoogleAnalyticsService(
|
||||||
IAppIdService appIdService,
|
IAppIdService appIdService,
|
||||||
IAuthService authService,
|
|
||||||
ISettings settings)
|
ISettings settings)
|
||||||
{
|
{
|
||||||
_authService = authService;
|
|
||||||
|
|
||||||
Gai.SharedInstance.DispatchInterval = 10;
|
Gai.SharedInstance.DispatchInterval = 10;
|
||||||
Gai.SharedInstance.TrackUncaughtExceptions = false;
|
Gai.SharedInstance.TrackUncaughtExceptions = false;
|
||||||
_tracker = Gai.SharedInstance.GetTracker("UA-81915606-1");
|
_tracker = Gai.SharedInstance.GetTracker("UA-81915606-1");
|
||||||
|
|
|
@ -9,16 +9,21 @@ using Xamarin.Forms;
|
||||||
using Photos;
|
using Photos;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models.Page;
|
||||||
|
|
||||||
namespace Bit.iOS.Services
|
namespace Bit.iOS.Services
|
||||||
{
|
{
|
||||||
public class DeviceActionService : IDeviceActionService
|
public class DeviceActionService : IDeviceActionService
|
||||||
{
|
{
|
||||||
private readonly IAppSettingsService _appSettingsService;
|
private readonly IAppSettingsService _appSettingsService;
|
||||||
|
private readonly IDeviceInfoService _deviceInfoService;
|
||||||
|
|
||||||
public DeviceActionService(IAppSettingsService appSettingsService)
|
public DeviceActionService(
|
||||||
|
IAppSettingsService appSettingsService,
|
||||||
|
IDeviceInfoService deviceInfoService)
|
||||||
{
|
{
|
||||||
_appSettingsService = appSettingsService;
|
_appSettingsService = appSettingsService;
|
||||||
|
_deviceInfoService = deviceInfoService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyToClipboard(string text)
|
public void CopyToClipboard(string text)
|
||||||
|
@ -202,5 +207,48 @@ namespace Bit.iOS.Services
|
||||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
|
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
|
||||||
new Tuple<byte[], string>(data, fileName));
|
new Tuple<byte[], string>(data, fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Autofill(VaultListPageModel.Cipher cipher)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseAutofill()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Background()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RateApp()
|
||||||
|
{
|
||||||
|
if(_deviceInfoService.Version < 11)
|
||||||
|
{
|
||||||
|
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
|
||||||
|
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/us/app/id1137397744?action=write-review"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DismissKeyboard()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenAccessibilitySettings()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LaunchApp(string appName)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue