2020-02-14 22:10:58 +01:00
|
|
|
|
using System;
|
|
|
|
|
using Bit.App.Abstractions;
|
|
|
|
|
using Bit.App.Resources;
|
|
|
|
|
using Bit.Core.Abstractions;
|
|
|
|
|
using Bit.Core.Utilities;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
2021-09-23 18:30:20 +02:00
|
|
|
|
using Bit.Core.Enums;
|
2021-11-19 15:44:01 +01:00
|
|
|
|
using Bit.Core.Exceptions;
|
2022-01-21 10:31:03 +01:00
|
|
|
|
using Bit.Core;
|
2020-04-02 16:30:21 +02:00
|
|
|
|
#if !FDROID
|
|
|
|
|
using Microsoft.AppCenter.Crashes;
|
|
|
|
|
#endif
|
2020-02-14 22:10:58 +01:00
|
|
|
|
using Xamarin.Forms;
|
|
|
|
|
|
|
|
|
|
namespace Bit.App.Pages
|
|
|
|
|
{
|
|
|
|
|
public class ExportVaultPageViewModel : BaseViewModel
|
|
|
|
|
{
|
|
|
|
|
private readonly IDeviceActionService _deviceActionService;
|
|
|
|
|
private readonly IPlatformUtilsService _platformUtilsService;
|
|
|
|
|
private readonly II18nService _i18nService;
|
|
|
|
|
private readonly IExportService _exportService;
|
2021-09-23 18:30:20 +02:00
|
|
|
|
private readonly IPolicyService _policyService;
|
2021-11-11 02:46:48 +01:00
|
|
|
|
private readonly IKeyConnectorService _keyConnectorService;
|
|
|
|
|
private readonly IUserVerificationService _userVerificationService;
|
|
|
|
|
private readonly IApiService _apiService;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
|
|
|
|
private int _fileFormatSelectedIndex;
|
2020-12-14 18:56:13 +01:00
|
|
|
|
private string _exportWarningMessage;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
private bool _showPassword;
|
2021-11-11 02:46:48 +01:00
|
|
|
|
private string _secret;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
private byte[] _exportResult;
|
|
|
|
|
private string _defaultFilename;
|
2020-12-14 18:56:13 +01:00
|
|
|
|
private bool _initialized = false;
|
2021-11-11 02:46:48 +01:00
|
|
|
|
private bool _useOTPVerification = false;
|
|
|
|
|
private string _secretName;
|
|
|
|
|
private string _instructionText;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
|
|
|
|
public ExportVaultPageViewModel()
|
|
|
|
|
{
|
|
|
|
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
|
|
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
|
|
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
|
|
|
|
_exportService = ServiceContainer.Resolve<IExportService>("exportService");
|
2021-09-23 18:30:20 +02:00
|
|
|
|
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
2021-11-11 02:46:48 +01:00
|
|
|
|
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
|
|
|
|
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>("userVerificationService");
|
|
|
|
|
_apiService = ServiceContainer.Resolve<IApiService>("apiService");
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
|
|
|
|
PageTitle = AppResources.ExportVault;
|
|
|
|
|
TogglePasswordCommand = new Command(TogglePassword);
|
|
|
|
|
ExportVaultCommand = new Command(async () => await ExportVaultAsync());
|
|
|
|
|
|
|
|
|
|
FileFormatOptions = new List<KeyValuePair<string, string>>
|
|
|
|
|
{
|
|
|
|
|
new KeyValuePair<string, string>("json", ".json"),
|
2020-12-14 18:56:13 +01:00
|
|
|
|
new KeyValuePair<string, string>("csv", ".csv"),
|
|
|
|
|
new KeyValuePair<string, string>("encrypted_json", ".json (Encrypted)")
|
2020-02-14 22:10:58 +01:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task InitAsync()
|
|
|
|
|
{
|
2020-12-14 18:56:13 +01:00
|
|
|
|
_initialized = true;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
FileFormatSelectedIndex = FileFormatOptions.FindIndex(k => k.Key == "json");
|
2021-09-23 18:30:20 +02:00
|
|
|
|
DisablePrivateVaultPolicyEnabled = await _policyService.PolicyAppliesToUser(PolicyType.DisablePersonalVaultExport);
|
2021-11-11 02:46:48 +01:00
|
|
|
|
UseOTPVerification = await _keyConnectorService.GetUsesKeyConnector();
|
2021-09-23 18:30:20 +02:00
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
if (UseOTPVerification)
|
|
|
|
|
{
|
|
|
|
|
InstructionText = _i18nService.T("ExportVaultOTPDescription");
|
|
|
|
|
SecretName = _i18nService.T("VerificationCode");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
InstructionText = _i18nService.T("ExportVaultMasterPasswordDescription");
|
|
|
|
|
SecretName = _i18nService.T("MasterPassword");
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 18:56:13 +01:00
|
|
|
|
UpdateWarning();
|
2020-02-14 22:10:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<KeyValuePair<string, string>> FileFormatOptions { get; set; }
|
2021-09-23 18:30:20 +02:00
|
|
|
|
private bool _disabledPrivateVaultPolicyEnabled = false;
|
|
|
|
|
|
|
|
|
|
public bool DisablePrivateVaultPolicyEnabled
|
|
|
|
|
{
|
|
|
|
|
get => _disabledPrivateVaultPolicyEnabled;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
SetProperty(ref _disabledPrivateVaultPolicyEnabled, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
|
|
|
|
public int FileFormatSelectedIndex
|
|
|
|
|
{
|
|
|
|
|
get => _fileFormatSelectedIndex;
|
|
|
|
|
set { SetProperty(ref _fileFormatSelectedIndex, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 18:56:13 +01:00
|
|
|
|
public string ExportWarningMessage
|
|
|
|
|
{
|
|
|
|
|
get => _exportWarningMessage;
|
|
|
|
|
set { SetProperty(ref _exportWarningMessage, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 22:10:58 +01:00
|
|
|
|
public bool ShowPassword
|
|
|
|
|
{
|
|
|
|
|
get => _showPassword;
|
|
|
|
|
set => SetProperty(ref _showPassword, value,
|
|
|
|
|
additionalPropertyNames: new string[] {nameof(ShowPasswordIcon)});
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
public bool UseOTPVerification
|
|
|
|
|
{
|
|
|
|
|
get => _useOTPVerification;
|
|
|
|
|
set => SetProperty(ref _useOTPVerification, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Secret
|
2020-02-14 22:10:58 +01:00
|
|
|
|
{
|
2021-11-11 02:46:48 +01:00
|
|
|
|
get => _secret;
|
|
|
|
|
set => SetProperty(ref _secret, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string SecretName
|
|
|
|
|
{
|
|
|
|
|
get => _secretName;
|
|
|
|
|
set => SetProperty(ref _secretName, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string InstructionText
|
|
|
|
|
{
|
|
|
|
|
get => _instructionText;
|
|
|
|
|
set => SetProperty(ref _instructionText, value);
|
2020-02-14 22:10:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Command TogglePasswordCommand { get; }
|
|
|
|
|
|
2022-01-21 10:31:03 +01:00
|
|
|
|
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
|
|
|
|
public void TogglePassword()
|
|
|
|
|
{
|
|
|
|
|
ShowPassword = !ShowPassword;
|
2021-11-11 02:46:48 +01:00
|
|
|
|
(Page as ExportVaultPage).SecretEntry.Focus();
|
2020-02-14 22:10:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Command ExportVaultCommand { get; }
|
|
|
|
|
|
|
|
|
|
public async Task ExportVaultAsync()
|
|
|
|
|
{
|
2021-11-11 02:46:48 +01:00
|
|
|
|
bool userConfirmedExport = await _platformUtilsService.ShowDialogAsync(ExportWarningMessage,
|
|
|
|
|
_i18nService.T("ExportVaultConfirmationTitle"), _i18nService.T("ExportVault"), _i18nService.T("Cancel"));
|
2020-02-14 22:10:58 +01:00
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
if (!userConfirmedExport)
|
2020-02-14 22:10:58 +01:00
|
|
|
|
{
|
2020-12-18 23:47:34 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
var verificationType = await _keyConnectorService.GetUsesKeyConnector()
|
|
|
|
|
? VerificationType.OTP
|
|
|
|
|
: VerificationType.MasterPassword;
|
|
|
|
|
if (!await _userVerificationService.VerifyUser(Secret, verificationType))
|
2020-12-18 23:47:34 +01:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
Secret = string.Empty;
|
|
|
|
|
|
2020-12-18 23:47:34 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var data = await _exportService.GetExport(FileFormatOptions[FileFormatSelectedIndex].Key);
|
|
|
|
|
var fileFormat = FileFormatOptions[FileFormatSelectedIndex].Key;
|
2020-12-31 17:58:58 +01:00
|
|
|
|
fileFormat = fileFormat == "encrypted_json" ? "json" : fileFormat;
|
|
|
|
|
|
2020-12-18 23:47:34 +01:00
|
|
|
|
_defaultFilename = _exportService.GetFileName(null, fileFormat);
|
2021-05-17 18:40:20 +02:00
|
|
|
|
_exportResult = Encoding.UTF8.GetBytes(data);
|
2020-12-18 23:47:34 +01:00
|
|
|
|
|
|
|
|
|
if (!_deviceActionService.SaveFile(_exportResult, null, _defaultFilename, null))
|
2020-02-14 22:10:58 +01:00
|
|
|
|
{
|
|
|
|
|
ClearResult();
|
2020-03-13 16:02:49 +01:00
|
|
|
|
await _platformUtilsService.ShowDialogAsync(_i18nService.T("ExportVaultFailure"));
|
2020-02-14 22:10:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-18 23:47:34 +01:00
|
|
|
|
catch (Exception ex)
|
2020-02-14 22:10:58 +01:00
|
|
|
|
{
|
2020-12-18 23:47:34 +01:00
|
|
|
|
ClearResult();
|
|
|
|
|
await _platformUtilsService.ShowDialogAsync(_i18nService.T("ExportVaultFailure"));
|
|
|
|
|
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", ex.GetType(), ex.StackTrace);
|
|
|
|
|
#if !FDROID
|
|
|
|
|
Crashes.TrackError(ex);
|
|
|
|
|
#endif
|
2020-02-14 22:10:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
public async Task RequestOTP()
|
|
|
|
|
{
|
2021-11-19 15:44:01 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await _deviceActionService.ShowLoadingAsync(AppResources.Sending);
|
|
|
|
|
await _apiService.PostAccountRequestOTP();
|
|
|
|
|
await _deviceActionService.HideLoadingAsync();
|
|
|
|
|
_platformUtilsService.ShowToast("success", null, AppResources.CodeSent);
|
|
|
|
|
}
|
|
|
|
|
catch (ApiException e)
|
|
|
|
|
{
|
|
|
|
|
await _deviceActionService.HideLoadingAsync();
|
|
|
|
|
if (e?.Error != null)
|
|
|
|
|
{
|
|
|
|
|
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
|
|
|
|
|
AppResources.AnErrorHasOccurred);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 02:46:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 22:10:58 +01:00
|
|
|
|
public async void SaveFileSelected(string contentUri, string filename)
|
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (_deviceActionService.SaveFile(_exportResult, null, filename ?? _defaultFilename, contentUri))
|
2020-02-14 22:10:58 +01:00
|
|
|
|
{
|
|
|
|
|
ClearResult();
|
|
|
|
|
_platformUtilsService.ShowToast("success", null, _i18nService.T("ExportVaultSuccess"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClearResult();
|
|
|
|
|
await _platformUtilsService.ShowDialogAsync(_i18nService.T("ExportVaultFailure"));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 18:56:13 +01:00
|
|
|
|
public void UpdateWarning()
|
|
|
|
|
{
|
|
|
|
|
if (!_initialized)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (FileFormatOptions[FileFormatSelectedIndex].Key)
|
|
|
|
|
{
|
|
|
|
|
case "encrypted_json":
|
2021-03-05 00:33:29 +01:00
|
|
|
|
ExportWarningMessage = _i18nService.T("EncExportKeyWarning") +
|
|
|
|
|
"\n\n" +
|
|
|
|
|
_i18nService.T("EncExportAccountWarning");
|
2020-12-14 18:56:13 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ExportWarningMessage = _i18nService.T("ExportVaultWarning");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 22:10:58 +01:00
|
|
|
|
private void ClearResult()
|
|
|
|
|
{
|
|
|
|
|
_defaultFilename = null;
|
|
|
|
|
_exportResult = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|