background thread full/incremental sync operations. pool sqlconnection. sqlconnection to FullMutex mode for multithread environment. try/catch decryption errors.

This commit is contained in:
Kyle Spearrin 2016-07-06 22:33:50 -04:00
parent 0be15d7a34
commit 29c7a0ccf0
4 changed files with 104 additions and 71 deletions

View file

@ -1,22 +1,29 @@
using System; using System;
using System.IO; using System.IO;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using SQLite;
namespace Bit.Android.Services namespace Bit.Android.Services
{ {
public class SqlService : ISqlService public class SqlService : ISqlService
{ {
public SQLite.SQLiteConnection GetConnection() private SQLiteConnection _connection;
public SQLiteConnection GetConnection()
{ {
if(_connection != null)
{
return _connection;
}
var sqliteFilename = "bitwarden.db3"; var sqliteFilename = "bitwarden.db3";
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename); var path = Path.Combine(documentsPath, sqliteFilename);
Console.WriteLine(path); Console.WriteLine(path);
var conn = new SQLite.SQLiteConnection(path);
// Return the database connection _connection = new SQLiteConnection(path,
return conn; SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex | SQLiteOpenFlags.SharedCache);
return _connection;
} }
} }
} }

View file

@ -57,35 +57,7 @@ namespace Bit.App
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) => MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
{ {
await CheckLockAsync(args); await CheckLockAsync(args);
if(_connectivity.IsConnected) await Task.Run(() => IncrementalSyncAsync()).ConfigureAwait(false);
{
var attempt = 0;
do
{
try
{
await _syncService.IncrementalSyncAsync();
break;
}
catch(WebException)
{
Debug.WriteLine("Failed to sync.");
if(attempt >= 1)
{
await _userDialogs.AlertAsync("Unable to automatically sync.");
}
else
{
await Task.Delay(1000);
}
attempt++;
}
} while(attempt <= 1);
}
else
{
Debug.WriteLine("Not connected.");
}
}); });
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", async (sender, args) => MessagingCenter.Subscribe<Application, bool>(Current, "Lock", async (sender, args) =>
@ -99,30 +71,7 @@ namespace Bit.App
// Handle when your app starts // Handle when your app starts
await CheckLockAsync(false); await CheckLockAsync(false);
_databaseService.CreateTables(); _databaseService.CreateTables();
if(_connectivity.IsConnected) await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
{
var attempt = 0;
do
{
try
{
await _syncService.FullSyncAsync();
break;
}
catch(WebException)
{
if(attempt >= 1)
{
await _userDialogs.AlertAsync("Unable to automatically sync. Manual sync required.");
}
else
{
await Task.Delay(1000);
}
attempt++;
}
} while(attempt <= 1);
}
Debug.WriteLine("OnStart"); Debug.WriteLine("OnStart");
} }
@ -155,6 +104,68 @@ namespace Bit.App
} }
} }
private async Task IncrementalSyncAsync()
{
if(_connectivity.IsConnected)
{
var attempt = 0;
do
{
try
{
await _syncService.IncrementalSyncAsync();
break;
}
catch(WebException)
{
Debug.WriteLine("Failed to incremental sync.");
if(attempt >= 1)
{
break;
}
else
{
await Task.Delay(1000);
}
attempt++;
}
} while(attempt <= 1);
}
else
{
Debug.WriteLine("Not connected.");
}
}
private async Task FullSyncAsync()
{
if(_connectivity.IsConnected)
{
var attempt = 0;
do
{
try
{
await _syncService.FullSyncAsync();
break;
}
catch(WebException)
{
Debug.WriteLine("Failed to full sync.");
if(attempt >= 1)
{
break;
}
else
{
await Task.Delay(1000);
}
attempt++;
}
} while(attempt <= 1);
}
}
private async Task CheckLockAsync(bool forceLock) private async Task CheckLockAsync(bool forceLock)
{ {
// Only lock if they are logged in // Only lock if they are logged in

View file

@ -1,7 +1,9 @@
using System; using System;
using System.Diagnostics;
using System.Text; using System.Text;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models; using Bit.App.Models;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Generators;
@ -113,14 +115,20 @@ namespace Bit.App.Services
throw new ArgumentNullException(nameof(encyptedValue)); throw new ArgumentNullException(nameof(encyptedValue));
} }
var keyParamWithIV = new ParametersWithIV(_keyParameter, encyptedValue.InitializationVectorBytes, 0, InitializationVectorSize); try
{
_cipher.Init(false, keyParamWithIV); var keyParamWithIV = new ParametersWithIV(_keyParameter, encyptedValue.InitializationVectorBytes, 0, InitializationVectorSize);
byte[] comparisonBytes = new byte[_cipher.GetOutputSize(encyptedValue.CipherTextBytes.Length)]; _cipher.Init(false, keyParamWithIV);
var length = _cipher.ProcessBytes(encyptedValue.CipherTextBytes, comparisonBytes, 0); byte[] comparisonBytes = new byte[_cipher.GetOutputSize(encyptedValue.CipherTextBytes.Length)];
_cipher.DoFinal(comparisonBytes, length); var length = _cipher.ProcessBytes(encyptedValue.CipherTextBytes, comparisonBytes, 0);
_cipher.DoFinal(comparisonBytes, length);
return Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length).TrimEnd('\0'); return Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length).TrimEnd('\0');
}
catch(Exception e)
{
Debug.WriteLine("Could not decrypt '{0}'. {1}", encyptedValue, e.Message);
return "[error: cannot decrypt]";
}
} }
public byte[] MakeKeyFromPassword(string password, string salt) public byte[] MakeKeyFromPassword(string password, string salt)

View file

@ -2,24 +2,31 @@
using System.IO; using System.IO;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Foundation; using Foundation;
using SQLite;
namespace Bit.iOS.Core.Services namespace Bit.iOS.Core.Services
{ {
public class SqlService : ISqlService public class SqlService : ISqlService
{ {
public SQLite.SQLiteConnection GetConnection() private SQLiteConnection _connection;
public SQLiteConnection GetConnection()
{ {
if(_connection != null)
{
return _connection;
}
var sqliteFilename = "bitwarden.db3"; var sqliteFilename = "bitwarden.db3";
var fileManager = new NSFileManager(); var fileManager = new NSFileManager();
var appGroupContainer = fileManager.GetContainerUrl("group.com.8bit.bitwarden"); var appGroupContainer = fileManager.GetContainerUrl("group.com.8bit.bitwarden");
var libraryPath = Path.Combine(appGroupContainer.Path, "Library"); // Library folder var libraryPath = Path.Combine(appGroupContainer.Path, "Library"); // Library folder
var path = Path.Combine(libraryPath, sqliteFilename); var path = Path.Combine(libraryPath, sqliteFilename);
Console.WriteLine(path); Console.WriteLine(path);
var conn = new SQLite.SQLiteConnection(path);
// Return the database connection _connection = new SQLiteConnection(path,
return conn; SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex | SQLiteOpenFlags.SharedCache);
return _connection;
} }
} }
} }