1
0
mirror of https://github.com/bitwarden/mobile.git synced 2024-06-25 10:26:02 +02:00
bitwarden-mobile/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs

360 lines
16 KiB
C#
Raw Normal View History

2019-05-15 19:09:49 +02:00
using Bit.App.Abstractions;
using Bit.App.Resources;
2019-05-16 20:55:18 +02:00
using Bit.Core;
2019-05-15 15:14:49 +02:00
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
2019-05-14 15:09:35 +02:00
using System;
2019-03-29 04:52:33 +01:00
using System.Collections.Generic;
2019-05-16 20:55:18 +02:00
using System.Linq;
2019-05-15 15:14:49 +02:00
using System.Threading.Tasks;
2019-04-05 22:13:17 +02:00
using Xamarin.Forms;
2019-03-29 04:52:33 +01:00
namespace Bit.App.Pages
{
public class SettingsPageViewModel : BaseViewModel
{
2019-05-15 15:14:49 +02:00
private readonly IPlatformUtilsService _platformUtilsService;
2019-05-15 18:54:48 +02:00
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
2019-05-15 19:09:49 +02:00
private readonly IDeviceActionService _deviceActionService;
2019-05-15 19:26:55 +02:00
private readonly IEnvironmentService _environmentService;
private readonly IMessagingService _messagingService;
2019-05-15 21:47:50 +02:00
private readonly ILockService _lockService;
2019-05-16 20:55:18 +02:00
private readonly IStorageService _storageService;
private readonly ISyncService _syncService;
2019-05-16 22:31:58 +02:00
private string _fingerprintName;
private bool _supportsFingerprint;
2019-05-16 20:55:18 +02:00
private bool _pin;
private bool _fingerprint;
private string _lastSyncDate;
private string _lockOptionValue;
private List<KeyValuePair<string, int?>> _lockOptions =
new List<KeyValuePair<string, int?>>
{
new KeyValuePair<string, int?>(AppResources.LockOptionImmediately, 0),
new KeyValuePair<string, int?>(AppResources.LockOption1Minute, 1),
new KeyValuePair<string, int?>(AppResources.LockOption5Minutes, 5),
new KeyValuePair<string, int?>(AppResources.LockOption15Minutes, 15),
new KeyValuePair<string, int?>(AppResources.LockOption30Minutes, 30),
new KeyValuePair<string, int?>(AppResources.LockOption1Hour, 60),
new KeyValuePair<string, int?>(AppResources.LockOption4Hours, 240),
new KeyValuePair<string, int?>(AppResources.Never, null),
};
2019-05-15 15:14:49 +02:00
2019-03-29 04:52:33 +01:00
public SettingsPageViewModel()
{
2019-05-15 15:14:49 +02:00
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
2019-05-15 18:54:48 +02:00
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
_userService = ServiceContainer.Resolve<IUserService>("userService");
2019-05-15 19:09:49 +02:00
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
2019-05-15 19:26:55 +02:00
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
2019-05-15 21:47:50 +02:00
_lockService = ServiceContainer.Resolve<ILockService>("lockService");
2019-05-16 20:55:18 +02:00
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
2019-04-05 22:13:17 +02:00
2019-05-16 20:55:18 +02:00
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
2019-05-15 15:14:49 +02:00
PageTitle = AppResources.Settings;
2019-05-16 22:31:58 +02:00
_fingerprintName = AppResources.Fingerprint;
if(Device.RuntimePlatform == Device.iOS)
{
_fingerprintName = AppResources.TouchID;
// TODO: face id
}
2019-03-29 04:52:33 +01:00
}
2019-04-05 22:13:17 +02:00
2019-05-16 20:55:18 +02:00
public ExtendedObservableCollection<SettingsPageListGroup> GroupedItems { get; set; }
public async Task InitAsync()
{
2019-05-16 22:31:58 +02:00
_supportsFingerprint = await _platformUtilsService.SupportsFingerprintAsync();
2019-05-16 20:55:18 +02:00
var lastSync = await _syncService.GetLastSyncAsync();
if(lastSync != null)
{
_lastSyncDate = string.Format("{0} {1}", lastSync.Value.ToShortDateString(),
lastSync.Value.ToShortTimeString());
}
var option = await _storageService.GetAsync<int?>(Constants.LockOptionKey);
_lockOptionValue = _lockOptions.FirstOrDefault(o => o.Value == option).Key;
var pinSet = await _lockService.IsPinLockSetAsync();
_pin = pinSet.Item1 || pinSet.Item2;
2019-05-16 23:30:07 +02:00
_fingerprint = await _lockService.IsFingerprintLockSetAsync();
2019-05-16 20:55:18 +02:00
BuildList();
}
2019-05-14 17:53:41 +02:00
2019-05-15 15:14:49 +02:00
public async Task AboutAsync()
{
2019-05-31 03:25:54 +02:00
var debugText = string.Format("{0}: {1} ({2})", AppResources.Version,
_platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber());
2019-05-15 15:14:49 +02:00
var text = string.Format("© 8bit Solutions LLC 2015-{0}\n\n{1}", DateTime.Now.Year, debugText);
var copy = await _platformUtilsService.ShowDialogAsync(text, AppResources.Bitwarden, AppResources.Copy,
AppResources.Close);
if(copy)
{
await _platformUtilsService.CopyToClipboardAsync(debugText);
}
}
2019-05-15 18:54:48 +02:00
public void Help()
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/");
}
public async Task FingerprintAsync()
{
var fingerprint = await _cryptoService.GetFingerprintAsync(await _userService.GetUserIdAsync());
var phrase = string.Join("-", fingerprint);
2019-05-15 18:55:52 +02:00
var text = string.Format("{0}:\n\n{1}", AppResources.YourAccountsFingerprint, phrase);
2019-05-15 18:54:48 +02:00
var learnMore = await _platformUtilsService.ShowDialogAsync(text, AppResources.FingerprintPhrase,
AppResources.LearnMore, AppResources.Close);
if(learnMore)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/fingerprint-phrase/");
}
}
2019-05-15 19:09:49 +02:00
public void Rate()
{
_deviceActionService.RateApp();
}
2019-05-15 18:54:48 +02:00
2019-05-15 19:26:55 +02:00
public void Import()
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/import-data/");
}
public void Export()
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/export-your-data/");
}
public void WebVault()
{
var url = _environmentService.GetWebVaultUrl();
if(url == null)
{
url = "https://vault.bitwarden.com";
}
_platformUtilsService.LaunchUri(url);
}
public async Task ShareAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.ShareVaultConfirmation,
AppResources.ShareVault, AppResources.Yes, AppResources.Cancel);
if(confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/what-is-an-organization/");
}
}
public async Task TwoStepAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.TwoStepLoginConfirmation,
AppResources.TwoStepLogin, AppResources.Yes, AppResources.Cancel);
if(confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/setup-two-step-login/");
}
}
public async Task ChangePasswordAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.ChangePasswordConfirmation,
AppResources.ChangeMasterPassword, AppResources.Yes, AppResources.Cancel);
if(confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/change-your-master-password/");
}
}
public async Task LogOutAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation,
AppResources.LogOut, AppResources.Yes, AppResources.Cancel);
if(confirmed)
{
_messagingService.Send("logout");
}
}
2019-05-15 21:47:50 +02:00
public async Task LockAsync()
{
await _lockService.LockAsync(true, true);
2019-05-15 21:47:50 +02:00
}
2019-05-16 20:55:18 +02:00
public async Task LockOptionsAsync()
{
var options = _lockOptions.Select(o => o.Key == _lockOptionValue ? $"✓ {o.Key}" : o.Key).ToArray();
var selection = await Page.DisplayActionSheet(AppResources.LockOptions, AppResources.Cancel, null, options);
2019-05-31 00:33:18 +02:00
if(selection == null || selection == AppResources.Cancel)
2019-05-16 20:55:18 +02:00
{
return;
}
var cleanSelection = selection.Replace("✓ ", string.Empty);
var selectionOption = _lockOptions.FirstOrDefault(o => o.Key == cleanSelection);
_lockOptionValue = selectionOption.Key;
2019-05-16 22:00:16 +02:00
await _lockService.SetLockOptionAsync(selectionOption.Value);
2019-05-16 20:55:18 +02:00
BuildList();
}
2019-05-16 21:54:21 +02:00
public async Task UpdatePinAsync()
{
_pin = !_pin;
if(_pin)
{
var pin = await _deviceActionService.DisplayPromptAync(AppResources.EnterPIN,
AppResources.SetPINDescription, null, AppResources.Submit, AppResources.Cancel, true);
if(!string.IsNullOrWhiteSpace(pin))
{
var masterPassOnRestart = await _platformUtilsService.ShowDialogAsync(
AppResources.PINRequireMasterPasswordRestart, AppResources.UnlockWithPIN,
AppResources.Yes, AppResources.No);
2019-05-16 21:54:21 +02:00
if(masterPassOnRestart)
{
var encPin = await _cryptoService.EncryptAsync(pin);
await _storageService.SaveAsync(Constants.ProtectedPin, encPin.EncryptedString);
}
else
{
var kdf = await _userService.GetKdfAsync();
var kdfIterations = await _userService.GetKdfIterationsAsync();
var email = await _userService.GetEmailAsync();
var pinKey = await _cryptoService.MakePinKeyAysnc(pin, email,
kdf.GetValueOrDefault(Core.Enums.KdfType.PBKDF2_SHA256),
kdfIterations.GetValueOrDefault(5000));
var key = await _cryptoService.GetKeyAsync();
var pinProtectedKey = await _cryptoService.EncryptAsync(key.Key, pinKey);
await _storageService.SaveAsync(Constants.PinProtectedKey, pinProtectedKey.EncryptedString);
}
}
else
{
_pin = false;
}
}
if(!_pin)
{
await _storageService.RemoveAsync(Constants.PinProtectedKey);
await _storageService.RemoveAsync(Constants.ProtectedPin);
}
2019-05-16 23:30:07 +02:00
BuildList();
}
2019-05-16 22:31:58 +02:00
2019-05-16 23:30:07 +02:00
public async Task UpdateFingerprintAsync()
{
2019-05-31 04:50:58 +02:00
var current = _fingerprint;
if(_fingerprint)
{
_fingerprint = false;
}
else if(await _platformUtilsService.SupportsFingerprintAsync())
{
_fingerprint = await _platformUtilsService.AuthenticateFingerprintAsync();
}
if(_fingerprint == current)
{
return;
}
2019-05-16 23:30:07 +02:00
if(_fingerprint)
{
await _storageService.SaveAsync(Constants.FingerprintUnlockKey, true);
}
else
{
await _storageService.RemoveAsync(Constants.FingerprintUnlockKey);
}
await _cryptoService.ToggleKeyAsync();
2019-05-16 21:54:21 +02:00
BuildList();
}
2019-05-14 17:53:41 +02:00
private void BuildList()
{
var doUpper = Device.RuntimePlatform != Device.Android;
2019-05-31 04:45:48 +02:00
var autofillItems = new List<SettingsPageListItem>();
if(Device.RuntimePlatform == Device.Android)
{
if(_deviceActionService.SupportsAutofillService())
{
autofillItems.Add(new SettingsPageListItem
{
Name = AppResources.AutofillService,
2019-06-03 17:26:16 +02:00
SubLabel = _deviceActionService.AutofillServiceEnabled() ?
AppResources.Enabled : AppResources.Disabled
2019-05-31 04:45:48 +02:00
});
}
autofillItems.Add(new SettingsPageListItem
{
Name = AppResources.AutofillAccessibilityService,
2019-06-03 17:26:16 +02:00
SubLabel = _deviceActionService.AutofillAccessibilityServiceRunning() ?
AppResources.Enabled : AppResources.Disabled
2019-05-31 04:45:48 +02:00
});
}
else
{
if(_deviceActionService.SystemMajorVersion() >= 12)
{
autofillItems.Add(new SettingsPageListItem { Name = AppResources.PasswordAutofill });
}
autofillItems.Add(new SettingsPageListItem { Name = AppResources.AppExtension });
}
2019-05-14 17:53:41 +02:00
var manageItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.Folders },
2019-05-16 20:55:18 +02:00
new SettingsPageListItem { Name = AppResources.Sync, SubLabel = _lastSyncDate }
2019-05-14 17:53:41 +02:00
};
var securityItems = new List<SettingsPageListItem>
{
2019-05-16 20:55:18 +02:00
new SettingsPageListItem { Name = AppResources.LockOptions, SubLabel = _lockOptionValue },
2019-06-03 17:26:16 +02:00
new SettingsPageListItem
{
Name = AppResources.UnlockWithPIN,
SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled
},
2019-05-15 19:35:17 +02:00
new SettingsPageListItem { Name = AppResources.LockNow },
2019-05-14 17:53:41 +02:00
new SettingsPageListItem { Name = AppResources.TwoStepLogin }
};
2019-05-16 22:31:58 +02:00
if(_supportsFingerprint)
{
var item = new SettingsPageListItem
{
Name = string.Format(AppResources.UnlockWith, _fingerprintName),
2019-06-03 17:26:16 +02:00
SubLabel = _fingerprint ? AppResources.Enabled : AppResources.Disabled
2019-05-16 22:31:58 +02:00
};
securityItems.Insert(1, item);
}
2019-05-14 17:53:41 +02:00
var accountItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.ChangeMasterPassword },
2019-05-15 18:54:48 +02:00
new SettingsPageListItem { Name = AppResources.FingerprintPhrase },
2019-05-14 17:53:41 +02:00
new SettingsPageListItem { Name = AppResources.LogOut }
};
2019-05-15 19:26:55 +02:00
var toolsItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.ImportItems },
new SettingsPageListItem { Name = AppResources.ExportVault },
new SettingsPageListItem { Name = AppResources.ShareVault },
new SettingsPageListItem { Name = AppResources.WebVault }
};
2019-05-14 17:53:41 +02:00
var otherItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.Options },
new SettingsPageListItem { Name = AppResources.About },
new SettingsPageListItem { Name = AppResources.HelpAndFeedback },
new SettingsPageListItem { Name = AppResources.RateTheApp }
};
2019-05-16 20:55:18 +02:00
GroupedItems.ResetWithRange(new List<SettingsPageListGroup>
2019-05-14 17:53:41 +02:00
{
new SettingsPageListGroup(autofillItems, AppResources.Autofill, doUpper, true),
2019-05-14 17:53:41 +02:00
new SettingsPageListGroup(manageItems, AppResources.Manage, doUpper),
new SettingsPageListGroup(securityItems, AppResources.Security, doUpper),
new SettingsPageListGroup(accountItems, AppResources.Account, doUpper),
2019-05-15 19:26:55 +02:00
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
2019-05-14 17:53:41 +02:00
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
2019-05-16 20:55:18 +02:00
});
2019-05-14 17:53:41 +02:00
}
2019-03-29 04:52:33 +01:00
}
}