mirror of
https://github.com/moparisthebest/keepass2android
synced 2025-02-17 23:40:23 -05:00
* Introduced IFileStorage interface: Better abstraction than current IOConnection (suitable for cloud support). Currently only implemented by the built-in IOConnection (local/http/ftp)
* Implemented Merge functionality for SaveDB. UI is not yet implemented! * Added tests for merge functionality
This commit is contained in:
parent
64e62cae70
commit
84aeb31fd0
@ -164,7 +164,6 @@ namespace KeePassLib.Native
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Kp2aLog.Log("4+1"+new Kp2atest.TestClass().Add1(4));
|
|
||||||
Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey key = new Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey();
|
Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey key = new Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey();
|
||||||
|
|
||||||
byte[] newKey = key.TransformMasterKey(pKey256, pBuf256, (int)uRounds);
|
byte[] newKey = key.TransformMasterKey(pKey256, pBuf256, (int)uRounds);
|
||||||
|
@ -562,22 +562,40 @@ namespace KeePassLib
|
|||||||
/// Open a database. The URL may point to any supported data source.
|
/// Open a database. The URL may point to any supported data source.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ioSource">IO connection to load the database from.</param>
|
/// <param name="ioSource">IO connection to load the database from.</param>
|
||||||
/// <param name="pwKey">Key used to open the specified database.</param>
|
/// s<param name="pwKey">Key used to open the specified database.</param>
|
||||||
/// <param name="slLogger">Logger, which gets all status messages.</param>
|
/// <param name="slLogger">Logger, which gets all status messages.</param>
|
||||||
public void Open(IOConnectionInfo ioSource, CompositeKey pwKey,
|
public void Open(IOConnectionInfo ioSource, CompositeKey pwKey,
|
||||||
IStatusLogger slLogger)
|
IStatusLogger slLogger)
|
||||||
{
|
{
|
||||||
Debug.Assert(ioSource != null);
|
Open(IOConnection.OpenRead(ioSource), UrlUtil.StripExtension(
|
||||||
if(ioSource == null) throw new ArgumentNullException("ioSource");
|
UrlUtil.GetFileName(ioSource.Path)), ioSource, pwKey, slLogger );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open a database. The URL may point to any supported data source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ioSource">IO connection to load the database from.</param>
|
||||||
|
/// <param name="pwKey">Key used to open the specified database.</param>
|
||||||
|
/// <param name="slLogger">Logger, which gets all status messages.</param>
|
||||||
|
public void Open(Stream s, string fileNameWithoutPathAndExt, IOConnectionInfo ioSource, CompositeKey pwKey,
|
||||||
|
IStatusLogger slLogger)
|
||||||
|
{
|
||||||
|
Debug.Assert(s != null);
|
||||||
|
if (s == null) throw new ArgumentNullException("s");
|
||||||
|
Debug.Assert(fileNameWithoutPathAndExt != null);
|
||||||
|
if (fileNameWithoutPathAndExt == null) throw new ArgumentException("fileNameWithoutPathAndExt");
|
||||||
Debug.Assert(pwKey != null);
|
Debug.Assert(pwKey != null);
|
||||||
if(pwKey == null) throw new ArgumentNullException("pwKey");
|
Debug.Assert(ioSource != null);
|
||||||
|
if (ioSource == null) throw new ArgumentNullException("ioSource");
|
||||||
|
|
||||||
|
if (pwKey == null) throw new ArgumentNullException("pwKey");
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_pgRootGroup = new PwGroup(true, true, UrlUtil.StripExtension(
|
m_pgRootGroup = new PwGroup(true, true, fileNameWithoutPathAndExt, PwIcon.FolderOpen);
|
||||||
UrlUtil.GetFileName(ioSource.Path)), PwIcon.FolderOpen);
|
|
||||||
m_pgRootGroup.IsExpanded = true;
|
m_pgRootGroup.IsExpanded = true;
|
||||||
|
|
||||||
m_pwUserKey = pwKey;
|
m_pwUserKey = pwKey;
|
||||||
@ -587,8 +605,8 @@ namespace KeePassLib
|
|||||||
KdbxFile kdbx = new KdbxFile(this);
|
KdbxFile kdbx = new KdbxFile(this);
|
||||||
kdbx.DetachBinaries = m_strDetachBins;
|
kdbx.DetachBinaries = m_strDetachBins;
|
||||||
|
|
||||||
Stream s = IOConnection.OpenRead(ioSource);
|
|
||||||
kdbx.Load(s, KdbxFormat.Default, slLogger);
|
kdbx.Load(s, KdbxFormat.Default, slLogger);
|
||||||
|
|
||||||
s.Close();
|
s.Close();
|
||||||
|
|
||||||
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
|
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
|
||||||
@ -598,13 +616,14 @@ namespace KeePassLib
|
|||||||
m_bDatabaseOpened = true;
|
m_bDatabaseOpened = true;
|
||||||
m_ioSource = ioSource;
|
m_ioSource = ioSource;
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save the currently opened database. The file is written to the location
|
/// Save the currently opened database. The file is written to the location
|
||||||
/// it has been opened from.
|
/// it has been opened from.
|
||||||
@ -626,7 +645,7 @@ namespace KeePassLib
|
|||||||
kdb.Save(s, null, KdbxFormat.Default, slLogger);
|
kdb.Save(s, null, KdbxFormat.Default, slLogger);
|
||||||
|
|
||||||
ft.CommitWrite();
|
ft.CommitWrite();
|
||||||
|
|
||||||
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
|
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
|
||||||
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
|
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
|
||||||
Debug.Assert(m_pbHashOfFileOnDisk != null);
|
Debug.Assert(m_pbHashOfFileOnDisk != null);
|
||||||
@ -636,6 +655,23 @@ namespace KeePassLib
|
|||||||
m_bModified = false;
|
m_bModified = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save the currently opened database. The file is written to the given stream which is expected to be the original location.
|
||||||
|
/// </summary>
|
||||||
|
/// This allows to save to cloud locations etc.
|
||||||
|
public void Save(Stream streamOfOriginalLocation, IStatusLogger slLogger)
|
||||||
|
{
|
||||||
|
Debug.Assert(ValidateUuidUniqueness());
|
||||||
|
Stream s = streamOfOriginalLocation;
|
||||||
|
KdbxFile kdb = new KdbxFile(this);
|
||||||
|
kdb.Save(s, null, KdbxFormat.Default, slLogger);
|
||||||
|
|
||||||
|
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
|
||||||
|
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
|
||||||
|
Debug.Assert(m_pbHashOfFileOnDisk != null);
|
||||||
|
m_bModified = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save the currently opened database to a different location. If
|
/// Save the currently opened database to a different location. If
|
||||||
/// <paramref name="bIsPrimaryNow" /> is <c>true</c>, the specified
|
/// <paramref name="bIsPrimaryNow" /> is <c>true</c>, the specified
|
||||||
|
@ -91,12 +91,18 @@ namespace KeePassLib.Serialization
|
|||||||
if((sDecrypted == null) || (sDecrypted == hashedStream))
|
if((sDecrypted == null) || (sDecrypted == hashedStream))
|
||||||
throw new SecurityException(KLRes.CryptoStreamFailed);
|
throw new SecurityException(KLRes.CryptoStreamFailed);
|
||||||
|
|
||||||
|
if (m_slLogger != null)
|
||||||
|
m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo);
|
||||||
|
|
||||||
brDecrypted = new BinaryReaderEx(sDecrypted, encNoBom, KLRes.FileCorrupted);
|
brDecrypted = new BinaryReaderEx(sDecrypted, encNoBom, KLRes.FileCorrupted);
|
||||||
byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32);
|
byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32);
|
||||||
|
|
||||||
if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32))
|
if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32))
|
||||||
throw new InvalidDataException();
|
throw new InvalidDataException();
|
||||||
|
|
||||||
|
if (m_slLogger != null)
|
||||||
|
m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo);
|
||||||
|
|
||||||
for(int iStart = 0; iStart < 32; ++iStart)
|
for(int iStart = 0; iStart < 32; ++iStart)
|
||||||
{
|
{
|
||||||
if(pbStoredStartBytes[iStart] != m_pbStreamStartBytes[iStart])
|
if(pbStoredStartBytes[iStart] != m_pbStreamStartBytes[iStart])
|
||||||
@ -126,7 +132,8 @@ namespace KeePassLib.Serialization
|
|||||||
m_pbProtectedStreamKey);
|
m_pbProtectedStreamKey);
|
||||||
}
|
}
|
||||||
else m_randomStream = null; // No random stream for plain-text files
|
else m_randomStream = null; // No random stream for plain-text files
|
||||||
|
if (m_slLogger != null)
|
||||||
|
m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo);
|
||||||
ReadXmlStreamed(readerStream, hashedStream);
|
ReadXmlStreamed(readerStream, hashedStream);
|
||||||
// ReadXmlDom(readerStream);
|
// ReadXmlDom(readerStream);
|
||||||
|
|
||||||
@ -312,7 +319,8 @@ namespace KeePassLib.Serialization
|
|||||||
if(m_pbMasterSeed.Length != 32)
|
if(m_pbMasterSeed.Length != 32)
|
||||||
throw new FormatException(KLRes.MasterSeedLengthInvalid);
|
throw new FormatException(KLRes.MasterSeedLengthInvalid);
|
||||||
ms.Write(m_pbMasterSeed, 0, 32);
|
ms.Write(m_pbMasterSeed, 0, 32);
|
||||||
|
if (m_slLogger != null)
|
||||||
|
m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo);
|
||||||
byte[] pKey32 = m_pwDatabase.MasterKey.GenerateKey32(m_pbTransformSeed,
|
byte[] pKey32 = m_pwDatabase.MasterKey.GenerateKey32(m_pbTransformSeed,
|
||||||
m_pwDatabase.KeyEncryptionRounds).ReadData();
|
m_pwDatabase.KeyEncryptionRounds).ReadData();
|
||||||
if((pKey32 == null) || (pKey32.Length != 32))
|
if((pKey32 == null) || (pKey32.Length != 32))
|
||||||
|
@ -2,6 +2,7 @@ using System;
|
|||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
|
using keepass2android.Io;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
@ -57,5 +58,7 @@ namespace keepass2android
|
|||||||
Handler UiThreadHandler { get; }
|
Handler UiThreadHandler { get; }
|
||||||
|
|
||||||
IProgressDialog CreateProgressDialog(Context ctx);
|
IProgressDialog CreateProgressDialog(Context ctx);
|
||||||
|
IFileStorage GetFileStorage(IOConnectionInfo iocInfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ namespace keepass2android
|
|||||||
public interface IProgressDialog
|
public interface IProgressDialog
|
||||||
{
|
{
|
||||||
void SetTitle(string title);
|
void SetTitle(string title);
|
||||||
void SetMessage(string getResourceString);
|
void SetMessage(string resourceString);
|
||||||
void Dismiss();
|
void Dismiss();
|
||||||
void Show();
|
void Show();
|
||||||
}
|
}
|
||||||
|
104
src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs
Normal file
104
src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
using KeePassLib.Utility;
|
||||||
|
|
||||||
|
namespace keepass2android.Io
|
||||||
|
{
|
||||||
|
public class BuiltInFileStorage: IFileStorage
|
||||||
|
{
|
||||||
|
public void DeleteFile(IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
IOConnection.DeleteFile(ioc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
|
||||||
|
{
|
||||||
|
if (!ioc.IsLocalFile())
|
||||||
|
return false;
|
||||||
|
DateTime previousDate;
|
||||||
|
if (!DateTime.TryParse(previousFileVersion, out previousDate))
|
||||||
|
return false;
|
||||||
|
return File.GetLastWriteTimeUtc(ioc.Path) > previousDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ioc.IsLocalFile())
|
||||||
|
{
|
||||||
|
return File.GetLastWriteTimeUtc(ioc.Path).ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DateTime.MinValue.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream OpenFileForRead(IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
return IOConnection.OpenRead(ioc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
|
||||||
|
{
|
||||||
|
return new BuiltInFileTransaction(ioc, useFileTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BuiltInFileTransaction : IWriteTransaction
|
||||||
|
{
|
||||||
|
private readonly FileTransactionEx _transaction;
|
||||||
|
|
||||||
|
public BuiltInFileTransaction(IOConnectionInfo ioc, bool useFileTransaction)
|
||||||
|
{
|
||||||
|
_transaction = new FileTransactionEx(ioc, useFileTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream OpenFile()
|
||||||
|
{
|
||||||
|
return _transaction.OpenWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CommitWrite()
|
||||||
|
{
|
||||||
|
_transaction.CommitWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CompleteIoId()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool? FileExists()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
return UrlUtil.StripExtension(
|
||||||
|
UrlUtil.GetFileName(ioc.Path));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
src/Kp2aBusinessLogic/Io/IFileStorage.cs
Normal file
82
src/Kp2aBusinessLogic/Io/IFileStorage.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
using KeePassLib.Keys;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
|
||||||
|
namespace keepass2android.Io
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called as a callback from CheckForFileChangeAsync.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ioc"></param>
|
||||||
|
/// <param name="fileChanged"></param>
|
||||||
|
public delegate void OnCheckForFileChangeCompleted(IOConnectionInfo ioc, bool fileChanged);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface to encapsulate all access to disk or cloud.
|
||||||
|
/// </summary>
|
||||||
|
/// This interface might be implemented for different cloud storage providers in the future to extend the possibilities of the
|
||||||
|
/// "built-in" IOConnection class in the Keepass-Lib.
|
||||||
|
/// Note that it was decided to use the IOConnectionInfo also for cloud storage (unless it turns out that this isn't possible, but
|
||||||
|
/// with prefixes like dropbox:// it should be). The advantage is that the database for saving recent files etc. will then work without
|
||||||
|
/// much work to do. Furthermore, the IOConnectionInfo seems generic info to capture all required data, even though it might be nicer to
|
||||||
|
/// have an IIoStorageId interface in few cases.*/
|
||||||
|
public interface IFileStorage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the given file.
|
||||||
|
/// </summary>
|
||||||
|
void DeleteFile(IOConnectionInfo ioc);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests whether the file was changed.
|
||||||
|
/// </summary>
|
||||||
|
/// Note: This function may return false even if the file might have changed. The function
|
||||||
|
/// should focus on being fast and cheap instead of doing things like hashing or downloading a full file.
|
||||||
|
/// <returns>Returns true if a change was detected, false otherwise.</returns>
|
||||||
|
bool CheckForFileChangeFast(IOConnectionInfo ioc , string previousFileVersion);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string describing the "version" of the file specified by ioc.
|
||||||
|
/// </summary>
|
||||||
|
/// This string may have a deliberate value (except null) and should not be used by callers except for passing it to
|
||||||
|
/// CheckForFileChangeFast().
|
||||||
|
/// <returns>A string which should not be null.</returns>
|
||||||
|
string GetCurrentFileVersionFast(IOConnectionInfo ioc);
|
||||||
|
|
||||||
|
Stream OpenFileForRead(IOConnectionInfo ioc);
|
||||||
|
//Stream OpenFileForWrite( IOConnectionInfo ioc, bool useTransaction);
|
||||||
|
IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// brings up a dialog to query credentials or something like this.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if success, false if error or cancelled by user</returns>
|
||||||
|
bool CompleteIoId( /*in/out ioId*/);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the given file exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if it exists, false if not. Null if the check couldn't be performed (e.g. because no credentials available or no connection established.)</returns>
|
||||||
|
bool? FileExists( /*ioId*/);
|
||||||
|
|
||||||
|
string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IWriteTransaction: IDisposable
|
||||||
|
{
|
||||||
|
Stream OpenFile();
|
||||||
|
void CommitWrite();
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,8 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||||
|
<Compile Include="Io\IFileStorage.cs" />
|
||||||
<Compile Include="IProgressDialog.cs" />
|
<Compile Include="IProgressDialog.cs" />
|
||||||
<Compile Include="PreferenceKey.cs" />
|
<Compile Include="PreferenceKey.cs" />
|
||||||
<Compile Include="UiStringKey.cs" />
|
<Compile Include="UiStringKey.cs" />
|
||||||
@ -68,7 +70,7 @@
|
|||||||
<Compile Include="Resources\Resource.Designer.cs" />
|
<Compile Include="Resources\Resource.Designer.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SearchDbHelper.cs" />
|
<Compile Include="SearchDbHelper.cs" />
|
||||||
<Compile Include="UpdateStatus.cs" />
|
<Compile Include="ProgressDialogStatusLogger.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||||
|
@ -6,6 +6,7 @@ namespace keepass2android
|
|||||||
public enum PreferenceKey
|
public enum PreferenceKey
|
||||||
{
|
{
|
||||||
remember_keyfile,
|
remember_keyfile,
|
||||||
UseFileTransactions
|
UseFileTransactions,
|
||||||
|
CheckForFileChangesOnSave
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,34 +25,54 @@ namespace keepass2android
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// StatusLogger implementation which shows the progress in a progress dialog
|
/// StatusLogger implementation which shows the progress in a progress dialog
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpdateStatus: IStatusLogger {
|
public class ProgressDialogStatusLogger: IStatusLogger {
|
||||||
private readonly IProgressDialog _progressDialog;
|
private readonly IProgressDialog _progressDialog;
|
||||||
readonly IKp2aApp _app;
|
readonly IKp2aApp _app;
|
||||||
private readonly Handler _handler;
|
private readonly Handler _handler;
|
||||||
|
private string _message = "";
|
||||||
public UpdateStatus() {
|
|
||||||
|
public ProgressDialogStatusLogger() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateStatus(IKp2aApp app, Handler handler, IProgressDialog pd) {
|
public ProgressDialogStatusLogger(IKp2aApp app, Handler handler, IProgressDialog pd) {
|
||||||
_app = app;
|
_app = app;
|
||||||
_progressDialog = pd;
|
_progressDialog = pd;
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMessage(UiStringKey stringKey) {
|
public void UpdateMessage(UiStringKey stringKey) {
|
||||||
if ( _app != null && _progressDialog != null && _handler != null ) {
|
if (_app != null)
|
||||||
_handler.Post( () => {_progressDialog.SetMessage(_app.GetResourceString(stringKey));});
|
UpdateMessage(_app.GetResourceString(stringKey));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMessage (String message)
|
public void UpdateMessage (String message)
|
||||||
{
|
{
|
||||||
|
_message = message;
|
||||||
if ( _app!= null && _progressDialog != null && _handler != null ) {
|
if ( _app!= null && _progressDialog != null && _handler != null ) {
|
||||||
_handler.Post(() => {_progressDialog.SetMessage(message); } );
|
_handler.Post(() => {_progressDialog.SetMessage(message); } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateSubMessage(String submessage)
|
||||||
|
{
|
||||||
|
if (_app != null && _progressDialog != null && _handler != null)
|
||||||
|
{
|
||||||
|
_handler.Post(() =>
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(submessage))
|
||||||
|
{
|
||||||
|
_progressDialog.SetMessage(_message + " (" + submessage + ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_progressDialog.SetMessage(_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region IStatusLogger implementation
|
#region IStatusLogger implementation
|
||||||
|
|
||||||
public void StartLogging (string strOperation, bool bWriteOperationToLog)
|
public void StartLogging (string strOperation, bool bWriteOperationToLog)
|
||||||
@ -72,10 +92,32 @@ namespace keepass2android
|
|||||||
|
|
||||||
public bool SetText (string strNewText, LogStatusType lsType)
|
public bool SetText (string strNewText, LogStatusType lsType)
|
||||||
{
|
{
|
||||||
UpdateMessage(strNewText);
|
if (strNewText.StartsWith("KP2AKEY_"))
|
||||||
|
{
|
||||||
|
UiStringKey key;
|
||||||
|
if (Enum.TryParse(strNewText.Substring("KP2AKEY_".Length), true, out key))
|
||||||
|
{
|
||||||
|
UpdateMessage(_app.GetResourceString(key), lsType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateMessage(strNewText, lsType);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateMessage(string message, LogStatusType lsType)
|
||||||
|
{
|
||||||
|
if (lsType == LogStatusType.AdditionalInfo)
|
||||||
|
{
|
||||||
|
UpdateSubMessage(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool ContinueWork ()
|
public bool ContinueWork ()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
@ -32,7 +32,7 @@ namespace keepass2android
|
|||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
private Thread _thread;
|
private Thread _thread;
|
||||||
|
|
||||||
public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task, UiStringKey messageKey) {
|
public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) {
|
||||||
_task = task;
|
_task = task;
|
||||||
_handler = app.UiThreadHandler;
|
_handler = app.UiThreadHandler;
|
||||||
_app = app;
|
_app = app;
|
||||||
@ -40,11 +40,12 @@ namespace keepass2android
|
|||||||
// Show process dialog
|
// Show process dialog
|
||||||
_progressDialog = app.CreateProgressDialog(ctx);
|
_progressDialog = app.CreateProgressDialog(ctx);
|
||||||
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
|
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
|
||||||
_progressDialog.SetMessage(_app.GetResourceString(messageKey));
|
_progressDialog.SetMessage("Initializing...");
|
||||||
|
|
||||||
// Set code to run when this is finished
|
// Set code to run when this is finished
|
||||||
_task.SetStatus(new UpdateStatus(_app, _handler, _progressDialog));
|
|
||||||
_task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog);
|
_task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog);
|
||||||
|
_task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,19 @@ namespace keepass2android
|
|||||||
keyfile_does_not_exist,
|
keyfile_does_not_exist,
|
||||||
RecycleBin,
|
RecycleBin,
|
||||||
progress_create,
|
progress_create,
|
||||||
loading_database
|
loading_database,
|
||||||
|
AddingEntry,
|
||||||
|
AddingGroup,
|
||||||
|
DeletingEntry,
|
||||||
|
DeletingGroup,
|
||||||
|
SettingPassword,
|
||||||
|
UndoingChanges,
|
||||||
|
TransformingKey,
|
||||||
|
DecodingDatabase,
|
||||||
|
ParsingDatabase,
|
||||||
|
CheckingTargetFileForChanges,
|
||||||
|
TitleSyncQuestion,
|
||||||
|
MessageSyncQuestions,
|
||||||
|
SynchronizingDatabase
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,10 +17,12 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
|
using keepass2android.Io;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
@ -34,7 +36,7 @@ namespace keepass2android
|
|||||||
public PwGroup Root;
|
public PwGroup Root;
|
||||||
public PwDatabase KpDatabase;
|
public PwDatabase KpDatabase;
|
||||||
public IOConnectionInfo Ioc { get { return KpDatabase.IOConnectionInfo; } }
|
public IOConnectionInfo Ioc { get { return KpDatabase.IOConnectionInfo; } }
|
||||||
public DateTime LastChangeDate;
|
public string LastFileVersion;
|
||||||
public SearchDbHelper SearchHelper;
|
public SearchDbHelper SearchHelper;
|
||||||
|
|
||||||
public IDrawableFactory DrawableFactory;
|
public IDrawableFactory DrawableFactory;
|
||||||
@ -83,15 +85,16 @@ namespace keepass2android
|
|||||||
|
|
||||||
public bool DidOpenFileChange()
|
public bool DidOpenFileChange()
|
||||||
{
|
{
|
||||||
if ((Loaded == false) || (Ioc.IsLocalFile() == false))
|
if (Loaded == false)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return System.IO.File.GetLastWriteTimeUtc(Ioc.Path) > LastChangeDate;
|
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, String password, String keyfile, UpdateStatus status)
|
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, String password, String keyfile, ProgressDialogStatusLogger status)
|
||||||
{
|
{
|
||||||
PwDatabase pwDatabase = new PwDatabase();
|
PwDatabase pwDatabase = new PwDatabase();
|
||||||
|
|
||||||
@ -103,15 +106,17 @@ namespace keepass2android
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
compositeKey.AddUserKey(new KcpKeyFile(keyfile));
|
compositeKey.AddUserKey(new KcpKeyFile(keyfile));
|
||||||
} catch (Exception)
|
} catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log(e.ToString());
|
||||||
throw new KeyFileException();
|
throw new KeyFileException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pwDatabase.Open(iocInfo, compositeKey, status);
|
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
|
||||||
|
pwDatabase.Open(fileStorage.OpenFileForRead(iocInfo), fileStorage.GetFilenameWithoutPathAndExt(iocInfo), iocInfo, compositeKey, status);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
@ -125,14 +130,9 @@ namespace keepass2android
|
|||||||
else throw;
|
else throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status.UpdateSubMessage("");
|
||||||
|
|
||||||
if (iocInfo.IsLocalFile())
|
LastFileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
|
||||||
{
|
|
||||||
LastChangeDate = System.IO.File.GetLastWriteTimeUtc(iocInfo.Path);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
LastChangeDate = DateTime.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Root = pwDatabase.RootGroup;
|
Root = pwDatabase.RootGroup;
|
||||||
PopulateGlobals(Root);
|
PopulateGlobals(Root);
|
||||||
@ -184,9 +184,14 @@ namespace keepass2android
|
|||||||
public void SaveData(Context ctx) {
|
public void SaveData(Context ctx) {
|
||||||
|
|
||||||
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
|
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
|
||||||
KpDatabase.Save(null);
|
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
|
||||||
|
{
|
||||||
|
KpDatabase.Save(trans.OpenFile(), null);
|
||||||
|
trans.CommitWrite();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void PopulateGlobals (PwGroup currentGroup)
|
private void PopulateGlobals (PwGroup currentGroup)
|
||||||
{
|
{
|
||||||
|
@ -21,31 +21,38 @@ using KeePassLib;
|
|||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
public class AddEntry : RunnableOnFinish {
|
public class AddEntry : RunnableOnFinish {
|
||||||
protected Database Db;
|
protected Database Db
|
||||||
|
{
|
||||||
|
get { return _app.GetDb(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IKp2aApp _app;
|
||||||
private readonly PwEntry _entry;
|
private readonly PwEntry _entry;
|
||||||
private readonly PwGroup _parentGroup;
|
private readonly PwGroup _parentGroup;
|
||||||
private readonly Context _ctx;
|
private readonly Context _ctx;
|
||||||
|
|
||||||
public static AddEntry GetInstance(Context ctx, Database db, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
|
public static AddEntry GetInstance(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
|
||||||
|
|
||||||
return new AddEntry(ctx, db, entry, parentGroup, finish);
|
return new AddEntry(ctx, app, entry, parentGroup, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AddEntry(Context ctx, Database db, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
|
protected AddEntry(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_parentGroup = parentGroup;
|
_parentGroup = parentGroup;
|
||||||
Db = db;
|
_app = app;
|
||||||
_entry = entry;
|
_entry = entry;
|
||||||
|
|
||||||
OnFinishToRun = new AfterAdd(db, entry, OnFinishToRun);
|
_onFinishToRun = new AfterAdd(app.GetDb(), entry, OnFinishToRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
|
||||||
_parentGroup.AddEntry(_entry, true);
|
_parentGroup.AddEntry(_entry, true);
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, Db, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +79,9 @@ namespace keepass2android
|
|||||||
// Add entry to global
|
// Add entry to global
|
||||||
_db.Entries[_entry.Uuid] = _entry;
|
_db.Entries[_entry.Uuid] = _entry;
|
||||||
|
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
||||||
//TODO test fail
|
//TODO test fail
|
||||||
_entry.ParentGroup.Entries.Remove(_entry);
|
_entry.ParentGroup.Entries.Remove(_entry);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,11 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
|
|
||||||
public class AddGroup : RunnableOnFinish {
|
public class AddGroup : RunnableOnFinish {
|
||||||
internal Database Db;
|
internal Database Db
|
||||||
|
{
|
||||||
|
get { return _app.GetDb(); }
|
||||||
|
}
|
||||||
|
private IKp2aApp _app;
|
||||||
private readonly String _name;
|
private readonly String _name;
|
||||||
private readonly int _iconId;
|
private readonly int _iconId;
|
||||||
internal PwGroup Group;
|
internal PwGroup Group;
|
||||||
@ -32,31 +36,32 @@ namespace keepass2android
|
|||||||
readonly Context _ctx;
|
readonly Context _ctx;
|
||||||
|
|
||||||
|
|
||||||
public static AddGroup GetInstance(Context ctx, Database db, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave) {
|
public static AddGroup GetInstance(Context ctx, IKp2aApp app, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave) {
|
||||||
return new AddGroup(ctx, db, name, iconid, parent, finish, dontSave);
|
return new AddGroup(ctx, app, name, iconid, parent, finish, dontSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AddGroup(Context ctx, Database db, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave): base(finish) {
|
private AddGroup(Context ctx, IKp2aApp app, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave): base(finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
Db = db;
|
|
||||||
_name = name;
|
_name = name;
|
||||||
_iconId = iconid;
|
_iconId = iconid;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DontSave = dontSave;
|
DontSave = dontSave;
|
||||||
|
_app = app;
|
||||||
OnFinishToRun = new AfterAdd(this, OnFinishToRun);
|
|
||||||
|
_onFinishToRun = new AfterAdd(this, OnFinishToRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.AddingGroup);
|
||||||
// Generate new group
|
// Generate new group
|
||||||
Group = new PwGroup(true, true, _name, (PwIcon)_iconId);
|
Group = new PwGroup(true, true, _name, (PwIcon)_iconId);
|
||||||
Parent.AddGroup(Group, true);
|
Parent.AddGroup(Group, true);
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, Db, OnFinishToRun, DontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +82,7 @@ namespace keepass2android
|
|||||||
// Add group to global list
|
// Add group to global list
|
||||||
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
|
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
|
||||||
} else {
|
} else {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
||||||
_addGroup.Parent.Groups.Remove(_addGroup.Group);
|
_addGroup.Parent.Groups.Remove(_addGroup.Group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.progress_create);
|
||||||
Database db = _app.CreateNewDatabase();
|
Database db = _app.CreateNewDatabase();
|
||||||
|
|
||||||
db.KpDatabase = new KeePassLib.PwDatabase();
|
db.KpDatabase = new KeePassLib.PwDatabase();
|
||||||
@ -58,14 +59,15 @@ namespace keepass2android
|
|||||||
db.SearchHelper = new SearchDbHelper(_app);
|
db.SearchHelper = new SearchDbHelper(_app);
|
||||||
|
|
||||||
// Add a couple default groups
|
// Add a couple default groups
|
||||||
AddGroup internet = AddGroup.GetInstance(_ctx, db, "Internet", 1, db.KpDatabase.RootGroup, null, true);
|
AddGroup internet = AddGroup.GetInstance(_ctx, _app, "Internet", 1, db.KpDatabase.RootGroup, null, true);
|
||||||
internet.Run();
|
internet.Run();
|
||||||
AddGroup email = AddGroup.GetInstance(_ctx, db, "eMail", 19, db.KpDatabase.RootGroup, null, true);
|
AddGroup email = AddGroup.GetInstance(_ctx, _app, "eMail", 19, db.KpDatabase.RootGroup, null, true);
|
||||||
email.Run();
|
email.Run();
|
||||||
|
|
||||||
// Commit changes
|
// Commit changes
|
||||||
SaveDb save = new SaveDb(_ctx, db, OnFinishToRun, _dontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||||
OnFinishToRun = null;
|
save.SetStatusLogger(StatusLogger);
|
||||||
|
_onFinishToRun = null;
|
||||||
save.Run();
|
save.Run();
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,8 +48,9 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run()
|
||||||
|
{
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.DeletingEntry);
|
||||||
PwDatabase pd = Db.KpDatabase;
|
PwDatabase pd = Db.KpDatabase;
|
||||||
|
|
||||||
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
|
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
|
||||||
@ -68,7 +69,7 @@ namespace keepass2android
|
|||||||
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
|
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
|
||||||
pd.DeletedObjects.Add(pdo);
|
pd.DeletedObjects.Add(pdo);
|
||||||
|
|
||||||
OnFinishToRun = new ActionOnFinish((success, message) =>
|
_onFinishToRun = new ActionOnFinish((success, message) =>
|
||||||
{
|
{
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -89,7 +90,7 @@ namespace keepass2android
|
|||||||
pgRecycleBin.AddEntry(pe, true, true);
|
pgRecycleBin.AddEntry(pe, true, true);
|
||||||
pe.Touch(false);
|
pe.Touch(false);
|
||||||
|
|
||||||
OnFinishToRun = new ActionOnFinish( (success, message) =>
|
_onFinishToRun = new ActionOnFinish( (success, message) =>
|
||||||
{
|
{
|
||||||
if ( success ) {
|
if ( success ) {
|
||||||
// Mark previous parent dirty
|
// Mark previous parent dirty
|
||||||
@ -106,7 +107,8 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Commit database
|
// Commit database
|
||||||
SaveDb save = new SaveDb(Ctx, Db, OnFinishToRun, false);
|
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.DeletingGroup);
|
||||||
//from KP Desktop
|
//from KP Desktop
|
||||||
PwGroup pg = _group;
|
PwGroup pg = _group;
|
||||||
PwGroup pgParent = pg.ParentGroup;
|
PwGroup pgParent = pg.ParentGroup;
|
||||||
@ -86,7 +87,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
|
PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
|
||||||
pd.DeletedObjects.Add(pdo);
|
pd.DeletedObjects.Add(pdo);
|
||||||
OnFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
|
_onFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
|
||||||
}
|
}
|
||||||
else // Recycle
|
else // Recycle
|
||||||
{
|
{
|
||||||
@ -95,7 +96,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
pgRecycleBin.AddGroup(pg, true, true);
|
pgRecycleBin.AddGroup(pg, true, true);
|
||||||
pg.Touch(false);
|
pg.Touch(false);
|
||||||
OnFinishToRun = new ActionOnFinish((success, message) =>
|
_onFinishToRun = new ActionOnFinish((success, message) =>
|
||||||
{
|
{
|
||||||
if ( success ) {
|
if ( success ) {
|
||||||
// Mark new parent (Recycle bin) dirty
|
// Mark new parent (Recycle bin) dirty
|
||||||
@ -113,7 +114,8 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
SaveDb save = new SaveDb(Ctx, Db, OnFinishToRun, DontSave);
|
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, DontSave);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -109,12 +109,12 @@ namespace keepass2android
|
|||||||
(dlgSender, dlgEvt) =>
|
(dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
DeletePermanently = true;
|
DeletePermanently = true;
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) => {
|
(dlgSender, dlgEvt) => {
|
||||||
DeletePermanently = false;
|
DeletePermanently = false;
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) => {},
|
(dlgSender, dlgEvt) => {},
|
||||||
@ -124,7 +124,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_app.GetDb().LoadData (_app, _ioc, _pass, _key, Status);
|
StatusLogger.UpdateMessage(UiStringKey.loading_database);
|
||||||
|
_app.GetDb().LoadData (_app, _ioc, _pass, _key, StatusLogger);
|
||||||
SaveFileData (_ioc, _key);
|
SaveFileData (_ioc, _key);
|
||||||
|
|
||||||
} catch (KeyFileException) {
|
} catch (KeyFileException) {
|
||||||
|
@ -29,6 +29,13 @@ namespace keepass2android
|
|||||||
|
|
||||||
protected OnFinish BaseOnFinish;
|
protected OnFinish BaseOnFinish;
|
||||||
protected Handler Handler;
|
protected Handler Handler;
|
||||||
|
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
|
||||||
|
|
||||||
|
public ProgressDialogStatusLogger StatusLogger
|
||||||
|
{
|
||||||
|
get { return _statusLogger; }
|
||||||
|
set { _statusLogger = value; }
|
||||||
|
}
|
||||||
|
|
||||||
protected OnFinish() {
|
protected OnFinish() {
|
||||||
}
|
}
|
||||||
@ -47,7 +54,7 @@ namespace keepass2android
|
|||||||
BaseOnFinish = finish;
|
BaseOnFinish = finish;
|
||||||
Handler = null;
|
Handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResult(bool success, String message) {
|
public void SetResult(bool success, String message) {
|
||||||
Success = success;
|
Success = success;
|
||||||
Message = message;
|
Message = message;
|
||||||
|
@ -21,13 +21,19 @@ namespace keepass2android
|
|||||||
|
|
||||||
public abstract class RunnableOnFinish {
|
public abstract class RunnableOnFinish {
|
||||||
|
|
||||||
public OnFinish OnFinishToRun;
|
protected OnFinish _onFinishToRun;
|
||||||
public UpdateStatus Status;
|
public ProgressDialogStatusLogger StatusLogger = new ProgressDialogStatusLogger(); //default: empty but not null
|
||||||
|
|
||||||
protected RunnableOnFinish(OnFinish finish) {
|
protected RunnableOnFinish(OnFinish finish) {
|
||||||
OnFinishToRun = finish;
|
_onFinishToRun = finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OnFinish OnFinishToRun
|
||||||
|
{
|
||||||
|
get { return _onFinishToRun; }
|
||||||
|
set { _onFinishToRun = value; }
|
||||||
|
}
|
||||||
|
|
||||||
protected void Finish(bool result, String message) {
|
protected void Finish(bool result, String message) {
|
||||||
if ( OnFinishToRun != null ) {
|
if ( OnFinishToRun != null ) {
|
||||||
OnFinishToRun.SetResult(result, message);
|
OnFinishToRun.SetResult(result, message);
|
||||||
@ -42,8 +48,12 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStatus(UpdateStatus status) {
|
public void SetStatusLogger(ProgressDialogStatusLogger status) {
|
||||||
Status = status;
|
if (OnFinishToRun != null)
|
||||||
|
{
|
||||||
|
OnFinishToRun.StatusLogger = status;
|
||||||
|
}
|
||||||
|
StatusLogger = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public void Run();
|
abstract public void Run();
|
||||||
|
@ -14,26 +14,40 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Java.Lang;
|
||||||
|
using KeePassLib;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
using KeePassLib.Utility;
|
||||||
|
using keepass2android.Io;
|
||||||
|
using Debug = System.Diagnostics.Debug;
|
||||||
|
using Exception = System.Exception;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|
||||||
public class SaveDb : RunnableOnFinish {
|
public class SaveDb : RunnableOnFinish {
|
||||||
private readonly Database _db;
|
private readonly IKp2aApp _app;
|
||||||
private readonly bool _dontSave;
|
private readonly bool _dontSave;
|
||||||
private readonly Context _ctx;
|
private readonly Context _ctx;
|
||||||
|
private Thread _workerThread;
|
||||||
public SaveDb(Context ctx, Database db, OnFinish finish, bool dontSave): base(finish) {
|
|
||||||
|
public SaveDb(Context ctx, IKp2aApp app, OnFinish finish, bool dontSave): base(finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_db = db;
|
_app = app;
|
||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveDb(Context ctx, Database db, OnFinish finish):base(finish) {
|
public SaveDb(Context ctx, IKp2aApp app, OnFinish finish)
|
||||||
|
: base(finish)
|
||||||
|
{
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_db = db;
|
_app = app;
|
||||||
_dontSave = false;
|
_dontSave = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +56,67 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (! _dontSave) {
|
if (! _dontSave) {
|
||||||
try {
|
try
|
||||||
_db.SaveData (_ctx);
|
{
|
||||||
if (_db.Ioc.IsLocalFile())
|
StatusLogger.UpdateMessage(UiStringKey.saving_database);
|
||||||
_db.LastChangeDate = System.IO.File.GetLastWriteTimeUtc(_db.Ioc.Path);
|
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||||
|
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||||
|
|
||||||
|
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|
||||||
|
|| (_app.GetDb().KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
||||||
|
{
|
||||||
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
|
Finish(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection
|
||||||
|
|| (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk))) //if that fails, hash the file and compare:
|
||||||
|
{
|
||||||
|
//ask user...
|
||||||
|
_app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestions,
|
||||||
|
//yes = sync
|
||||||
|
(sender, args) =>
|
||||||
|
{
|
||||||
|
Action runHandler = () =>
|
||||||
|
{
|
||||||
|
//note: when synced, the file might be downloaded once again from the server. Caching the data
|
||||||
|
//in the hashing function would solve this but increases complexity. I currently assume the files are
|
||||||
|
//small.
|
||||||
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
|
||||||
|
MergeIn(fileStorage, ioc);
|
||||||
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
|
Finish(true);
|
||||||
|
};
|
||||||
|
RunInWorkerThread(runHandler);
|
||||||
|
},
|
||||||
|
//no = overwrite
|
||||||
|
(sender, args) =>
|
||||||
|
{
|
||||||
|
RunInWorkerThread( () =>
|
||||||
|
{
|
||||||
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
|
Finish(true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//cancel
|
||||||
|
(sender, args) =>
|
||||||
|
{
|
||||||
|
RunInWorkerThread(() => Finish(false));
|
||||||
|
},
|
||||||
|
_ctx
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
|
Finish(true);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
/* TODO KPDesktop:
|
/* TODO KPDesktop:
|
||||||
* catch(Exception exSave)
|
* catch(Exception exSave)
|
||||||
@ -54,13 +125,85 @@ namespace keepass2android
|
|||||||
bSuccess = false;
|
bSuccess = false;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
Finish (false, e.Message);
|
Finish (false, e.ToString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Finish(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RunInWorkerThread(Action runHandler)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_workerThread = new Thread(runHandler);
|
||||||
|
_workerThread.Run();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("Error in worker thread of SaveDb: "+e);
|
||||||
|
Finish(false, e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void JoinWorkerThread()
|
||||||
|
{
|
||||||
|
if (_workerThread != null)
|
||||||
|
_workerThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MergeIn(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
PwDatabase pwImp = new PwDatabase();
|
||||||
|
PwDatabase pwDatabase = _app.GetDb().KpDatabase;
|
||||||
|
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
|
||||||
|
pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
|
||||||
|
pwImp.MasterKey = pwDatabase.MasterKey;
|
||||||
|
KdbxFile kdbx = new KdbxFile(pwImp);
|
||||||
|
kdbx.Load(fileStorage.OpenFileForRead(ioc), KdbxFormat.Default, null);
|
||||||
|
|
||||||
|
pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
_app.GetDb().SaveData(_ctx);
|
||||||
|
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] HashFile(IOConnectionInfo iocFile)
|
||||||
|
{
|
||||||
|
if (iocFile == null) { Debug.Assert(false); return null; } // Assert only
|
||||||
|
|
||||||
|
Stream sIn;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sIn = _app.GetFileStorage(iocFile).OpenFileForRead(iocFile);
|
||||||
|
if (sIn == null) throw new FileNotFoundException();
|
||||||
|
}
|
||||||
|
catch (Exception) { return null; }
|
||||||
|
|
||||||
|
byte[] pbHash;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SHA256Managed sha256 = new SHA256Managed();
|
||||||
|
pbHash = sha256.ComputeHash(sIn);
|
||||||
|
}
|
||||||
|
catch (Exception) { Debug.Assert(false); sIn.Close(); return null; }
|
||||||
|
|
||||||
|
sIn.Close();
|
||||||
|
return pbHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FileHashChanged(IOConnectionInfo ioc, byte[] hashOfFileOnDisk)
|
||||||
|
{
|
||||||
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.CheckingTargetFileForChanges));
|
||||||
|
return !MemUtil.ArraysEqual(HashFile(ioc), hashOfFileOnDisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,21 +25,23 @@ namespace keepass2android
|
|||||||
|
|
||||||
private readonly String _password;
|
private readonly String _password;
|
||||||
private readonly String _keyfile;
|
private readonly String _keyfile;
|
||||||
private readonly Database _db;
|
private readonly IKp2aApp _app;
|
||||||
private readonly bool _dontSave;
|
private readonly bool _dontSave;
|
||||||
private readonly Context _ctx;
|
private readonly Context _ctx;
|
||||||
|
|
||||||
public SetPassword(Context ctx, Database db, String password, String keyfile, OnFinish finish): base(finish) {
|
public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish): base(finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_db = db;
|
_app = app;
|
||||||
_password = password;
|
_password = password;
|
||||||
_keyfile = keyfile;
|
_keyfile = keyfile;
|
||||||
_dontSave = false;
|
_dontSave = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SetPassword(Context ctx, Database db, String password, String keyfile, OnFinish finish, bool dontSave): base(finish) {
|
public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish, bool dontSave)
|
||||||
|
: base(finish)
|
||||||
|
{
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_db = db;
|
_app = app;
|
||||||
_password = password;
|
_password = password;
|
||||||
_keyfile = keyfile;
|
_keyfile = keyfile;
|
||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
@ -48,7 +50,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
public override void Run ()
|
public override void Run ()
|
||||||
{
|
{
|
||||||
PwDatabase pm = _db.KpDatabase;
|
StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
|
||||||
|
PwDatabase pm = _app.GetDb().KpDatabase;
|
||||||
CompositeKey newKey = new CompositeKey ();
|
CompositeKey newKey = new CompositeKey ();
|
||||||
if (String.IsNullOrEmpty (_password) == false) {
|
if (String.IsNullOrEmpty (_password) == false) {
|
||||||
newKey.AddUserKey (new KcpPassword (_password));
|
newKey.AddUserKey (new KcpPassword (_password));
|
||||||
@ -69,8 +72,9 @@ namespace keepass2android
|
|||||||
pm.MasterKey = newKey;
|
pm.MasterKey = newKey;
|
||||||
|
|
||||||
// Save Database
|
// Save Database
|
||||||
OnFinishToRun = new AfterSave(previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
_onFinishToRun = new AfterSave(previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
||||||
SaveDb save = new SaveDb(_ctx, _db, OnFinishToRun, _dontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,32 +22,33 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
|
|
||||||
public class UpdateEntry : RunnableOnFinish {
|
public class UpdateEntry : RunnableOnFinish {
|
||||||
private readonly Database _db;
|
private readonly IKp2aApp _app;
|
||||||
private readonly Context _ctx;
|
private readonly Context _ctx;
|
||||||
|
|
||||||
public UpdateEntry(Context ctx, Database db, PwEntry oldE, PwEntry newE, OnFinish finish):base(finish) {
|
public UpdateEntry(Context ctx, IKp2aApp app, PwEntry oldE, PwEntry newE, OnFinish finish):base(finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_db = db;
|
_app = app;
|
||||||
|
|
||||||
OnFinishToRun = new AfterUpdate(oldE, newE, db, finish);
|
_onFinishToRun = new AfterUpdate(oldE, newE, app, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _db, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AfterUpdate : OnFinish {
|
private class AfterUpdate : OnFinish {
|
||||||
private readonly PwEntry _backup;
|
private readonly PwEntry _backup;
|
||||||
private readonly PwEntry _updatedEntry;
|
private readonly PwEntry _updatedEntry;
|
||||||
private readonly Database _db;
|
private readonly IKp2aApp _app;
|
||||||
|
|
||||||
public AfterUpdate(PwEntry backup, PwEntry updatedEntry, Database db, OnFinish finish):base(finish) {
|
public AfterUpdate(PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnFinish finish):base(finish) {
|
||||||
_backup = backup;
|
_backup = backup;
|
||||||
_updatedEntry = updatedEntry;
|
_updatedEntry = updatedEntry;
|
||||||
_db = db;
|
_app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
@ -65,11 +66,12 @@ namespace keepass2android
|
|||||||
if ( parent != null ) {
|
if ( parent != null ) {
|
||||||
|
|
||||||
// Mark parent group dirty
|
// Mark parent group dirty
|
||||||
_db.Dirty.Add(parent);
|
_app.GetDb().Dirty.Add(parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
||||||
// If we fail to save, back out changes to global structure
|
// If we fail to save, back out changes to global structure
|
||||||
//TODO test fail
|
//TODO test fail
|
||||||
_updatedEntry.AssignProperties(_backup, false, true, false);
|
_updatedEntry.AssignProperties(_backup, false, true, false);
|
||||||
|
@ -20,7 +20,8 @@ namespace Kp2aUnitTests
|
|||||||
// Run all tests from this assembly
|
// Run all tests from this assembly
|
||||||
runner.AddTests(Assembly.GetExecutingAssembly());
|
runner.AddTests(Assembly.GetExecutingAssembly());
|
||||||
//runner.AddTests(new List<Type> { typeof(TestSaveDb)});
|
//runner.AddTests(new List<Type> { typeof(TestSaveDb)});
|
||||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadWithPasswordOnly"));}}
|
//runner.AddTests(typeof(TestSaveDb).GetMethod("TestLoadEditSaveWithSyncConflict"));
|
||||||
|
//runner.AddTests(typeof(TestSaveDb).GetMethod("TestLoadEditSave"));
|
||||||
return runner;
|
return runner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ namespace Kp2aUnitTests
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMessage(string getResourceString)
|
public void SetMessage(string resourceString)
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log("Progress message: " + resourceString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dismiss()
|
public void Dismiss()
|
||||||
|
@ -74,7 +74,7 @@ namespace Kp2aUnitTests
|
|||||||
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ProgressTask pt = new ProgressTask(app, Application.Context, task, UiStringKey.loading_database);
|
ProgressTask pt = new ProgressTask(app, Application.Context, task);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
pt.JoinWorkerThread();
|
pt.JoinWorkerThread();
|
||||||
Assert.IsTrue(loadSuccesful);
|
Assert.IsTrue(loadSuccesful);
|
||||||
@ -83,16 +83,27 @@ namespace Kp2aUnitTests
|
|||||||
|
|
||||||
protected void SaveDatabase(IKp2aApp app)
|
protected void SaveDatabase(IKp2aApp app)
|
||||||
{
|
{
|
||||||
bool saveSuccesful = false;
|
bool saveSuccesful = TrySaveDatabase(app);
|
||||||
SaveDb save = new SaveDb(Application.Context, app.GetDb(), new ActionOnFinish((success, message) =>
|
|
||||||
{
|
|
||||||
saveSuccesful = success;
|
|
||||||
}), false);
|
|
||||||
save.Run();
|
|
||||||
|
|
||||||
Assert.IsTrue(saveSuccesful);
|
Assert.IsTrue(saveSuccesful);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool TrySaveDatabase(IKp2aApp app)
|
||||||
|
{
|
||||||
|
bool saveSuccesful = false;
|
||||||
|
SaveDb save = new SaveDb(Application.Context, app, new ActionOnFinish((success, message) =>
|
||||||
|
{
|
||||||
|
saveSuccesful = success;
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("Error during TestBase.SaveDatabase: " + message);
|
||||||
|
}
|
||||||
|
}), false);
|
||||||
|
save.Run();
|
||||||
|
save.JoinWorkerThread();
|
||||||
|
return saveSuccesful;
|
||||||
|
}
|
||||||
|
|
||||||
protected IKp2aApp SetupAppWithDefaultDatabase()
|
protected IKp2aApp SetupAppWithDefaultDatabase()
|
||||||
{
|
{
|
||||||
IKp2aApp app = new TestKp2aApp();
|
IKp2aApp app = new TestKp2aApp();
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using keepass2android;
|
using keepass2android;
|
||||||
|
using keepass2android.Io;
|
||||||
|
|
||||||
namespace Kp2aUnitTests
|
namespace Kp2aUnitTests
|
||||||
{
|
{
|
||||||
@ -11,7 +13,14 @@ namespace Kp2aUnitTests
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class TestKp2aApp : IKp2aApp
|
internal class TestKp2aApp : IKp2aApp
|
||||||
{
|
{
|
||||||
|
internal enum YesNoCancelResult
|
||||||
|
{
|
||||||
|
Yes, No, Cancel
|
||||||
|
}
|
||||||
|
|
||||||
private Database _db;
|
private Database _db;
|
||||||
|
private YesNoCancelResult _yesNoCancelResult = YesNoCancelResult.Yes;
|
||||||
|
private Dictionary<PreferenceKey, bool> _preferences = new Dictionary<PreferenceKey, bool>();
|
||||||
|
|
||||||
public void SetShutdown()
|
public void SetShutdown()
|
||||||
{
|
{
|
||||||
@ -43,13 +52,32 @@ namespace Kp2aUnitTests
|
|||||||
|
|
||||||
public bool GetBooleanPreference(PreferenceKey key)
|
public bool GetBooleanPreference(PreferenceKey key)
|
||||||
{
|
{
|
||||||
|
if (_preferences.ContainsKey(key))
|
||||||
|
return _preferences[key];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UiStringKey? LastYesNoCancelQuestionTitle { get; set; }
|
||||||
|
|
||||||
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey, EventHandler<DialogClickEventArgs> yesHandler, EventHandler<DialogClickEventArgs> noHandler,
|
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey, EventHandler<DialogClickEventArgs> yesHandler, EventHandler<DialogClickEventArgs> noHandler,
|
||||||
EventHandler<DialogClickEventArgs> cancelHandler, Context ctx)
|
EventHandler<DialogClickEventArgs> cancelHandler, Context ctx)
|
||||||
{
|
{
|
||||||
yesHandler(null, null);
|
LastYesNoCancelQuestionTitle = titleKey;
|
||||||
|
switch (_yesNoCancelResult)
|
||||||
|
{
|
||||||
|
case YesNoCancelResult.Yes:
|
||||||
|
yesHandler(null, null);
|
||||||
|
break;
|
||||||
|
case YesNoCancelResult.No:
|
||||||
|
noHandler(null, null);
|
||||||
|
break;
|
||||||
|
case YesNoCancelResult.Cancel:
|
||||||
|
cancelHandler(null, null);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("unexpected case!");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handler UiThreadHandler {
|
public Handler UiThreadHandler {
|
||||||
@ -59,5 +87,20 @@ namespace Kp2aUnitTests
|
|||||||
{
|
{
|
||||||
return new ProgressDialogStub();
|
return new ProgressDialogStub();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||||
|
{
|
||||||
|
return new BuiltInFileStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetYesNoCancelResult(YesNoCancelResult yesNoCancelResult)
|
||||||
|
{
|
||||||
|
_yesNoCancelResult = yesNoCancelResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPreference(PreferenceKey key, bool value)
|
||||||
|
{
|
||||||
|
_preferences[key] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ namespace Kp2aUnitTests
|
|||||||
loadSuccesful = success;
|
loadSuccesful = success;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ProgressTask pt = new ProgressTask(app, Application.Context, task, UiStringKey.loading_database);
|
ProgressTask pt = new ProgressTask(app, Application.Context, task);
|
||||||
Android.Util.Log.Debug("KP2ATest", "Running ProgressTask");
|
Android.Util.Log.Debug("KP2ATest", "Running ProgressTask");
|
||||||
pt.Run();
|
pt.Run();
|
||||||
pt.JoinWorkerThread();
|
pt.JoinWorkerThread();
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
@ -23,6 +25,7 @@ namespace Kp2aUnitTests
|
|||||||
{
|
{
|
||||||
//create the default database:
|
//create the default database:
|
||||||
IKp2aApp app = SetupAppWithDefaultDatabase();
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
||||||
|
IOConnection.DeleteFile(new IOConnectionInfo { Path = DefaultFilename });
|
||||||
//save it and reload it so we have a base version
|
//save it and reload it so we have a base version
|
||||||
SaveDatabase(app);
|
SaveDatabase(app);
|
||||||
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
@ -56,9 +59,14 @@ namespace Kp2aUnitTests
|
|||||||
//save the database from app 1:
|
//save the database from app 1:
|
||||||
SaveDatabase(app);
|
SaveDatabase(app);
|
||||||
|
|
||||||
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
|
||||||
|
|
||||||
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
||||||
SaveDatabase(app2);
|
SaveDatabase(app2);
|
||||||
|
|
||||||
|
//make sure the right question was asked
|
||||||
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
||||||
|
|
||||||
//add group 2 to app 1:
|
//add group 2 to app 1:
|
||||||
app.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
app.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
||||||
|
|
||||||
@ -68,7 +76,162 @@ namespace Kp2aUnitTests
|
|||||||
//ensure the sync was successful:
|
//ensure the sync was successful:
|
||||||
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
||||||
|
|
||||||
Assert.IsTrue(false, "todo: test for sync question, test overwrite or cancel!");
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestLoadEditSaveWithSyncOverwrite()
|
||||||
|
{
|
||||||
|
//create the default database:
|
||||||
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
||||||
|
//save it and reload it so we have a base version
|
||||||
|
SaveDatabase(app);
|
||||||
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
//load it once again:
|
||||||
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//modify the database by adding a group in both databases:
|
||||||
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
||||||
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
||||||
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
||||||
|
//save the database from app 1:
|
||||||
|
SaveDatabase(app);
|
||||||
|
|
||||||
|
//the user clicks the "no" button when asked if the sync should be performed -> overwrite expected!
|
||||||
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.No);
|
||||||
|
|
||||||
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
||||||
|
SaveDatabase(app2);
|
||||||
|
|
||||||
|
//make sure the right question was asked
|
||||||
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
||||||
|
|
||||||
|
//load database to a new app instance:
|
||||||
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//ensure the sync was NOT performed (overwrite expected!):
|
||||||
|
AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestLoadEditSaveWithSyncOverwriteBecauseOfNoCheck()
|
||||||
|
{
|
||||||
|
//create the default database:
|
||||||
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
||||||
|
//save it and reload it so we have a base version
|
||||||
|
SaveDatabase(app);
|
||||||
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
//load it once again:
|
||||||
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//modify the database by adding a group in both databases:
|
||||||
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
||||||
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
||||||
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
||||||
|
//save the database from app 1:
|
||||||
|
SaveDatabase(app);
|
||||||
|
|
||||||
|
//the user doesn't want to perform check for file change:
|
||||||
|
((TestKp2aApp) app2).SetPreference(PreferenceKey.CheckForFileChangesOnSave, false);
|
||||||
|
|
||||||
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
||||||
|
SaveDatabase(app2);
|
||||||
|
|
||||||
|
//make sure no question was asked
|
||||||
|
Assert.AreEqual(null, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
||||||
|
|
||||||
|
//load database to a new app instance:
|
||||||
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//ensure the sync was NOT performed (overwrite expected!):
|
||||||
|
AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestLoadEditSaveWithSyncCancel()
|
||||||
|
{
|
||||||
|
//create the default database:
|
||||||
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
||||||
|
//save it and reload it so we have a base version
|
||||||
|
SaveDatabase(app);
|
||||||
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
//load it once again:
|
||||||
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//modify the database by adding a group in both databases:
|
||||||
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
||||||
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
||||||
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
||||||
|
//save the database from app 1:
|
||||||
|
SaveDatabase(app);
|
||||||
|
|
||||||
|
//the user clicks the "cancel" button when asked if the sync should be performed
|
||||||
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Cancel);
|
||||||
|
|
||||||
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
||||||
|
Assert.AreEqual(false, TrySaveDatabase(app2));
|
||||||
|
|
||||||
|
//make sure the right question was asked
|
||||||
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
||||||
|
|
||||||
|
//load database to a new app instance:
|
||||||
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//ensure the sync was NOT performed (cancel expected!):
|
||||||
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestLoadEditSaveWithSyncConflict()
|
||||||
|
{
|
||||||
|
|
||||||
|
//create the default database:
|
||||||
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
||||||
|
//save it and reload it so we have a base version
|
||||||
|
SaveDatabase(app);
|
||||||
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
//load it once again:
|
||||||
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
||||||
|
|
||||||
|
//modify the database by renaming the same group in both databases:
|
||||||
|
app.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abc";
|
||||||
|
app2.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abcde";
|
||||||
|
//app1 also changes the master password:
|
||||||
|
var compositeKey = app.GetDb().KpDatabase.MasterKey;
|
||||||
|
compositeKey.RemoveUserKey(compositeKey.GetUserKey(typeof (KcpPassword)));
|
||||||
|
compositeKey.AddUserKey(new KcpPassword("abc"));
|
||||||
|
|
||||||
|
//save the database from app 1:
|
||||||
|
SaveDatabase(app);
|
||||||
|
|
||||||
|
|
||||||
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
|
||||||
|
|
||||||
|
//save the database from app 2: This save operation must fail because the target file cannot be loaded:
|
||||||
|
Assert.IsFalse(TrySaveDatabase(app2));
|
||||||
|
|
||||||
|
//make sure the right question was asked
|
||||||
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSaveAsWhenReadOnly()
|
||||||
|
{
|
||||||
|
Assert.Fail("TODO: Test ");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSaveAsWhenSyncError()
|
||||||
|
{
|
||||||
|
Assert.Fail("TODO: Test ");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -119,4 +282,6 @@ namespace Kp2aUnitTests
|
|||||||
return sOutput.Text;
|
return sOutput.Text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,8 @@ namespace keepass2android
|
|||||||
Entry.Expires = true;
|
Entry.Expires = true;
|
||||||
Entry.Touch(true);
|
Entry.Touch(true);
|
||||||
RequiresRefresh();
|
RequiresRefresh();
|
||||||
UpdateEntry update = new UpdateEntry(this, App.Kp2a.GetDb(), backupEntry, Entry, null);
|
UpdateEntry update = new UpdateEntry(this, App.Kp2a, backupEntry, Entry, null);
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, update, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, this, update);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
}
|
}
|
||||||
FillData(false);
|
FillData(false);
|
||||||
|
@ -383,11 +383,11 @@ namespace keepass2android
|
|||||||
},closeOrShowError);
|
},closeOrShowError);
|
||||||
|
|
||||||
if ( State.IsNew ) {
|
if ( State.IsNew ) {
|
||||||
runnable = AddEntry.GetInstance(this, App.Kp2a.GetDb(), newEntry, State.ParentGroup, afterAddEntry);
|
runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry);
|
||||||
} else {
|
} else {
|
||||||
runnable = new UpdateEntry(this, App.Kp2a.GetDb(), initialEntry, newEntry, closeOrShowError);
|
runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
|
||||||
}
|
}
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, act, runnable, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, act, runnable);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,8 +177,8 @@ namespace keepass2android
|
|||||||
int groupIconId = data.Extras.GetInt(GroupEditActivity.KeyIconId);
|
int groupIconId = data.Extras.GetInt(GroupEditActivity.KeyIconId);
|
||||||
GroupBaseActivity act = this;
|
GroupBaseActivity act = this;
|
||||||
Handler handler = new Handler();
|
Handler handler = new Handler();
|
||||||
AddGroup task = AddGroup.GetInstance(this, App.Kp2a.GetDb(), groupName, groupIconId, Group, new RefreshTask(handler, this), false);
|
AddGroup task = AddGroup.GetInstance(this, App.Kp2a, groupName, groupIconId, Group, new RefreshTask(handler, this), false);
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, act, task, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, act, task);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
Handler handler = new Handler();
|
Handler handler = new Handler();
|
||||||
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, pass, key, new AfterLoad(handler, this));
|
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, pass, key, new AfterLoad(handler, this));
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, task, UiStringKey.loading_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, this, task);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
62
src/keepass2android/Resources/Resource.designer.cs
generated
62
src/keepass2android/Resources/Resource.designer.cs
generated
@ -1230,6 +1230,12 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f080033
|
// aapt resource value: 0x7f080033
|
||||||
public const int AboutText = 2131230771;
|
public const int AboutText = 2131230771;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f08011e
|
||||||
|
public const int AddingEntry = 2131231006;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f08011f
|
||||||
|
public const int AddingGroup = 2131231007;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080114
|
// aapt resource value: 0x7f080114
|
||||||
public const int AskDeletePermanentlyEntry = 2131230996;
|
public const int AskDeletePermanentlyEntry = 2131230996;
|
||||||
|
|
||||||
@ -1278,29 +1284,32 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f0800f5
|
// aapt resource value: 0x7f0800f5
|
||||||
public const int BinaryDirectory_title = 2131230965;
|
public const int BinaryDirectory_title = 2131230965;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080125
|
// aapt resource value: 0x7f08012f
|
||||||
public const int ChangeLog = 2131231013;
|
public const int ChangeLog = 2131231023;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080124
|
// aapt resource value: 0x7f08012e
|
||||||
public const int ChangeLog_0_7 = 2131231012;
|
public const int ChangeLog_0_7 = 2131231022;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080122
|
// aapt resource value: 0x7f08012c
|
||||||
public const int ChangeLog_0_8 = 2131231010;
|
public const int ChangeLog_0_8 = 2131231020;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080121
|
// aapt resource value: 0x7f08012b
|
||||||
public const int ChangeLog_0_8_1 = 2131231009;
|
public const int ChangeLog_0_8_1 = 2131231019;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080120
|
// aapt resource value: 0x7f08012a
|
||||||
public const int ChangeLog_0_8_2 = 2131231008;
|
public const int ChangeLog_0_8_2 = 2131231018;
|
||||||
|
|
||||||
// aapt resource value: 0x7f08011f
|
// aapt resource value: 0x7f080129
|
||||||
public const int ChangeLog_0_8_3 = 2131231007;
|
public const int ChangeLog_0_8_3 = 2131231017;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080123
|
// aapt resource value: 0x7f08012d
|
||||||
public const int ChangeLog_keptDonate = 2131231011;
|
public const int ChangeLog_keptDonate = 2131231021;
|
||||||
|
|
||||||
// aapt resource value: 0x7f08011e
|
// aapt resource value: 0x7f080128
|
||||||
public const int ChangeLog_title = 2131231006;
|
public const int ChangeLog_title = 2131231016;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080127
|
||||||
|
public const int CheckingTargetFileForChanges = 2131231015;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080048
|
// aapt resource value: 0x7f080048
|
||||||
public const int ClearClipboard = 2131230792;
|
public const int ClearClipboard = 2131230792;
|
||||||
@ -1311,6 +1320,15 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f080034
|
// aapt resource value: 0x7f080034
|
||||||
public const int CreditsText = 2131230772;
|
public const int CreditsText = 2131230772;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080125
|
||||||
|
public const int DecodingDatabase = 2131231013;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080120
|
||||||
|
public const int DeletingEntry = 2131231008;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080121
|
||||||
|
public const int DeletingGroup = 2131231009;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080081
|
// aapt resource value: 0x7f080081
|
||||||
public const int FileNotFound = 2131230849;
|
public const int FileNotFound = 2131230849;
|
||||||
|
|
||||||
@ -1335,6 +1353,9 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f08010c
|
// aapt resource value: 0x7f08010c
|
||||||
public const int OpenKp2aKeyboardAutomatically_title = 2131230988;
|
public const int OpenKp2aKeyboardAutomatically_title = 2131230988;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080126
|
||||||
|
public const int ParsingDatabase = 2131231014;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080023
|
// aapt resource value: 0x7f080023
|
||||||
public const int QuickUnlockDefaultEnabled_key = 2131230755;
|
public const int QuickUnlockDefaultEnabled_key = 2131230755;
|
||||||
|
|
||||||
@ -1389,6 +1410,9 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f0800fb
|
// aapt resource value: 0x7f0800fb
|
||||||
public const int SaveAttachment_doneMessage = 2131230971;
|
public const int SaveAttachment_doneMessage = 2131230971;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080122
|
||||||
|
public const int SettingPassword = 2131231010;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080109
|
// aapt resource value: 0x7f080109
|
||||||
public const int ShowCopyToClipboardNotification_summary = 2131230985;
|
public const int ShowCopyToClipboardNotification_summary = 2131230985;
|
||||||
|
|
||||||
@ -1422,9 +1446,15 @@ namespace keepass2android
|
|||||||
// aapt resource value: 0x7f0800de
|
// aapt resource value: 0x7f0800de
|
||||||
public const int TanExpiresOnUse_title = 2131230942;
|
public const int TanExpiresOnUse_title = 2131230942;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080124
|
||||||
|
public const int TransformingKey = 2131231012;
|
||||||
|
|
||||||
// aapt resource value: 0x7f08002b
|
// aapt resource value: 0x7f08002b
|
||||||
public const int TranslationURL = 2131230763;
|
public const int TranslationURL = 2131230763;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f080123
|
||||||
|
public const int UndoingChanges = 2131231011;
|
||||||
|
|
||||||
// aapt resource value: 0x7f080026
|
// aapt resource value: 0x7f080026
|
||||||
public const int UsageCount_key = 2131230758;
|
public const int UsageCount_key = 2131230758;
|
||||||
|
|
||||||
|
@ -240,6 +240,17 @@
|
|||||||
<string name="suggest_improvements">Suggest or vote for improvements</string>
|
<string name="suggest_improvements">Suggest or vote for improvements</string>
|
||||||
<string name="rate_app">Rate this app</string>
|
<string name="rate_app">Rate this app</string>
|
||||||
<string name="translate_app">Translate KP2A</string>
|
<string name="translate_app">Translate KP2A</string>
|
||||||
|
<string name="AddingEntry">Adding entry…</string>
|
||||||
|
<string name="AddingGroup">Adding group…</string>
|
||||||
|
<string name="DeletingEntry">Deleting entry…</string>
|
||||||
|
<string name="DeletingGroup">Deleting group…</string>
|
||||||
|
<string name="SettingPassword">Setting password…</string>
|
||||||
|
<string name="UndoingChanges">Undoing changes…</string>
|
||||||
|
<string name="TransformingKey">Transforming master key…</string>
|
||||||
|
<string name="DecodingDatabase">Decoding database…</string>
|
||||||
|
<string name="ParsingDatabase">Parsing database…</string>
|
||||||
|
<string name="CheckingTargetFileForChanges">Checking target file for changes…</string>
|
||||||
|
|
||||||
<string name="ChangeLog_title">Change log</string>
|
<string name="ChangeLog_title">Change log</string>
|
||||||
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
|
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
|
||||||
* Username/TAN index displayed in entry list (see settings)\n
|
* Username/TAN index displayed in entry list (see settings)\n
|
||||||
|
@ -71,8 +71,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetPassword sp = new SetPassword(Context, App.Kp2a.GetDb(), pass, keyfile, new AfterSave(this, _finish, new Handler()));
|
SetPassword sp = new SetPassword(Context, App.Kp2a, pass, keyfile, new AfterSave(this, _finish, new Handler()));
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, Context, sp, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, Context, sp);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ using Android.OS;
|
|||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
|
using keepass2android.Io;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
@ -223,6 +224,11 @@ namespace keepass2android
|
|||||||
return new RealProgressDialog(ctx);
|
return new RealProgressDialog(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||||
|
{
|
||||||
|
return new BuiltInFileStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal void OnTerminate()
|
internal void OnTerminate()
|
||||||
{
|
{
|
||||||
|
@ -170,8 +170,7 @@ namespace keepass2android
|
|||||||
CreateDb create = new CreateDb(App.Kp2a, this, IOConnectionInfo.FromPath(filename), collectPassword, true);
|
CreateDb create = new CreateDb(App.Kp2a, this, IOConnectionInfo.FromPath(filename), collectPassword, true);
|
||||||
ProgressTask createTask = new ProgressTask(
|
ProgressTask createTask = new ProgressTask(
|
||||||
App.Kp2a,
|
App.Kp2a,
|
||||||
this, create,
|
this, create);
|
||||||
UiStringKey.progress_create);
|
|
||||||
createTask.Run();
|
createTask.Run();
|
||||||
|
|
||||||
|
|
||||||
@ -313,7 +312,8 @@ namespace keepass2android
|
|||||||
GroupActivity.Launch(_activity, _activity.AppTask);
|
GroupActivity.Launch(_activity, _activity.AppTask);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
IOConnection.DeleteFile(_ioc);
|
App.Kp2a.GetFileStorage(_ioc).DeleteFile(_ioc);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace keepass2android
|
|||||||
String previousUsername = db.KpDatabase.DefaultUserName;
|
String previousUsername = db.KpDatabase.DefaultUserName;
|
||||||
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
|
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
|
||||||
|
|
||||||
SaveDb save = new SaveDb(this, App.Kp2a.GetDb(), new ActionOnFinish( (success, message) =>
|
SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish( (success, message) =>
|
||||||
{
|
{
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@ -82,7 +82,7 @@ namespace keepass2android
|
|||||||
Toast.MakeText(this, message, ToastLength.Long).Show();
|
Toast.MakeText(this, message, ToastLength.Long).Show();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, save, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ namespace keepass2android
|
|||||||
String previousName = db.KpDatabase.Name;
|
String previousName = db.KpDatabase.Name;
|
||||||
db.KpDatabase.Name = e.NewValue.ToString();
|
db.KpDatabase.Name = e.NewValue.ToString();
|
||||||
|
|
||||||
SaveDb save = new SaveDb(this, App.Kp2a.GetDb(), new ActionOnFinish( (success, message) =>
|
SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish( (success, message) =>
|
||||||
{
|
{
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@ -104,7 +104,7 @@ namespace keepass2android
|
|||||||
Toast.MakeText(this, message, ToastLength.Long).Show();
|
Toast.MakeText(this, message, ToastLength.Long).Show();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, save, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,8 +80,8 @@ namespace keepass2android.settings
|
|||||||
PwDatabase.KeyEncryptionRounds = rounds;
|
PwDatabase.KeyEncryptionRounds = rounds;
|
||||||
|
|
||||||
Handler handler = new Handler();
|
Handler handler = new Handler();
|
||||||
SaveDb save = new SaveDb(Context, App.Kp2a.GetDb(), new AfterSave(Context, handler, oldRounds, this));
|
SaveDb save = new SaveDb(Context, App.Kp2a, new AfterSave(Context, handler, oldRounds, this));
|
||||||
ProgressTask pt = new ProgressTask(App.Kp2a, Context, save, UiStringKey.saving_database);
|
ProgressTask pt = new ProgressTask(App.Kp2a, Context, save);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user