mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
start some migration work for auth data
This commit is contained in:
parent
b191542ab7
commit
6aef106482
6 changed files with 113 additions and 9 deletions
|
@ -43,10 +43,12 @@ namespace Bit.Droid
|
||||||
|
|
||||||
private void RegisterLocalServices()
|
private void RegisterLocalServices()
|
||||||
{
|
{
|
||||||
var settingsShim = new App.Migration.SettingsShim();
|
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
|
||||||
ServiceContainer.Register("settingsShim", settingsShim);
|
if(App.Migration.MigrationHelpers.NeedsMigration())
|
||||||
App.Utilities.AppHelpers.NeedsMigration =
|
{
|
||||||
settingsShim.GetValueOrDefault(Constants.OldLastActivityKey, DateTime.MinValue) > DateTime.MinValue;
|
ServiceContainer.Register<App.Migration.Abstractions.IOldSecureStorageService>(
|
||||||
|
"oldSecureStorageService", new Migration.AndroidKeyStoreStorageService());
|
||||||
|
}
|
||||||
|
|
||||||
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
|
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
|
||||||
// Note: This might cause a race condition. Investigate more.
|
// Note: This might cause a race condition. Investigate more.
|
||||||
|
|
|
@ -13,10 +13,11 @@ using Javax.Crypto.Spec;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
using Bit.App.Migration;
|
using Bit.App.Migration;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.App.Migration.Abstractions;
|
||||||
|
|
||||||
namespace Bit.Droid.Migration
|
namespace Bit.Droid.Migration
|
||||||
{
|
{
|
||||||
public class AndroidKeyStoreStorageService
|
public class AndroidKeyStoreStorageService : IOldSecureStorageService
|
||||||
{
|
{
|
||||||
private const string AndroidKeyStore = "AndroidKeyStore";
|
private const string AndroidKeyStore = "AndroidKeyStore";
|
||||||
private const string AesMode = "AES/GCM/NoPadding";
|
private const string AesMode = "AES/GCM/NoPadding";
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace Bit.App
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
private readonly IPlatformUtilsService _platformUtilsService;
|
||||||
private readonly IAuthService _authService;
|
private readonly IAuthService _authService;
|
||||||
private readonly IStorageService _storageService;
|
private readonly IStorageService _storageService;
|
||||||
|
private readonly IStorageService _secureStorageService;
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private readonly AppOptions _appOptions;
|
private readonly AppOptions _appOptions;
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ namespace Bit.App
|
||||||
_authService = ServiceContainer.Resolve<IAuthService>("authService");
|
_authService = ServiceContainer.Resolve<IAuthService>("authService");
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
|
||||||
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
|
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
|
||||||
"passwordGenerationService");
|
"passwordGenerationService");
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
|
||||||
|
@ -100,7 +102,8 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
else if(message.Command == "loggedOut")
|
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")
|
else if(message.Command == "unlocked" || message.Command == "loggedIn")
|
||||||
{
|
{
|
||||||
|
|
10
src/App/Migration/Abstractions/IOldSecureStorageService.cs
Normal file
10
src/App/Migration/Abstractions/IOldSecureStorageService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
90
src/App/Migration/MigrationHelpers.cs
Normal file
90
src/App/Migration/MigrationHelpers.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,6 @@ namespace Bit.App.Utilities
|
||||||
{
|
{
|
||||||
public static class AppHelpers
|
public static class AppHelpers
|
||||||
{
|
{
|
||||||
public static bool NeedsMigration = false;
|
|
||||||
|
|
||||||
public static async Task<string> CipherListOptions(ContentPage page, CipherView cipher)
|
public static async Task<string> CipherListOptions(ContentPage page, CipherView cipher)
|
||||||
{
|
{
|
||||||
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
@ -118,7 +116,7 @@ namespace Bit.App.Utilities
|
||||||
{
|
{
|
||||||
var currentBuild = deviceActionService.GetBuildNumber();
|
var currentBuild = deviceActionService.GetBuildNumber();
|
||||||
var lastBuild = await storageService.GetAsync<string>(Constants.LastBuildKey);
|
var lastBuild = await storageService.GetAsync<string>(Constants.LastBuildKey);
|
||||||
if(!NeedsMigration)
|
if(!Migration.MigrationHelpers.NeedsMigration())
|
||||||
{
|
{
|
||||||
if(lastBuild == null)
|
if(lastBuild == null)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue