first version to have multiple databases open at the same time. needs testing and bug fixing.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Android.App;
|
||||
@@ -33,26 +34,37 @@ namespace keepass2android
|
||||
/// This also contains methods which are UI specific and should be replacable for testing.
|
||||
public interface IKp2aApp : ICertificateValidationHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Locks the currently open database, quicklocking if available (unless false is passed for allowQuickUnlock)
|
||||
/// </summary>
|
||||
void LockDatabase(bool allowQuickUnlock = true);
|
||||
/// <summary>
|
||||
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
|
||||
/// </summary>
|
||||
void Lock(bool allowQuickUnlock);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the specified data as the currently open database, as unlocked.
|
||||
/// </summary>
|
||||
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey,
|
||||
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current database
|
||||
/// </summary>
|
||||
Database GetDb();
|
||||
/// <summary>
|
||||
/// Loads the specified data as the currently open database, as unlocked.
|
||||
/// </summary>
|
||||
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
|
||||
|
||||
/// <summary>
|
||||
/// Tell the app that the file from ioc was opened with keyfile.
|
||||
/// </summary>
|
||||
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
|
||||
|
||||
HashSet<PwGroup> DirtyGroups { get; }
|
||||
|
||||
void MarkAllGroupsAsDirty();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current database
|
||||
/// </summary>
|
||||
Database CurrentDb { get; }
|
||||
|
||||
IEnumerable<Database> OpenDatabases { get; }
|
||||
void CloseDatabase(Database db);
|
||||
|
||||
Database FindDatabaseForGroupId(PwUuid groupKey);
|
||||
Database FindDatabaseForEntryId(PwUuid entryId);
|
||||
|
||||
/// <summary>
|
||||
/// Tell the app that the file from ioc was opened with keyfile.
|
||||
/// </summary>
|
||||
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new database and returns it
|
||||
@@ -111,6 +123,10 @@ namespace keepass2android
|
||||
bool CheckForDuplicateUuids { get; }
|
||||
#if !NoNet
|
||||
ICertificateErrorHandler CertificateErrorHandler { get; }
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -90,8 +90,9 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
||||
<Compile Include="database\edit\AddTemplateEntries.cs" />
|
||||
<Compile Include="database\edit\ChangeTemplateIds.cs" />
|
||||
<Compile Include="database\edit\CopyEntry.cs" />
|
||||
<Compile Include="database\edit\DeleteMultipleItems.cs" />
|
||||
<Compile Include="database\edit\DeleteMultipleItemsFromOneDatabase.cs" />
|
||||
<Compile Include="database\edit\EditGroup.cs" />
|
||||
<Compile Include="database\edit\MoveElements.cs" />
|
||||
<Compile Include="database\KdbDatabaseFormat.cs" />
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace keepass2android
|
||||
/// <summary>
|
||||
/// EqualityComparer implementation to compare PwGroups based on their Id
|
||||
/// </summary>
|
||||
class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
|
||||
public class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
|
||||
{
|
||||
#region IEqualityComparer implementation
|
||||
public bool Equals (PwGroup x, PwGroup y)
|
||||
|
||||
@@ -86,6 +86,11 @@ namespace keepass2android
|
||||
ReadOnlyReason_PreKitKat,
|
||||
ReadOnlyReason_ReadOnlyFlag,
|
||||
ReadOnlyReason_ReadOnlyKitKat,
|
||||
ReadOnlyReason_LocalBackup
|
||||
ReadOnlyReason_LocalBackup,
|
||||
UpdatingTemplateIds,
|
||||
ChangleLegacyTemplateIds_Message,
|
||||
ChangleLegacyTemplateIds_Title,
|
||||
Ok,
|
||||
cancel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
if (fileStorage is CachingFileStorage)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ namespace keepass2android
|
||||
hashingRemoteStream.CopyTo(remoteData);
|
||||
hashingRemoteStream.Close();
|
||||
|
||||
if (!MemUtil.ArraysEqual(_app.GetDb().KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
|
||||
if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
|
||||
{
|
||||
_app.TriggerReload(_context);
|
||||
Finish(true);
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace keepass2android
|
||||
|
||||
public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
|
||||
public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
|
||||
public HashSet<PwGroup> Dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
|
||||
public PwGroup Root;
|
||||
public PwDatabase KpDatabase;
|
||||
public IOConnectionInfo Ioc
|
||||
@@ -49,11 +48,6 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about the last opened entry. Includes the entry but also transformed fields.
|
||||
/// </summary>
|
||||
public PwEntryOutput LastOpenedEntry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// if an OTP key was used, this property tells the location of the OTP auxiliary file.
|
||||
/// Must be set after loading.
|
||||
@@ -74,16 +68,11 @@ namespace keepass2android
|
||||
CanWrite = true; //default
|
||||
}
|
||||
|
||||
private bool _reloadRequested;
|
||||
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
|
||||
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
|
||||
|
||||
public bool ReloadRequested
|
||||
{
|
||||
get { return _reloadRequested; }
|
||||
set { _reloadRequested = value; }
|
||||
}
|
||||
public bool ReloadRequested { get; set; }
|
||||
|
||||
public bool DidOpenFileChange()
|
||||
public bool DidOpenFileChange()
|
||||
{
|
||||
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
|
||||
}
|
||||
@@ -195,8 +184,7 @@ namespace keepass2android
|
||||
|
||||
public void SaveData() {
|
||||
|
||||
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
|
||||
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
|
||||
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
|
||||
{
|
||||
DatabaseFormat.Save(KpDatabase, trans.OpenFile());
|
||||
|
||||
@@ -243,14 +231,6 @@ namespace keepass2android
|
||||
PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids);
|
||||
}
|
||||
|
||||
public void MarkAllGroupsAsDirty() {
|
||||
foreach ( PwGroup group in Groups.Values ) {
|
||||
Dirty.Add(group);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ namespace keepass2android
|
||||
public class PwEntryOutput
|
||||
{
|
||||
private readonly PwEntry _entry;
|
||||
private readonly PwDatabase _db;
|
||||
private readonly Database _db;
|
||||
private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the PwEntryOutput by replacing the placeholders
|
||||
/// </summary>
|
||||
public PwEntryOutput(PwEntry entry, PwDatabase db)
|
||||
public PwEntryOutput(PwEntry entry, Database db)
|
||||
{
|
||||
_entry = entry;
|
||||
_db = db;
|
||||
@@ -34,7 +34,7 @@ namespace keepass2android
|
||||
string GetStringAndReplacePlaceholders(string key)
|
||||
{
|
||||
String value = Entry.Strings.ReadSafe(key);
|
||||
value = SprEngine.Compile(value, new SprContext(Entry, _db, SprCompileFlags.All));
|
||||
value = SprEngine.Compile(value, new SprContext(Entry, _db.KpDatabase, SprCompileFlags.All));
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
if (!(fileStorage is CachingFileStorage))
|
||||
{
|
||||
@@ -70,10 +70,10 @@ namespace keepass2android
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
_saveDb = null;
|
||||
}), false, remoteData);
|
||||
}), _app.CurrentDb, false, remoteData);
|
||||
_saveDb.Run();
|
||||
|
||||
_app.GetDb().MarkAllGroupsAsDirty();
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace keepass2android
|
||||
public class AddEntry : RunnableOnFinish {
|
||||
protected Database Db
|
||||
{
|
||||
get { return _app.GetDb(); }
|
||||
get { return _app.CurrentDb; }
|
||||
}
|
||||
|
||||
private readonly IKp2aApp _app;
|
||||
@@ -43,7 +43,7 @@ namespace keepass2android
|
||||
_app = app;
|
||||
_entry = entry;
|
||||
|
||||
_onFinishToRun = new AfterAdd(ctx, app.GetDb(), entry, OnFinishToRun);
|
||||
_onFinishToRun = new AfterAdd(ctx, app.CurrentDb, entry, app,OnFinishToRun);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace keepass2android
|
||||
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -68,12 +68,13 @@ namespace keepass2android
|
||||
private class AfterAdd : OnFinish {
|
||||
private readonly Database _db;
|
||||
private readonly PwEntry _entry;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public AfterAdd(Activity activity, Database db, PwEntry entry, OnFinish finish):base(activity, finish) {
|
||||
public AfterAdd(Activity activity, Database db, PwEntry entry, IKp2aApp app, OnFinish finish):base(activity, finish) {
|
||||
_db = db;
|
||||
_entry = entry;
|
||||
|
||||
}
|
||||
_app = app;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace keepass2android
|
||||
PwGroup parent = _entry.ParentGroup;
|
||||
|
||||
// Mark parent group dirty
|
||||
_db.Dirty.Add(parent);
|
||||
_app.DirtyGroups.Add(parent);
|
||||
|
||||
// Add entry to global
|
||||
_db.Entries[_entry.Uuid] = _entry;
|
||||
|
||||
@@ -26,9 +26,12 @@ namespace keepass2android
|
||||
public class AddGroup : RunnableOnFinish {
|
||||
internal Database Db
|
||||
{
|
||||
get { return _app.GetDb(); }
|
||||
get { return _app.CurrentDb; }
|
||||
}
|
||||
private IKp2aApp _app;
|
||||
|
||||
public IKp2aApp App { get => _app; }
|
||||
|
||||
private IKp2aApp _app;
|
||||
private readonly String _name;
|
||||
private readonly int _iconId;
|
||||
private readonly PwUuid _groupCustomIconId;
|
||||
@@ -69,7 +72,7 @@ namespace keepass2android
|
||||
Parent.AddGroup(Group, true);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -86,7 +89,7 @@ namespace keepass2android
|
||||
|
||||
if ( Success ) {
|
||||
// Mark parent group dirty
|
||||
_addGroup.Db.Dirty.Add(_addGroup.Parent);
|
||||
_addGroup.App.DirtyGroups.Add(_addGroup.Parent);
|
||||
|
||||
// Add group to global list
|
||||
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace keepass2android
|
||||
{
|
||||
public class AddTemplateEntries : RunnableOnFinish {
|
||||
|
||||
class TemplateEntry
|
||||
public class TemplateEntry
|
||||
{
|
||||
public UiStringKey Title { get; set; }
|
||||
public PwIcon Icon { get; set; }
|
||||
@@ -47,11 +47,12 @@ namespace keepass2android
|
||||
void AddToEntry(IKp2aApp app, PwEntry entry, int position);
|
||||
}
|
||||
|
||||
internal enum FieldType
|
||||
public enum FieldType
|
||||
{
|
||||
Inline, ProtectedInline
|
||||
}
|
||||
internal enum SpecialFieldKey
|
||||
|
||||
public enum SpecialFieldKey
|
||||
{
|
||||
ExpDate, OverrideUrl, Tags
|
||||
}
|
||||
@@ -125,7 +126,7 @@ namespace keepass2android
|
||||
|
||||
protected Database Db
|
||||
{
|
||||
get { return _app.GetDb(); }
|
||||
get { return _app.CurrentDb; }
|
||||
}
|
||||
|
||||
private readonly IKp2aApp _app;
|
||||
@@ -140,7 +141,7 @@ namespace keepass2android
|
||||
//_onFinishToRun = new AfterAdd(this, OnFinishToRun);
|
||||
}
|
||||
|
||||
static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
|
||||
public static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
|
||||
{
|
||||
new TemplateEntry()
|
||||
{
|
||||
@@ -285,12 +286,23 @@ namespace keepass2android
|
||||
|
||||
};
|
||||
|
||||
public static bool ContainsAllTemplates(IKp2aApp app)
|
||||
public static bool ContainsAllTemplates(Database db)
|
||||
{
|
||||
return TemplateEntries.All(t => app.GetDb().Entries.ContainsKey(t.Uuid));
|
||||
return TemplateEntries.All(t =>
|
||||
{
|
||||
string hexId = t.Uuid.ToHexString();
|
||||
|
||||
return db.Entries.Any(kvp => kvp.Key.Equals(t.Uuid) ||
|
||||
kvp.Value.Strings.ReadSafe(TemplateIdStringKey) == hexId);
|
||||
});
|
||||
}
|
||||
|
||||
public override void Run() {
|
||||
public static string TemplateIdStringKey
|
||||
{
|
||||
get { return "KP2A_TemplateId"; }
|
||||
}
|
||||
|
||||
public override void Run() {
|
||||
StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
|
||||
|
||||
List<PwEntry> addedEntries;
|
||||
@@ -298,10 +310,10 @@ namespace keepass2android
|
||||
|
||||
if (addedEntries.Any())
|
||||
{
|
||||
_app.GetDb().Dirty.Add(templateGroup);
|
||||
_app.DirtyGroups.Add(templateGroup);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -315,37 +327,38 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
PwGroup templateGroup;
|
||||
if (!_app.GetDb().Groups.TryGetValue(_app.GetDb().KpDatabase.EntryTemplatesGroup, out templateGroup))
|
||||
if (!_app.CurrentDb.Groups.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup))
|
||||
{
|
||||
//create template group
|
||||
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
|
||||
_app.GetDb().KpDatabase.RootGroup.AddGroup(templateGroup, true);
|
||||
_app.GetDb().KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
|
||||
_app.GetDb().KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
|
||||
_app.GetDb().Dirty.Add(_app.GetDb().KpDatabase.RootGroup);
|
||||
_app.GetDb().Groups[templateGroup.Uuid] = templateGroup;
|
||||
_app.CurrentDb.KpDatabase.RootGroup.AddGroup(templateGroup, true);
|
||||
_app.CurrentDb.KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
|
||||
_app.CurrentDb.KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
|
||||
_app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup);
|
||||
_app.CurrentDb.Groups[templateGroup.Uuid] = templateGroup;
|
||||
}
|
||||
addedEntries = new List<PwEntry>();
|
||||
|
||||
foreach (var template in TemplateEntries)
|
||||
{
|
||||
if (_app.GetDb().Entries.ContainsKey(template.Uuid))
|
||||
if (_app.CurrentDb.Entries.ContainsKey(template.Uuid))
|
||||
continue;
|
||||
PwEntry entry = CreateEntry(template);
|
||||
templateGroup.AddEntry(entry, true);
|
||||
addedEntries.Add(entry);
|
||||
_app.GetDb().Entries[entry.Uuid] = entry;
|
||||
_app.CurrentDb.Entries[entry.Uuid] = entry;
|
||||
}
|
||||
return templateGroup;
|
||||
}
|
||||
|
||||
private PwEntry CreateEntry(TemplateEntry template)
|
||||
{
|
||||
PwEntry entry = new PwEntry(false, true);
|
||||
entry.Uuid = template.Uuid;
|
||||
PwEntry entry = new PwEntry(true, true);
|
||||
|
||||
entry.IconId = template.Icon;
|
||||
entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, _app.GetResourceString(template.Title)));
|
||||
entry.Strings.Set("_etm_template", new ProtectedString(false, "1"));
|
||||
entry.Strings.Set(TemplateIdStringKey, new ProtectedString(false, template.Uuid.ToHexString()));
|
||||
int position = 0;
|
||||
foreach (var field in template.Fields)
|
||||
{
|
||||
@@ -373,8 +386,12 @@ namespace keepass2android
|
||||
base.Run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static bool IsTemplateId(PwUuid pwUuid)
|
||||
{
|
||||
return TemplateEntries.Any(te => te.Uuid.Equals(pwUuid));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
76
src/Kp2aBusinessLogic/database/edit/ChangeTemplateIds.cs
Normal file
76
src/Kp2aBusinessLogic/database/edit/ChangeTemplateIds.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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;
|
||||
using KeePassLib.Security;
|
||||
|
||||
namespace keepass2android.database.edit
|
||||
{
|
||||
public class ChangeTemplateIds: RunnableOnFinish
|
||||
{
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly Database _db;
|
||||
private string _etmTemplateUuid { get { return "_etm_template_uuid"; } }
|
||||
public static string TemplateIdStringKey
|
||||
{
|
||||
get { return "KP2A_TemplateId"; }
|
||||
}
|
||||
|
||||
public ChangeTemplateIds(Activity activeActivity, IKp2aApp app, Database db, OnFinish finish) : base(activeActivity, finish)
|
||||
{
|
||||
_app = app;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
StatusLogger.UpdateMessage(UiStringKey.UpdatingTemplateIds);
|
||||
Dictionary<string, string> uuidMap = new Dictionary<string, string>();
|
||||
foreach (var templateEntry in AddTemplateEntries.TemplateEntries)
|
||||
{
|
||||
PwEntry entry;
|
||||
if (_db.Entries.TryGetValue(templateEntry.Uuid, out entry))
|
||||
{
|
||||
PwUuid oldUuid = entry.Uuid;
|
||||
entry.Uuid = new PwUuid(true);
|
||||
uuidMap[oldUuid.ToHexString()] = entry.Uuid.ToHexString();
|
||||
entry.Strings.Set(TemplateIdStringKey,new ProtectedString(false, oldUuid.ToHexString()));
|
||||
_db.Entries.Remove(oldUuid);
|
||||
_db.Entries[entry.Uuid] = entry;
|
||||
}
|
||||
}
|
||||
foreach (var entry in _db.Entries.Values)
|
||||
{
|
||||
string templateUuid = entry.Strings.ReadSafe(_etmTemplateUuid);
|
||||
if (templateUuid != null)
|
||||
{
|
||||
string newTemplateUuid;
|
||||
if (uuidMap.TryGetValue(templateUuid, out newTemplateUuid))
|
||||
{
|
||||
entry.Strings.Set(_etmTemplateUuid, new ProtectedString(false, newTemplateUuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uuidMap.Any())
|
||||
{
|
||||
SaveDb save = new SaveDb( ActiveActivity, _app, _db, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnFinishToRun?.Run();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace keepass2android
|
||||
addTemplates.AddTemplates(out addedEntries);
|
||||
|
||||
// Commit changes
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||
SaveDb save = new SaveDb(_ctx, _app, db, OnFinishToRun, _dontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
_onFinishToRun = null;
|
||||
save.Run();
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace keepass2android
|
||||
|
||||
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
|
||||
Ctx = activiy;
|
||||
Db = app.GetDb();
|
||||
Db = app.FindDatabaseForEntryId(entry.Uuid);
|
||||
_entry = entry;
|
||||
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace keepass2android
|
||||
{
|
||||
get
|
||||
{
|
||||
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
|
||||
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace keepass2android
|
||||
*/
|
||||
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
|
||||
{
|
||||
base.SetMembers(activity, app.GetDb());
|
||||
base.SetMembers(activity, app.FindDatabaseForGroupId(group.Uuid));
|
||||
|
||||
_group = group;
|
||||
DontSave = dontSave;
|
||||
@@ -58,7 +58,7 @@ namespace keepass2android
|
||||
{
|
||||
get
|
||||
{
|
||||
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
|
||||
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class DeleteMultipleItems : DeleteRunnable
|
||||
public class DeleteMultipleItemsFromOneDatabase : DeleteRunnable
|
||||
{
|
||||
private readonly List<IStructureItem> _elementsToDelete;
|
||||
private readonly bool _canRecycle;
|
||||
|
||||
public DeleteMultipleItems(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
|
||||
public DeleteMultipleItemsFromOneDatabase(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
|
||||
: base(activity, finish, app)
|
||||
{
|
||||
_elementsToDelete = elementsToDelete;
|
||||
@@ -26,7 +26,7 @@ namespace keepass2android
|
||||
private bool DetermineCanRecycle()
|
||||
{
|
||||
Android.Util.Log.Debug("KP2A", "CanRecycle?");
|
||||
if (!App.GetDb().DatabaseFormat.CanRecycle)
|
||||
if (!Db.DatabaseFormat.CanRecycle)
|
||||
{
|
||||
Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format.");
|
||||
return false;
|
||||
@@ -130,6 +130,7 @@ namespace keepass2android
|
||||
DeletePermanently = true;
|
||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||
pt.Run();
|
||||
|
||||
},
|
||||
(dlgSender, dlgEvt) =>
|
||||
{
|
||||
@@ -215,11 +216,11 @@ namespace keepass2android
|
||||
if (success)
|
||||
{
|
||||
foreach (var g in touchedGroups)
|
||||
Db.Dirty.Add(g);
|
||||
App.DirtyGroups.Add(g);
|
||||
foreach (var g in permanentlyDeletedGroups)
|
||||
{
|
||||
//remove groups from global lists if present there
|
||||
Db.Dirty.Remove(g);
|
||||
//remove groups from global lists if present there
|
||||
App.DirtyGroups.Remove(g);
|
||||
Db.Groups.Remove(g.Uuid);
|
||||
}
|
||||
|
||||
@@ -227,12 +228,12 @@ namespace keepass2android
|
||||
else
|
||||
{
|
||||
// Let's not bother recovering from a failure to save. It is too much work.
|
||||
App.LockDatabase(false);
|
||||
App.Lock(false);
|
||||
}
|
||||
}, OnFinishToRun);
|
||||
|
||||
// Commit database
|
||||
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
|
||||
SaveDb save = new SaveDb(Ctx, App, Db, OnFinishToRun, false);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
|
||||
|
||||
@@ -26,9 +26,12 @@ namespace keepass2android
|
||||
public class EditGroup : RunnableOnFinish {
|
||||
internal Database Db
|
||||
{
|
||||
get { return _app.GetDb(); }
|
||||
get { return _app.FindDatabaseForGroupId(Group.Uuid); }
|
||||
}
|
||||
private IKp2aApp _app;
|
||||
|
||||
public IKp2aApp App { get => _app; }
|
||||
|
||||
private IKp2aApp _app;
|
||||
private readonly String _name;
|
||||
private readonly PwIcon _iconId;
|
||||
private readonly PwUuid _customIconId;
|
||||
@@ -57,7 +60,7 @@ namespace keepass2android
|
||||
Group.Touch(true);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, Db, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -76,10 +79,10 @@ namespace keepass2android
|
||||
|
||||
if ( Success ) {
|
||||
// Mark parent group dirty
|
||||
_editGroup.Db.Dirty.Add(_editGroup.Group.ParentGroup);
|
||||
_editGroup.App.DirtyGroups.Add(_editGroup.Group.ParentGroup);
|
||||
} else
|
||||
{
|
||||
_editGroup._app.LockDatabase(false);
|
||||
_editGroup._app.Lock(false);
|
||||
}
|
||||
|
||||
base.Run();
|
||||
|
||||
@@ -21,6 +21,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using keepass2android.database.edit;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Keys;
|
||||
using KeePassLib.Serialization;
|
||||
@@ -47,7 +48,8 @@ namespace keepass2android
|
||||
|
||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||
}
|
||||
|
||||
|
||||
protected bool success = false;
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
@@ -78,6 +80,10 @@ namespace keepass2android
|
||||
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
|
||||
_format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_ioc));
|
||||
TryLoad(databaseStream);
|
||||
|
||||
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -125,7 +131,7 @@ namespace keepass2android
|
||||
/// </summary>
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
private void TryLoad(MemoryStream databaseStream)
|
||||
Database TryLoad(MemoryStream databaseStream)
|
||||
{
|
||||
//create a copy of the stream so we can try again if we get an exception which indicates we should change parameters
|
||||
//This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors.
|
||||
@@ -138,19 +144,89 @@ namespace keepass2android
|
||||
//now let's go:
|
||||
try
|
||||
{
|
||||
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format);
|
||||
Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format);
|
||||
Kp2aLog.Log("LoadDB OK");
|
||||
|
||||
//make sure the stored access time for the actual file is more recent than that of its backup
|
||||
Thread.Sleep(10);
|
||||
SaveFileData(_ioc, _keyfileOrProvider);
|
||||
|
||||
Finish(true, _format.SuccessMessage);
|
||||
|
||||
bool hasLegacyTemplateIds = false;
|
||||
//make sure we never have entries with same Uuids
|
||||
foreach (var entryKey in newDb.Entries.Keys)
|
||||
{
|
||||
foreach (Database otherDb in _app.OpenDatabases)
|
||||
{
|
||||
if (otherDb == newDb)
|
||||
continue;
|
||||
if (otherDb.Entries.ContainsKey(entryKey))
|
||||
{
|
||||
if (AddTemplateEntries.IsTemplateId(entryKey))
|
||||
{
|
||||
hasLegacyTemplateIds = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_app.CloseDatabase(newDb);
|
||||
throw new Exception("Database contains entry id " + entryKey.ToHexString() + "(" +
|
||||
newDb.Entries[entryKey].Strings.ReadSafe(PwDefs.TitleField)
|
||||
+ ") which is already contained in " +
|
||||
_app.GetFileStorage(otherDb.Ioc).GetDisplayName(otherDb.Ioc) +
|
||||
"! Please close the other database before opening this one.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var groupKey in newDb.Groups.Keys)
|
||||
{
|
||||
foreach (Database otherDb in _app.OpenDatabases)
|
||||
{
|
||||
if (otherDb == newDb)
|
||||
continue;
|
||||
if (otherDb.Groups.ContainsKey(groupKey))
|
||||
{
|
||||
throw new Exception("Database contains group id " + groupKey.ToHexString() + "(" +
|
||||
newDb.Groups[groupKey].Name + ") which is already contained in " +
|
||||
_app.GetFileStorage(otherDb.Ioc).GetDisplayName(otherDb.Ioc) +
|
||||
"! Please close the other database before opening this one.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLegacyTemplateIds)
|
||||
{
|
||||
_app.AskYesNoCancel(UiStringKey.ChangleLegacyTemplateIds_Title, UiStringKey.ChangleLegacyTemplateIds_Message,UiStringKey.Ok, UiStringKey.cancel,
|
||||
/*yes*/
|
||||
(sender, args) =>
|
||||
{
|
||||
ChangeTemplateIds cti = new ChangeTemplateIds(ActiveActivity, _app, newDb, new ActionOnFinish(ActiveActivity, (b, message, activity) => Finish(b, message)));
|
||||
cti.Run();
|
||||
},
|
||||
/*no*/
|
||||
(sender, args) =>
|
||||
{
|
||||
_app.CloseDatabase(newDb);
|
||||
Finish(false);
|
||||
},
|
||||
null,
|
||||
ActiveActivity
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
Finish(true, _format.SuccessMessage);
|
||||
return newDb;
|
||||
}
|
||||
catch (OldFormatException)
|
||||
{
|
||||
_format = new KdbDatabaseFormat(_app);
|
||||
TryLoad(databaseStream);
|
||||
return TryLoad(databaseStream);
|
||||
}
|
||||
catch (InvalidCompositeKeyException)
|
||||
{
|
||||
@@ -162,7 +238,7 @@ namespace keepass2android
|
||||
//retry without password:
|
||||
_compositeKey.RemoveUserKey(passwordKey);
|
||||
//retry:
|
||||
TryLoad(databaseStream);
|
||||
return TryLoad(databaseStream);
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ namespace keepass2android.database.edit
|
||||
foreach (var elementToMove in _elementsToMove)
|
||||
{
|
||||
|
||||
_app.GetDb().Dirty.Add(elementToMove.ParentGroup);
|
||||
|
||||
_app.DirtyGroups.Add(elementToMove.ParentGroup);
|
||||
//TODO is this safe when transferring between databases?
|
||||
PwGroup pgParent = elementToMove.ParentGroup;
|
||||
if (pgParent != _targetGroup)
|
||||
{
|
||||
@@ -87,12 +87,15 @@ namespace keepass2android.database.edit
|
||||
{
|
||||
if (!success)
|
||||
{ // Let's not bother recovering from a failure.
|
||||
_app.LockDatabase(false);
|
||||
_app.Lock(false);
|
||||
}
|
||||
}, OnFinishToRun);
|
||||
|
||||
//Unchecked
|
||||
//TODO save the right database
|
||||
|
||||
// Save
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, false);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, false);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ namespace keepass2android
|
||||
|
||||
public class SaveDb : RunnableOnFinish {
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly bool _dontSave;
|
||||
private readonly Database _db;
|
||||
private readonly bool _dontSave;
|
||||
|
||||
/// <summary>
|
||||
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
|
||||
@@ -43,9 +44,10 @@ namespace keepass2android
|
||||
private readonly Context _ctx;
|
||||
private Thread _workerThread;
|
||||
|
||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish, bool dontSave)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_db = db;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_dontSave = dontSave;
|
||||
@@ -59,21 +61,23 @@ namespace keepass2android
|
||||
/// <param name="finish"></param>
|
||||
/// <param name="dontSave"></param>
|
||||
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
|
||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave, Stream streamForOrigFile)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, Database db, bool dontSave, Stream streamForOrigFile)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_db = db;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_dontSave = dontSave;
|
||||
_streamForOrigFile = streamForOrigFile;
|
||||
}
|
||||
|
||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_dontSave = false;
|
||||
_db = db;
|
||||
_dontSave = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +88,7 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_app.GetDb().CanWrite == false)
|
||||
if (_db.CanWrite == false)
|
||||
{
|
||||
//this should only happen if there is a problem in the UI so that the user sees an edit interface.
|
||||
Finish(false,"Cannot save changes. File is read-only!");
|
||||
@@ -92,13 +96,13 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
StatusLogger.UpdateMessage(UiStringKey.saving_database);
|
||||
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||
IOConnectionInfo ioc = _db.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
|
||||
if (_streamForOrigFile == null)
|
||||
{
|
||||
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|
||||
|| (_app.GetDb().KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
||||
|| (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
||||
{
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
Finish(true);
|
||||
@@ -109,8 +113,8 @@ namespace keepass2android
|
||||
|
||||
if (
|
||||
(_streamForOrigFile != null)
|
||||
|| fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection
|
||||
|| (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
|
||||
|| fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) //first try to use the fast change detection
|
||||
|| (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
|
||||
)
|
||||
{
|
||||
|
||||
@@ -217,13 +221,13 @@ namespace keepass2android
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
|
||||
|
||||
PwDatabase pwImp = new PwDatabase();
|
||||
PwDatabase pwDatabase = _app.GetDb().KpDatabase;
|
||||
PwDatabase pwDatabase = _db.KpDatabase;
|
||||
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
|
||||
pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
|
||||
pwImp.MasterKey = pwDatabase.MasterKey;
|
||||
var stream = GetStreamForBaseFile(fileStorage, ioc);
|
||||
|
||||
_app.GetDb().DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null);
|
||||
_db.DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null);
|
||||
|
||||
|
||||
pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
|
||||
@@ -249,8 +253,8 @@ namespace keepass2android
|
||||
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||
{
|
||||
StatusLogger.UpdateSubMessage("");
|
||||
_app.GetDb().SaveData();
|
||||
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
||||
_db.SaveData();
|
||||
_db.LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
||||
}
|
||||
|
||||
public byte[] HashOriginalFile(IOConnectionInfo iocFile)
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace keepass2android
|
||||
public override void Run ()
|
||||
{
|
||||
StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
|
||||
PwDatabase pm = _app.GetDb().KpDatabase;
|
||||
PwDatabase pm = _app.CurrentDb.KpDatabase;
|
||||
CompositeKey newKey = new CompositeKey ();
|
||||
if (String.IsNullOrEmpty (_password) == false) {
|
||||
newKey.AddUserKey (new KcpPassword (_password));
|
||||
@@ -74,7 +74,7 @@ namespace keepass2android
|
||||
|
||||
// Save Database
|
||||
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, _dontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace keepass2android
|
||||
|
||||
public override void Run() {
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace keepass2android
|
||||
if ( parent != null ) {
|
||||
|
||||
// Mark parent group dirty
|
||||
_app.GetDb().Dirty.Add(parent);
|
||||
_app.DirtyGroups.Add(parent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user