start some migration work for auth data

This commit is contained in:
Kyle Spearrin 2019-05-31 17:49:51 -04:00
parent b191542ab7
commit 6aef106482
6 changed files with 113 additions and 9 deletions

View file

@ -43,10 +43,12 @@ namespace Bit.Droid
private void RegisterLocalServices()
{
var settingsShim = new App.Migration.SettingsShim();
ServiceContainer.Register("settingsShim", settingsShim);
App.Utilities.AppHelpers.NeedsMigration =
settingsShim.GetValueOrDefault(Constants.OldLastActivityKey, DateTime.MinValue) > DateTime.MinValue;
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
if(App.Migration.MigrationHelpers.NeedsMigration())
{
ServiceContainer.Register<App.Migration.Abstractions.IOldSecureStorageService>(
"oldSecureStorageService", new Migration.AndroidKeyStoreStorageService());
}
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
// Note: This might cause a race condition. Investigate more.

View file

@ -13,10 +13,11 @@ using Javax.Crypto.Spec;
using Android.Preferences;
using Bit.App.Migration;
using Bit.Core.Utilities;
using Bit.App.Migration.Abstractions;
namespace Bit.Droid.Migration
{
public class AndroidKeyStoreStorageService
public class AndroidKeyStoreStorageService : IOldSecureStorageService
{
private const string AndroidKeyStore = "AndroidKeyStore";
private const string AesMode = "AES/GCM/NoPadding";

View file

@ -35,6 +35,7 @@ namespace Bit.App
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IAuthService _authService;
private readonly IStorageService _storageService;
private readonly IStorageService _secureStorageService;
private readonly IDeviceActionService _deviceActionService;
private readonly AppOptions _appOptions;
@ -57,6 +58,7 @@ namespace Bit.App
_authService = ServiceContainer.Resolve<IAuthService>("authService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
"passwordGenerationService");
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
@ -100,7 +102,8 @@ namespace Bit.App
}
else if(message.Command == "loggedOut")
{
// TODO
// Clean up old migrated key if they ever log out.
await _secureStorageService.RemoveAsync("oldKey");
}
else if(message.Command == "unlocked" || message.Command == "loggedIn")
{

View file

@ -0,0 +1,10 @@
namespace Bit.App.Migration.Abstractions
{
public interface IOldSecureStorageService
{
bool Contains(string key);
void Delete(string key);
byte[] Retrieve(string key);
void Store(string key, byte[] dataBytes);
}
}

View file

@ -0,0 +1,90 @@
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using System;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Migration
{
public static class MigrationHelpers
{
public static bool NeedsMigration()
{
return ServiceContainer.Resolve<SettingsShim>("settingsShim")
.GetValueOrDefault(Constants.OldLastActivityKey, DateTime.MinValue) > DateTime.MinValue;
}
public static async Task<bool> PerformMigrationAsync()
{
if(!NeedsMigration())
{
return false;
}
var settingsShim = ServiceContainer.Resolve<SettingsShim>("settingsShim");
var oldSecureStorageService = ServiceContainer.Resolve<Abstractions.IOldSecureStorageService>(
"oldSecureStorageService");
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
var secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
var cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
var tokenService = ServiceContainer.Resolve<ITokenService>("tokenService");
var userService = ServiceContainer.Resolve<IUserService>("userService");
// Get old data
var oldTokenBytes = oldSecureStorageService.Retrieve("accessToken");
var oldToken = oldTokenBytes == null ? null : Encoding.UTF8.GetString(
oldTokenBytes, 0, oldTokenBytes.Length);
var oldKeyBytes = oldSecureStorageService.Retrieve("key");
var oldKey = oldKeyBytes == null ? null : new Models.SymmetricCryptoKey(oldKeyBytes);
var oldUserId = settingsShim.GetValueOrDefault("userId", null);
var isAuthenticated = oldKey != null && !string.IsNullOrWhiteSpace(oldToken) &&
!string.IsNullOrWhiteSpace(oldUserId);
if(!isAuthenticated)
{
return false;
}
var oldRefreshTokenBytes = oldSecureStorageService.Retrieve("refreshToken");
var oldRefreshToken = oldRefreshTokenBytes == null ? null : Encoding.UTF8.GetString(
oldRefreshTokenBytes, 0, oldRefreshTokenBytes.Length);
var oldPinBytes = oldSecureStorageService.Retrieve("pin");
var oldPin = oldPinBytes == null ? null : Encoding.UTF8.GetString(
oldPinBytes, 0, oldPinBytes.Length);
var oldEncKey = settingsShim.GetValueOrDefault("encKey", null);
var oldEncPrivateKey = settingsShim.GetValueOrDefault("encPrivateKey", null);
var oldEmail = settingsShim.GetValueOrDefault("email", null);
var oldKdf = (KdfType)settingsShim.GetValueOrDefault("kdf", (int)KdfType.PBKDF2_SHA256);
var oldKdfIterations = settingsShim.GetValueOrDefault("kdfIterations", 5000);
var oldTwoFactorTokenBytes = oldSecureStorageService.Retrieve(
string.Format("twoFactorToken_{0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(oldEmail))));
var oldTwoFactorToken = oldTwoFactorTokenBytes == null ? null : Encoding.UTF8.GetString(
oldTwoFactorTokenBytes, 0, oldTwoFactorTokenBytes.Length);
// Save settings
// Save new authed data
await tokenService.SetTwoFactorTokenAsync(oldTwoFactorToken, oldEmail);
await tokenService.SetTokensAsync(oldToken, oldRefreshToken);
await userService.SetInformationAsync(oldUserId, oldEmail, oldKdf, oldKdfIterations);
var newKey = new Core.Models.Domain.SymmetricCryptoKey(oldKey.Key);
await cryptoService.SetKeyAsync(newKey);
// Key hash is unavailable in old version, store old key until we can move it to key hash
await secureStorageService.SaveAsync("oldKey", newKey.KeyB64);
await cryptoService.SetEncKeyAsync(oldEncKey);
await cryptoService.SetEncPrivateKeyAsync(oldEncPrivateKey);
return true;
}
}
}

View file

@ -13,8 +13,6 @@ namespace Bit.App.Utilities
{
public static class AppHelpers
{
public static bool NeedsMigration = false;
public static async Task<string> CipherListOptions(ContentPage page, CipherView cipher)
{
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
@ -118,7 +116,7 @@ namespace Bit.App.Utilities
{
var currentBuild = deviceActionService.GetBuildNumber();
var lastBuild = await storageService.GetAsync<string>(Constants.LastBuildKey);
if(!NeedsMigration)
if(!Migration.MigrationHelpers.NeedsMigration())
{
if(lastBuild == null)
{