first version to have multiple databases open at the same time. needs testing and bug fixing.

This commit is contained in:
Philipp Crocoll
2018-10-16 06:33:00 +02:00
parent 8a993b7dcb
commit a2dab72b25
73 changed files with 1329 additions and 669 deletions

View File

@@ -485,12 +485,6 @@ namespace KeePassLib
set { m_pbHashOfLastIO = value; }
}
public bool UseFileTransactions
{
get { return m_bUseFileTransactions; }
set { m_bUseFileTransactions = value; }
}
public bool UseFileLocks
{
get { return m_bUseFileLocks; }

View File

@@ -360,5 +360,12 @@ namespace KeePassLib.Serialization
m_ioCredProtMode = IOCredProtMode.None;
}
}
public bool IsSameFileAs(IOConnectionInfo other)
{
if (other == null)
return false;
return Path == other.Path && UserName == other.UserName;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Android.App;
@@ -34,20 +35,31 @@ namespace keepass2android
public interface IKp2aApp : ICertificateValidationHandler
{
/// <summary>
/// Locks the currently open database, quicklocking if available (unless false is passed for allowQuickUnlock)
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
/// </summary>
void LockDatabase(bool allowQuickUnlock = true);
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);
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
HashSet<PwGroup> DirtyGroups { get; }
void MarkAllGroupsAsDirty();
/// <summary>
/// Returns the current database
/// </summary>
Database GetDb();
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.
@@ -111,6 +123,10 @@ namespace keepass2android
bool CheckForDuplicateUuids { get; }
#if !NoNet
ICertificateErrorHandler CertificateErrorHandler { get; }
#endif
}
}

View File

@@ -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" />

View File

@@ -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)

View File

@@ -86,6 +86,11 @@ namespace keepass2android
ReadOnlyReason_PreKitKat,
ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup
ReadOnlyReason_LocalBackup,
UpdatingTemplateIds,
ChangleLegacyTemplateIds_Message,
ChangleLegacyTemplateIds_Title,
Ok,
cancel
}
}

View File

@@ -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);

View File

@@ -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,14 +68,9 @@ namespace keepass2android
CanWrite = true; //default
}
private bool _reloadRequested;
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
public bool ReloadRequested
{
get { return _reloadRequested; }
set { _reloadRequested = value; }
}
public bool ReloadRequested { get; set; }
public bool DidOpenFileChange()
{
@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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
{

View File

@@ -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,11 +68,12 @@ 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;

View File

@@ -26,8 +26,11 @@ namespace keepass2android
public class AddGroup : RunnableOnFinish {
internal Database Db
{
get { return _app.GetDb(); }
get { return _app.CurrentDb; }
}
public IKp2aApp App { get => _app; }
private IKp2aApp _app;
private readonly String _name;
private readonly int _iconId;
@@ -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;

View File

@@ -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,9 +286,20 @@ 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 static string TemplateIdStringKey
{
get { return "KP2A_TemplateId"; }
}
public override void Run() {
@@ -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)
{
@@ -375,6 +388,10 @@ namespace keepass2android
}
public static bool IsTemplateId(PwUuid pwUuid)
{
return TemplateEntries.Any(te => te.Uuid.Equals(pwUuid));
}
}
}

View 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();
}
}
}
}

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
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();

View File

@@ -26,8 +26,11 @@ namespace keepass2android
public class EditGroup : RunnableOnFinish {
internal Database Db
{
get { return _app.GetDb(); }
get { return _app.FindDatabaseForGroupId(Group.Uuid); }
}
public IKp2aApp App { get => _app; }
private IKp2aApp _app;
private readonly String _name;
private readonly PwIcon _iconId;
@@ -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();

View File

@@ -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;
@@ -48,6 +49,7 @@ 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);
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;
}

View File

@@ -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();
}

View File

@@ -34,6 +34,7 @@ namespace keepass2android
public class SaveDb : RunnableOnFinish {
private readonly IKp2aApp _app;
private readonly Database _db;
private readonly bool _dontSave;
/// <summary>
@@ -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,20 +61,22 @@ 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;
_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)

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -26,7 +26,7 @@ namespace keepass2android
b.SetMessage(Resource.String.killed_by_os);
b.SetPositiveButton(Android.Resource.String.Ok, delegate
{
Intent i = new Intent(this, typeof(FileSelectActivity));
Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
i.AddFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
StartActivity(i);

View File

@@ -107,6 +107,11 @@ namespace keepass2android
i.PutExtra(KeyEntry, pw.Uuid.ToHexString());
i.PutExtra(KeyRefreshPos, pos);
if (!App.Kp2a.CurrentDb.Entries.ContainsKey(pw.Uuid))
{
App.Kp2a.CurrentDb = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
}
if (flags != null)
i.SetFlags((ActivityFlags) flags);
@@ -167,7 +172,7 @@ namespace keepass2android
protected void SetupEditButtons() {
View edit = FindViewById(Resource.Id.entry_edit);
if (App.Kp2a.GetDb().CanWrite)
if (App.Kp2a.CurrentDb.CanWrite)
{
edit.Visibility = ViewStates.Visible;
edit.Click += (sender, e) =>
@@ -265,9 +270,9 @@ namespace keepass2android
//update the Entry output in the App database and notify the CopyToClipboard service
if (App.Kp2a.GetDb()?.LastOpenedEntry != null)
if (App.Kp2a.LastOpenedEntry != null)
{
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value));
App.Kp2a.LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value));
Intent updateKeyboardIntent = new Intent(this, typeof(CopyToClipboardService));
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
updateKeyboardIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
@@ -323,7 +328,7 @@ namespace keepass2android
i.SetPackage(pluginPackage);
i.PutExtra(Strings.ExtraActionData, bundleExtra);
i.PutExtra(Strings.ExtraSender, PackageName);
PluginHost.AddEntryToIntent(i, App.Kp2a.GetDb().LastOpenedEntry);
PluginHost.AddEntryToIntent(i, App.Kp2a.LastOpenedEntry);
var menuOption = new PluginMenuOption()
{
@@ -389,7 +394,7 @@ namespace keepass2android
SetEntryView();
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
// Likely the app has been killed exit the activity
if (db == null || (App.Kp2a.QuickLocked))
{
@@ -428,7 +433,7 @@ namespace keepass2android
SetupEditButtons();
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
App.Kp2a.LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.CurrentDb);
_pluginActionReceiver = new PluginActionReceiver(this);
RegisterReceiver(_pluginActionReceiver, new IntentFilter(Strings.ActionAddEntryAction));
@@ -508,8 +513,8 @@ namespace keepass2android
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
bool hasExtras = false;
IEditMode editMode = new DefaultEdit();
if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.GetDb(), this.Entry))
editMode = new KpEntryTemplatedEdit(App.Kp2a.GetDb(), this.Entry);
if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.CurrentDb, this.Entry))
editMode = new KpEntryTemplatedEdit(App.Kp2a.CurrentDb, this.Entry);
foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key))))
{
if (editMode.IsVisible(key))
@@ -936,7 +941,7 @@ namespace keepass2android
private void PopulateStandardText(List<int> viewIds, int containerViewId, String key)
{
String value = Entry.Strings.ReadSafe(key);
value = SprEngine.Compile(value, new SprContext(Entry, App.Kp2a.GetDb().KpDatabase, SprCompileFlags.All));
value = SprEngine.Compile(value, new SprContext(Entry, App.Kp2a.CurrentDb.KpDatabase, SprCompileFlags.All));
PopulateText(viewIds, containerViewId, value);
_stringViews.Add(key, new StandardStringView(viewIds, containerViewId, this));
}
@@ -1012,7 +1017,7 @@ namespace keepass2android
{
((IOfflineSwitchable)fileStorage).IsOffline = false;
}
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetDb().KpDatabase.UseFileTransactions))
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
{
Stream sOut = writeTransaction.OpenFile();
@@ -1173,7 +1178,7 @@ namespace keepass2android
return true;
case Resource.Id.menu_lock:
App.Kp2a.LockDatabase();
App.Kp2a.Lock();
return true;
case Android.Resource.Id.Home:
//Currently the action bar only displays the home button when we come from a previous activity.
@@ -1264,7 +1269,7 @@ namespace keepass2android
public void AddEntryToIntent(Intent intent)
{
PluginHost.AddEntryToIntent(intent, App.Kp2a.GetDb().LastOpenedEntry);
PluginHost.AddEntryToIntent(intent, App.Kp2a.LastOpenedEntry);
}
public void CloseAfterTaskComplete()

View File

@@ -120,7 +120,7 @@ namespace keepass2android
} else
{
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
App.Kp2a.EntryEditActivityState = new EntryEditActivityState();
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
@@ -199,7 +199,7 @@ namespace keepass2android
if (State.SelectedIcon)
{
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.GetDb().KpDatabase, (PwIcon)State.SelectedIconId, State.SelectedCustomIconId, false);
App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon)State.SelectedIconId, State.SelectedCustomIconId, false);
}
iconButton.Click += (sender, evt) => {
UpdateEntryFromUi(State.Entry);
@@ -371,7 +371,7 @@ namespace keepass2android
private void SetAddExtraStringEnabled()
{
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveCustomFields)
if (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveCustomFields)
((Button)FindViewById(Resource.Id.add_advanced)).Visibility = ViewStates.Gone;
}
@@ -393,7 +393,7 @@ namespace keepass2android
void SaveEntry()
{
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
EntryEditActivity act = this;
if (!ValidateBeforeSaving())
@@ -498,7 +498,7 @@ namespace keepass2android
void UpdateEntryFromUi(PwEntry entry)
{
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
EntryEditActivity act = this;
entry.Strings.Set(PwDefs.TitleField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectTitle,
@@ -753,7 +753,7 @@ namespace keepass2android
String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password");
byte[] password = StrUtil.Utf8.GetBytes(generatedPassword);
State.Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(App.Kp2a.GetDb().KpDatabase.MemoryProtection.ProtectPassword,
State.Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(App.Kp2a.CurrentDb.KpDatabase.MemoryProtection.ProtectPassword,
password));
MemUtil.ZeroByteArray(password);
@@ -792,7 +792,7 @@ namespace keepass2android
{
String key = pair.Key;
String label = key;
if ((String.IsNullOrEmpty(label) || (!App.Kp2a.GetDb().DatabaseFormat.SupportsAttachmentKeys)))
if ((String.IsNullOrEmpty(label) || (!App.Kp2a.CurrentDb.DatabaseFormat.SupportsAttachmentKeys)))
{
label = "<attachment>";
}
@@ -820,7 +820,7 @@ namespace keepass2android
addBinaryButton.Enabled = true;
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveMultipleAttachments)
if (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveMultipleAttachments)
addBinaryButton.Enabled = !State.Entry.Binaries.Any();
addBinaryButton.Click += (sender, e) =>
{
@@ -921,7 +921,7 @@ namespace keepass2android
{
if (_additionalKeys == null)
{
_additionalKeys = App.Kp2a.GetDb().Entries
_additionalKeys = App.Kp2a.CurrentDb.Entries
.Select(kvp => kvp.Value)
.SelectMany(x => x.Strings.GetKeys().Where(k => !PwDefs.IsStandardField(k)))
.Where(k => (k != null) && !k.StartsWith("_etm_") )
@@ -999,7 +999,7 @@ namespace keepass2android
{
_editModeHiddenViews = new List<View>();
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false);
App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.CurrentDb.KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false);
PopulateText(Resource.Id.entry_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField));
PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
@@ -1028,7 +1028,7 @@ namespace keepass2android
PopulateBinaries();
if (App.Kp2a.GetDb().DatabaseFormat.SupportsOverrideUrl)
if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsOverrideUrl)
{
PopulateText(Resource.Id.entry_override_url, State.Entry.OverrideUrl);
}
@@ -1037,7 +1037,7 @@ namespace keepass2android
FindViewById(Resource.Id.entry_override_url_container).Visibility = ViewStates.Gone;
}
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTags)
if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsTags)
{
PopulateText(Resource.Id.entry_tags, StrUtil.TagsToString(State.Entry.Tags, true));
}

View File

@@ -107,7 +107,7 @@ namespace keepass2android
public override void Run()
{
StatusLogger.UpdateMessage(UiStringKey.exporting_database);
var pd = _app.GetDb().KpDatabase;
var pd = _app.CurrentDb.KpDatabase;
PwExportInfo pwInfo = new PwExportInfo(pd.RootGroup, pd, true);
try
@@ -117,7 +117,7 @@ namespace keepass2android
{
((IOfflineSwitchable) fileStorage).IsOffline = false;
}
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetDb().KpDatabase.UseFileTransactions))
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
{
Stream sOut = writeTransaction.OpenFile();
_fileFormat.Export(pwInfo, sOut, new NullStatusLogger());

View File

@@ -64,7 +64,7 @@ namespace keepass2android
SetContentView(Resource.Layout.fingerprint_setup);
Enum.TryParse(
PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""),
PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, ""),
out _unlockMode);
_fpIcon = FindViewById<ImageView>(Resource.Id.fingerprint_icon);
@@ -174,7 +174,7 @@ namespace keepass2android
string CurrentPreferenceKey
{
get { return App.Kp2a.GetDb().CurrentFingerprintPrefKey; }
get { return App.Kp2a.CurrentDb.CurrentFingerprintPrefKey; }
}
private void StoreUnlockMode()
@@ -188,13 +188,13 @@ namespace keepass2android
{
if (_unlockMode == FingerprintUnlockMode.FullUnlock)
{
var userKey = App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey<KcpPassword>();
var userKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey.GetUserKey<KcpPassword>();
_enc.StoreEncrypted(userKey != null ? userKey.Password.ReadString() : "", CurrentPreferenceKey, edit);
}
else
_enc.StoreEncrypted("QuickUnlock" /*some dummy data*/, CurrentPreferenceKey, edit);
}
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.Commit();
}
@@ -261,7 +261,7 @@ namespace keepass2android
UpdateKeyboardCheckboxVisibility();
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.Commit();
return;
}

View File

@@ -69,15 +69,6 @@ namespace keepass2android
public static void Launch (Activity act, PwGroup g, AppTask appTask)
{
// Need to use PwDatabase since group may be null
PwDatabase db = App.Kp2a.GetDb().KpDatabase;
if (db == null) {
// Reached if db is null
Log.Debug (Tag, "Tried to launch with null db");
return;
}
Intent i = new Intent(act, typeof(GroupActivity));
if ( g != null ) {
@@ -105,7 +96,12 @@ namespace keepass2android
protected override bool AddEntryEnabled
{
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); }
get { return App.Kp2a.CurrentDb.CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.CurrentDb.DatabaseFormat.CanHaveEntriesInRootGroup); }
}
protected override bool AddGroupEnabled
{
get { return App.Kp2a.CurrentDb.CanWrite; }
}
private class TemplateListAdapter : ArrayAdapter<PwEntry>
@@ -149,8 +145,7 @@ namespace keepass2android
int size = (int)(Util.convertDpToPixel(Util.convertDpToPixel(20, Context), Context));
var bmp =
Bitmap.CreateScaledBitmap(
Util.DrawableToBitmap(App.Kp2a.GetDb()
.DrawableFactory.GetIconDrawable(Context, App.Kp2a.GetDb().KpDatabase, templateEntry.IconId, PwUuid.Zero, false)),
Util.DrawableToBitmap(App.Kp2a.CurrentDb .DrawableFactory.GetIconDrawable(Context, App.Kp2a.CurrentDb.KpDatabase, templateEntry.IconId, PwUuid.Zero, false)),
size, size,
true);
@@ -193,7 +188,7 @@ namespace keepass2android
PwUuid id = RetrieveGroupId (intent);
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
if (id == null) {
Group = db.Root;
} else {
@@ -221,8 +216,8 @@ namespace keepass2android
View addEntry = FindViewById (Resource.Id.fabAddNewEntry);
addEntry.Click += (sender, e) =>
{
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTemplates &&
!AddTemplateEntries.ContainsAllTemplates(App.Kp2a) &&
if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsTemplates &&
!AddTemplateEntries.ContainsAllTemplates(App.Kp2a.CurrentDb) &&
PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(Askaddtemplates, true))
{
App.Kp2a.AskYesNoCancel(UiStringKey.AskAddTemplatesTitle, UiStringKey.AskAddTemplatesMessage,UiStringKey.yes, UiStringKey.no,
@@ -256,14 +251,14 @@ namespace keepass2android
FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
Log.Warn(Tag, "Finished creating group");
var ioc = App.Kp2a.GetDb().Ioc;
var ioc = App.Kp2a.CurrentDb.Ioc;
OptionalOut<UiStringKey> reason = new OptionalOut<UiStringKey>();
if (App.Kp2a.GetFileStorage(ioc).IsReadOnly(ioc, reason))
{
bool hasShownReadOnlyReason =
PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", false);
.GetBoolean(App.Kp2a.CurrentDb.IocAsHexString() + "_readonlyreason", false);
if (!hasShownReadOnlyReason)
{
var b = new AlertDialog.Builder(this);
@@ -273,7 +268,7 @@ namespace keepass2android
(sender, args) =>
{
PreferenceManager.GetDefaultSharedPreferences(this).
Edit().PutBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", true).Commit();
Edit().PutBoolean(App.Kp2a.CurrentDb.IocAsHexString() + "_readonlyreason", true).Commit();
});
b.Show();
}
@@ -287,11 +282,11 @@ namespace keepass2android
defaultTemplate.IconId = PwIcon.Key;
defaultTemplate.Strings.Set(PwDefs.TitleField, new ProtectedString(false, GetString(Resource.String.DefaultTemplate)));
List<PwEntry> templates = new List<PwEntry>() {defaultTemplate};
if ((!PwUuid.Zero.Equals(App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup))
&& (App.Kp2a.GetDb().KpDatabase.RootGroup.FindGroup(App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup, true) != null))
if ((!PwUuid.Zero.Equals(App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup))
&& (App.Kp2a.CurrentDb.KpDatabase.RootGroup.FindGroup(App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup, true) != null))
{
templates.AddRange(
App.Kp2a.GetDb().Groups[App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup].Entries.OrderBy(
App.Kp2a.CurrentDb.Groups[App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup].Entries.OrderBy(
entr => entr.Strings.ReadSafe(PwDefs.TitleField)));
}
if (templates.Count > 1)
@@ -316,6 +311,11 @@ namespace keepass2android
cv.OnCreateMenu(menu, menuInfo);
}
public override bool EntriesBelongToCurrentDatabaseOnly
{
get { return true; }
}
public override void OnBackPressed()
{
base.OnBackPressed();

View File

@@ -95,11 +95,11 @@ namespace keepass2android
protected virtual bool AddGroupEnabled
{
get { return App.Kp2a.GetDb().CanWrite; }
get { return false; }
}
protected virtual bool AddEntryEnabled
{
get { return App.Kp2a.GetDb().CanWrite; }
get { return false; }
}
public void SetNormalButtonVisibility(bool showAddGroup, bool showAddEntry)
@@ -186,7 +186,7 @@ namespace keepass2android
else
{
PwUuid groupUuid = new PwUuid(MemUtil.HexStringToByteArray(strGroupUuid));
task = new EditGroup(this, App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.GetDb().Groups[groupUuid],
task = new EditGroup(this, App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.FindGroup(groupUuid),
new RefreshTask(handler, this));
}
ProgressTask pt = new ProgressTask(App.Kp2a, act, task);
@@ -258,7 +258,7 @@ namespace keepass2android
{
FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.GetDb().Ioc), ""), out um);
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
bool isFingerprintEnabled = (um == FingerprintUnlockMode.FullUnlock);
string masterKeyKey = "MasterKey" + isFingerprintEnabled;
@@ -267,11 +267,11 @@ namespace keepass2android
List<string> applicableInfoTextKeys = new List<string> { masterKeyKey };
if (App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).UserShouldBackup)
if (App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc).UserShouldBackup)
{
applicableInfoTextKeys.Add(backupKey);
}
if (App.Kp2a.GetDb().Entries.Count > 15)
if (App.Kp2a.CurrentDb.Entries.Count > 15)
{
applicableInfoTextKeys.Add(emergencyKey);
}
@@ -378,10 +378,9 @@ namespace keepass2android
public void RefreshIfDirty()
{
Database db = App.Kp2a.GetDb();
if (db.Dirty.Contains(Group))
if (App.Kp2a.DirtyGroups.Contains(Group))
{
db.Dirty.Remove(Group);
App.Kp2a.DirtyGroups.Remove(Group);
ListAdapter.NotifyDataSetChanged();
}
@@ -407,7 +406,7 @@ namespace keepass2android
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
// Likely the app has been killed exit the activity
if (App.Kp2a.GetDb() == null)
if (App.Kp2a.CurrentDb== null)
{
Finish();
return;
@@ -458,7 +457,7 @@ namespace keepass2android
{
FindViewById(Resource.Id.hide_fingerprint_info).Click += (sender, args) =>
{
_prefs.Edit().PutBoolean(fingerprintinfohidden_prefskey + App.Kp2a.GetDb().CurrentFingerprintPrefKey, true).Commit();
_prefs.Edit().PutBoolean(fingerprintinfohidden_prefskey + App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, true).Commit();
UpdateFingerprintInfo();
};
}
@@ -627,7 +626,7 @@ namespace keepass2android
{
bool canShowFingerprintInfo = false;
bool disabledForDatabase = _prefs.GetBoolean(fingerprintinfohidden_prefskey + App.Kp2a.GetDb().CurrentFingerprintPrefKey, false);
bool disabledForDatabase = _prefs.GetBoolean(fingerprintinfohidden_prefskey + App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, false);
bool disabledForAll = _prefs.GetBoolean(fingerprintinfohidden_prefskey, false);
if (!disabledForAll && !disabledForDatabase)
{
@@ -636,7 +635,7 @@ namespace keepass2android
if (fpModule.FingerprintManager != null && fpModule.FingerprintManager.IsHardwareDetected)
{
FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.GetDb().Ioc), ""), out um);
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
canShowFingerprintInfo = um == FingerprintUnlockMode.Disabled;
}
}
@@ -667,8 +666,7 @@ namespace keepass2android
private void InsertElements()
{
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
IEnumerable<IStructureItem> elementsToMove =
moveElementsTask.Uuids.Select(uuid => App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null));
IEnumerable<IStructureItem> elementsToMove = moveElementsTask.Uuids.Select(uuid => App.Kp2a.FindStructureItem(uuid));
@@ -690,7 +688,7 @@ namespace keepass2android
{
String name = Group.Name;
String titleText;
bool clickable = (Group != null) && (Group.IsVirtual == false) && (Group.ParentGroup != null);
bool clickable = (Group != null) && (Group.IsVirtual == false) && ((Group.ParentGroup != null) || App.Kp2a.OpenDatabases.Count() > 1);
if (!String.IsNullOrEmpty(name))
{
titleText = name;
@@ -715,9 +713,7 @@ namespace keepass2android
{
if (Group != null)
{
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid, true);
SupportActionBar.SetDisplayShowHomeEnabled(true);
//SupportActionBar.SetIcon(drawable);
}
}
@@ -740,7 +736,8 @@ namespace keepass2android
var cursor = _suggestionsAdapter.Cursor;
cursor.MoveToPosition(position);
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))], -1, _activity.AppTask);
var entryId = new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString));
EntryActivity.Launch(_activity, App.Kp2a.FindDatabaseForEntryId(entryId).Entries[entryId], -1, _activity.AppTask);
return true;
}
@@ -830,35 +827,34 @@ namespace keepass2android
{
if (_syncItem != null)
{
if (App.Kp2a.GetDb().Ioc.IsLocalFile())
if (((App.Kp2a.OpenDatabases.Count() == 1) || (EntriesBelongToCurrentDatabaseOnly))
&& App.Kp2a.CurrentDb.Ioc.IsLocalFile())
_syncItem.SetVisible(false);
else
_syncItem.SetVisible(!App.Kp2a.OfflineMode);
}
if (App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc) is IOfflineSwitchable)
if (((App.Kp2a.OpenDatabases.Count() == 1) || (EntriesBelongToCurrentDatabaseOnly))
&& (App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc) is IOfflineSwitchable))
{
if (_offlineItem != null)
_offlineItem.SetVisible(App.Kp2a.OfflineMode == false);
if (_onlineItem != null)
_onlineItem.SetVisible(App.Kp2a.OfflineMode);
_offlineItem?.SetVisible(App.Kp2a.OfflineMode == false);
_onlineItem?.SetVisible(App.Kp2a.OfflineMode);
}
else
{
if (_offlineItem != null)
_offlineItem.SetVisible(false);
if (_onlineItem != null)
_onlineItem.SetVisible(false);
_offlineItem?.SetVisible(false);
_onlineItem?.SetVisible(false);
}
}
catch (Exception e)
{
Kp2aLog.LogUnexpectedError(new Exception("Cannot UpdateOfflineModeMenu " + (App.Kp2a == null) + " " + ((App.Kp2a == null) || (App.Kp2a.GetDb() == null)) + " " + (((App.Kp2a == null) || (App.Kp2a.GetDb() == null) || (App.Kp2a.GetDb().Ioc == null)) + " " + (_syncItem != null) + " " + (_offlineItem != null) + " " + (_onlineItem != null))));
Kp2aLog.LogUnexpectedError(new Exception("Cannot UpdateOfflineModeMenu " + (App.Kp2a == null) + " " + ((App.Kp2a == null) || (App.Kp2a.CurrentDb== null)) + " " + (((App.Kp2a == null) || (App.Kp2a.CurrentDb== null) || (App.Kp2a.CurrentDb.Ioc == null)) + " " + (_syncItem != null) + " " + (_offlineItem != null) + " " + (_onlineItem != null))));
}
}
public abstract bool EntriesBelongToCurrentDatabaseOnly { get; }
public override bool OnPrepareOptionsMenu(IMenu menu)
{
@@ -880,7 +876,7 @@ namespace keepass2android
case Resource.Id.menu_donate:
return Util.GotoDonateUrl(this);
case Resource.Id.menu_lock:
App.Kp2a.LockDatabase();
App.Kp2a.Lock();
return true;
case Resource.Id.menu_search:
@@ -906,8 +902,10 @@ namespace keepass2android
UpdateOfflineModeMenu();
Synchronize();
return true;
case Resource.Id.menu_open_other_db:
AppTask.SetActivityResult(this, KeePass.ExitLoadAnotherDb);
Finish();
return true;
case Resource.Id.menu_sort:
ChangeSort();
return true;
@@ -960,7 +958,7 @@ namespace keepass2android
private void Synchronize()
{
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc);
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc);
RunnableOnFinish task;
OnFinish onFinish = new ActionOnFinish(this, (success, message, activity) =>
{
@@ -971,9 +969,9 @@ namespace keepass2android
BaseAdapter adapter = (BaseAdapter)((GroupBaseActivity)activity)?.ListAdapter;
adapter?.NotifyDataSetChanged();
if (App.Kp2a.GetDb().OtpAuxFileIoc != null)
if (App.Kp2a.CurrentDb.OtpAuxFileIoc != null)
{
var task2 = new SyncOtpAuxFile(this, App.Kp2a.GetDb().OtpAuxFileIoc);
var task2 = new SyncOtpAuxFile(this, App.Kp2a.CurrentDb.OtpAuxFileIoc);
new ProgressTask(App.Kp2a, activity, task2).Run(true);
}
});
@@ -1022,10 +1020,10 @@ namespace keepass2android
ActivityCompat.InvalidateOptionsMenu(this);
// Mark all groups as dirty now to refresh them on load
Database db = App.Kp2a.GetDb();
db.MarkAllGroupsAsDirty();
App.Kp2a.MarkAllGroupsAsDirty();
// We'll manually refresh this group so we can remove it
db.Dirty.Remove(Group);
App.Kp2a.DirtyGroups.Remove(Group);
// Tell the adapter to refresh it's list
@@ -1082,7 +1080,7 @@ namespace keepass2android
Toast.MakeText(ActiveActivity, "Unrecoverable error: " + Message, ToastLength.Long).Show();
});
App.Kp2a.LockDatabase(false);
App.Kp2a.Lock(false);
}
}
@@ -1133,9 +1131,9 @@ namespace keepass2android
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
foreach (var uuid in moveElementsTask.Uuids)
{
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null);
IStructureItem elementToMove = App.Kp2a.FindStructureItem(uuid);
if (elementToMove.ParentGroup != Group)
App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup);
App.Kp2a.DirtyGroups.Add(elementToMove.ParentGroup);
}
}
catch (Exception e)
@@ -1167,7 +1165,7 @@ namespace keepass2android
base.OnActivityCreated(savedInstanceState);
ListView.SetMultiChoiceModeListener(this);
if (App.Kp2a.GetDb().CanWrite)
if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
{
ListView.ChoiceMode = ChoiceMode.MultipleModal;
@@ -1221,13 +1219,10 @@ namespace keepass2android
{
case Resource.Id.menu_delete:
DeleteMultipleItems task = new DeleteMultipleItems((GroupBaseActivity)Activity, App.Kp2a.GetDb(), checkedItems,
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
task.Start();
DeleteMultipleItems((GroupBaseActivity)Activity, checkedItems, new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
break;
case Resource.Id.menu_move:
var navMove = new NavigateToFolderAndLaunchMoveElementTask(checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
var navMove = new NavigateToFolderAndLaunchMoveElementTask(App.Kp2a.CurrentDb, checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
((GroupBaseActivity)Activity).StartTask(navMove);
break;
case Resource.Id.menu_copy:
@@ -1240,7 +1235,7 @@ namespace keepass2android
break;
case Resource.Id.menu_navigate:
NavigateToFolder navNavigate = new NavigateToFolder(checkedItems.First().ParentGroup, true);
NavigateToFolder navNavigate = new NavigateToFolder(App.Kp2a.CurrentDb, checkedItems.First().ParentGroup, true);
((GroupBaseActivity)Activity).StartTask(navNavigate);
break;
case Resource.Id.menu_edit:
@@ -1378,6 +1373,66 @@ namespace keepass2android
{
return IsOnlyOneItemChecked() && !IsOnlyOneGroupChecked();
}
public void DeleteMultipleItems(GroupBaseActivity activity, List<IStructureItem> checkedItems, OnFinish onFinish, Kp2aApp app)
{
if (checkedItems.Any() == false)
return;
//sort checkedItems by database
List<KeyValuePair<Database, List<IStructureItem>>> itemsForDatabases =
new List<KeyValuePair<Database, List<IStructureItem>>>();
foreach (var item in checkedItems)
{
var db = app.FindDatabaseForEntryId(item.Uuid) ?? app.FindDatabaseForGroupId(item.Uuid);
if (db != null)
{
bool foundDatabase = false;
foreach (var listEntry in itemsForDatabases)
{
if (listEntry.Key == db)
{
foundDatabase = true;
listEntry.Value.Add(item);
break;
}
}
if (!foundDatabase)
{
itemsForDatabases.Add(new KeyValuePair<Database, List<IStructureItem>>(db, new List<IStructureItem> { item }));
}
}
}
int dbIndex = 0;
Action<bool, string, Activity> action = null;
action = (success, message, activeActivity) =>
{
if (success)
{
dbIndex++;
if (dbIndex == itemsForDatabases.Count)
{
onFinish.SetResult(true);
onFinish.Run();
return;
}
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activeActivity, (b, s, activity1) => action(b, s, activity1)), app)
.Start();
}
else
{
onFinish.SetResult(false, message, null);
}
};
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activity, (b, s, activity1) => action(b, s, activity1)), app)
.Start();
}
}
}

View File

@@ -90,7 +90,7 @@ namespace keepass2android
};
_selectedIconId = (int) PwIcon.FolderOpen;
iconButton.SetImageDrawable(App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this, App.Kp2a.GetDb().KpDatabase, (PwIcon)_selectedIconId, null, true));
iconButton.SetImageDrawable(App.Kp2a.CurrentDb.DrawableFactory.GetIconDrawable(this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon)_selectedIconId, null, true));
Button okButton = (Button)FindViewById (Resource.Id.ok);
okButton.Click += (sender, e) => {
@@ -118,12 +118,12 @@ namespace keepass2android
if (Intent.HasExtra(KeyGroupUuid))
{
string groupUuid = Intent.Extras.GetString(KeyGroupUuid);
_groupToEdit = App.Kp2a.GetDb().Groups[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))];
_groupToEdit = App.Kp2a.CurrentDb.Groups[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))];
_selectedIconId = (int) _groupToEdit.IconId;
_selectedCustomIconId = _groupToEdit.CustomIconUuid;
TextView nameField = (TextView)FindViewById(Resource.Id.group_name);
nameField.Text = _groupToEdit.Name;
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.GetDb().KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid, false);
App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.CurrentDb.KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid, false);
SetTitle(Resource.String.edit_group_title);
}
else
@@ -156,7 +156,7 @@ namespace keepass2android
_selectedCustomIconId = PwUuid.Zero;
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.GetDb().KpDatabase, (PwIcon) _selectedIconId, _selectedCustomIconId, false);
App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon) _selectedIconId, _selectedCustomIconId, false);
break;
}
}

View File

@@ -51,7 +51,7 @@ namespace keepass2android
SetContentView(Resource.Layout.icon_picker);
GridView currIconGridView = (GridView)FindViewById(Resource.Id.IconGridView);
currIconGridView.Adapter = new ImageAdapter(this, App.Kp2a.GetDb().KpDatabase);
currIconGridView.Adapter = new ImageAdapter(this, App.Kp2a.CurrentDb.KpDatabase);
currIconGridView.ItemClick += (sender, e) =>
{
@@ -134,7 +134,7 @@ namespace keepass2android
bitmap.Compress(Bitmap.CompressFormat.Png, 90, ms);
PwCustomIcon pwci = new PwCustomIcon(new PwUuid(true), ms.ToArray());
App.Kp2a.GetDb().KpDatabase.CustomIcons.Add(pwci);
App.Kp2a.CurrentDb.KpDatabase.CustomIcons.Add(pwci);
}
var gridView = ((GridView)FindViewById(Resource.Id.IconGridView));
@@ -198,8 +198,7 @@ namespace keepass2android
if (position < (int)PwIcon.Count)
{
tv.Text = "" + position;
var drawable = App.Kp2a.GetDb()
.DrawableFactory.GetIconDrawable(_act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);
var drawable = App.Kp2a.CurrentDb .DrawableFactory.GetIconDrawable(_act, App.Kp2a.CurrentDb.KpDatabase, (KeePassLib.PwIcon) position, null, false);
drawable = new BitmapDrawable(Util.DrawableToBitmap(drawable));
iv.SetImageDrawable(drawable);
//App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);

View File

@@ -317,7 +317,7 @@ namespace keepass2android
SetContentView(Resource.Layout.ImageViewActivity);
var uuid = new PwUuid(MemUtil.HexStringToByteArray(Intent.GetStringExtra("EntryId")));
string key = Intent.GetStringExtra("EntryKey");
var binary = App.Kp2a.GetDb().Entries[uuid].Binaries.Get(key);
var binary = App.Kp2a.FindDatabaseForEntryId(uuid).Entries[uuid].Binaries.Get(key);
SupportActionBar.Title = key;
byte[] pbdata = binary.ReadData();

View File

@@ -38,8 +38,8 @@ using String = System.String;
* Keepass2Android comprises quite a number of different activities and entry points: The app can be started
* using the launcher icon (-> Activity "Keepass"), or by sending a URL (-> FileSelect), opening a .kdb(x)-file (->Password),
* swiping a YubikeyNEO (NfcOtpActivity).
* While the database is closed, there is only one activity on the stack: Keepass -> FileSelect <-> Password.
* After opening an database (in Password), Password is always the root of the stack (exception: after creating a database,
* There is either only the KeePass activity on stack (no db loaded then) or the first activity
* After opening a database (in Password), Password is always the root of the stack (exception: after creating a database,
* FileSelect is the root without Password being open).
* Another exception: QueryCredentialsActivity is root of the stack if an external app is querying credentials.
* QueryCredentialsActivity checks the plugin access permissions, then launches FileSelectActivity (which starts
@@ -86,6 +86,8 @@ namespace keepass2android
public const Result ExitClose = Result.FirstUser + 7;
public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8;
public const Result ResultOkPasswordGenerator = Result.FirstUser + 9;
public const Result ExitLoadAnotherDb = Result.FirstUser + 10;
public const string TagsKey = "@tags";
public const string OverrideUrlKey = "@override";

View File

@@ -38,7 +38,7 @@ namespace keepass2android
return res;
}
private const string EtmTemplateUuid = "_etm_template_uuid";
public const string EtmTemplateUuid = "_etm_template_uuid";
private const string EtmTitle = "_etm_title_";
private readonly Database _db;
private readonly PwEntry _entry;

View File

@@ -51,7 +51,7 @@ namespace keepass2android
{
base.OnResume();
Kp2aLog.Log(ClassName+".OnResume");
if (App.Kp2a.GetDb() == null)
if (App.Kp2a.CurrentDb== null)
{
Kp2aLog.Log(" DB null");
}

View File

@@ -63,7 +63,7 @@ namespace keepass2android
}
_ioc = App.Kp2a.GetDb().Ioc;
_ioc = App.Kp2a.CurrentDb.Ioc;
if (Intent.GetBooleanExtra(NoLockCheck, false))
return;
@@ -106,8 +106,11 @@ namespace keepass2android
if (Intent.GetBooleanExtra(NoLockCheck, false))
return;
if (TimeoutHelper.CheckShutdown(this, _ioc))
if (TimeoutHelper.CheckDbChanged(this, _ioc))
{
Finish();
return;
}
//todo: it seems like OnResume can be called after dismissing a dialog, e.g. the Delete-permanently-Dialog.
//in this case the following check might run in parallel with the check performed during the SaveDb check (triggered after the

View File

@@ -51,7 +51,7 @@ namespace keepass2android
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
_ioc = App.Kp2a.GetDb().Ioc;
_ioc = App.Kp2a.CurrentDb.Ioc;
_intentReceiver = new LockCloseListActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
@@ -73,8 +73,11 @@ namespace keepass2android
base.OnResume();
_design.ReapplyTheme();
if (TimeoutHelper.CheckShutdown(this, _ioc))
if (TimeoutHelper.CheckDbChanged(this, _ioc))
{
Finish();
return;
}
//todo: see LockCloseActivity.OnResume
App.Kp2a.CheckForOpenFileChanged(this);

View File

@@ -43,7 +43,7 @@ namespace keepass2android
{
base.OnStart();
var xcKey = App.Kp2a.GetDb()?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
var xcKey = App.Kp2a.CurrentDb?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
if (xcKey != null)
{
xcKey.Activity = this;
@@ -58,7 +58,7 @@ namespace keepass2android
protected override void OnStop()
{
base.OnStop();
var xcKey = App.Kp2a.GetDb()?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
var xcKey = App.Kp2a.CurrentDb?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
if (xcKey != null)
{
//don't store a pointer to this activity in the static database object to avoid memory leak

View File

@@ -32,7 +32,7 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_ioc = App.Kp2a.GetDb().Ioc;
_ioc = App.Kp2a.CurrentDb.Ioc;
_intentReceiver = new LockingClosePreferenceActivityBroadcastReceiver(this);
@@ -44,7 +44,11 @@ namespace keepass2android
protected override void OnResume() {
base.OnResume();
TimeoutHelper.CheckShutdown(this, _ioc);
if (TimeoutHelper.CheckDbChanged(this, _ioc))
{
Finish();
return;
}
}

View File

@@ -93,15 +93,7 @@ namespace keepass2android
return;
}
if (App.Kp2a.GetDb() != null)
{
Toast.MakeText(this, GetString(Resource.String.otp_discarded_because_db_open), ToastLength.Long).Show();
}
else
{
StartActivity(i);
}
Finish();
}

View File

@@ -737,12 +737,6 @@ namespace keepass2android
}
}
if (App.Kp2a.GetDb()?.Ioc != null && App.Kp2a.GetDb().Ioc.GetDisplayName() != _ioConnection.GetDisplayName())
{
// A different database is currently loaded, unload it before loading the new one requested
App.Kp2a.LockDatabase(false);
}
SetContentView(Resource.Layout.password);
InitializeToolbar();
@@ -807,6 +801,14 @@ namespace keepass2android
if ((int)Build.VERSION.SdkInt >= 23)
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
var matchingOpenDb = App.Kp2a.OpenDatabases.FirstOrDefault(db => db.Ioc.IsSameFileAs(_ioConnection));
if (matchingOpenDb != null)
{
App.Kp2a.CurrentDb = matchingOpenDb;
Finish();
}
}
private void InitializeToolbarCollapsing()
@@ -1473,8 +1475,6 @@ namespace keepass2android
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish);
_loadDbFileTask = null; // prevent accidental re-use
SetNewDefaultFile();
new ProgressTask(App.Kp2a, this, task).Run();
}
catch (Exception e)
@@ -1596,34 +1596,6 @@ namespace keepass2android
base.OnPause();
}
private void SetNewDefaultFile()
{
//Don't allow the current file to be the default if we don't have stored credentials
bool makeFileDefault;
if ((_ioConnection.IsLocalFile() == false) && (_ioConnection.CredSaveMode != IOCredSaveMode.SaveCred))
{
makeFileDefault = false;
}
else
{
makeFileDefault = true;
}
String newDefaultFileName;
if (makeFileDefault)
{
newDefaultFileName = _ioConnection.Path;
}
else
{
newDefaultFileName = "";
}
ISharedPreferencesEditor editor = _prefs.Edit();
editor.PutString(KeyDefaultFilename, newDefaultFileName);
EditorCompat.Apply(editor);
}
protected override void OnStart()
{
base.OnStart();
@@ -1815,16 +1787,8 @@ namespace keepass2android
//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
if ( !IsFinishing && !_performingLoad)
{
if (App.Kp2a.DatabaseIsUnlocked)
{
Finish();
}
else if (App.Kp2a.QuickUnlockEnabled && App.Kp2a.QuickLocked)
{
Finish();
}
else
{
// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
if (_starting)
@@ -1835,14 +1799,15 @@ namespace keepass2android
//database not yet loaded.
//check if pre-loading is enabled but wasn't started yet:
if (_loadDbFileTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
if (_loadDbFileTask == null &&
_prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
{
// Create task to kick off file loading while the user enters the password
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
_loadDbTaskOffline = App.Kp2a.OfflineMode;
}
}
}
}
if (compositeKeyForImmediateLoad != null)
@@ -2049,6 +2014,7 @@ namespace keepass2android
_act.BroadcastOpenDatabase();
_act.InvalidCompositeKeyCount = 0;
_act.LoadingErrorCount = 0;
_act.Finish();
GC.Collect(); // Ensure temporary memory used while loading is collected
@@ -2193,7 +2159,7 @@ namespace keepass2android
if (!OathHotpKeyProv.CreateAuxFile(_act._otpInfo, ctx, _act._otpAuxIoc))
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile), ToastLength.Long).Show();
App.Kp2a.GetDb().OtpAuxFileIoc = _act._otpAuxIoc;
}
catch (Exception e)
{
@@ -2206,7 +2172,14 @@ namespace keepass2android
base.Run();
if (success)
{
App.Kp2a.CurrentDb.OtpAuxFileIoc = _act._otpAuxIoc;
}
}
}
private class PasswordActivityBroadcastReceiver : BroadcastReceiver
{

View File

@@ -49,8 +49,8 @@ namespace keepass2android
//if launched from history, don't re-use the task. Proceed to FileSelect instead.
if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
{
Kp2aLog.Log("Forwarding to FileSelect. QueryCredentialsActivity started from history.");
Intent intent = new Intent(this, typeof(FileSelectActivity));
Kp2aLog.Log("Forwarding to SelectCurrentDbActivity. QueryCredentialsActivity started from history.");
Intent intent = new Intent(this, typeof(SelectCurrentDbActivity));
intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent);
Finish();
@@ -135,9 +135,9 @@ namespace keepass2android
private void StartQuery()
{
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//launch SelectCurrentDbActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later
Intent i = new Intent(this, typeof (FileSelectActivity));
Intent i = new Intent(this, typeof (SelectCurrentDbActivity));
//don't show user notifications when an entry is opened.
var task = new SearchUrlTask() {UrlToSearchFor = _requestedUrl, ShowUserNotifications = false};
task.ToIntent(i);
@@ -185,7 +185,7 @@ namespace keepass2android
}
//return credentials to caller:
Intent credentialData = new Intent();
PluginHost.AddEntryToIntent(credentialData, App.Kp2a.GetDb().LastOpenedEntry);
PluginHost.AddEntryToIntent(credentialData, App.Kp2a.LastOpenedEntry);
credentialData.PutExtra(Strings.ExtraQueryString,_requestedUrl);
SetResult(Result.Ok, credentialData);
Finish();

View File

@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
*/
using System;
using System.Linq;
using Android;
using Android.App;
using Android.Content;
@@ -64,7 +65,7 @@ namespace keepass2android
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
_ioc = App.Kp2a.GetDb().Ioc;
_ioc = App.Kp2a.GetDbForQuickUnlock().Ioc;
if (_ioc == null)
{
@@ -81,10 +82,10 @@ namespace keepass2android
var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar);
collapsingToolbar.SetTitle(GetString(Resource.String.QuickUnlock_prefs));
if (App.Kp2a.GetDb().KpDatabase.Name != "")
if (App.Kp2a.GetDbForQuickUnlock().KpDatabase.Name != "")
{
FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Visible;
((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDb().KpDatabase.Name;
((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDbForQuickUnlock().KpDatabase.Name;
}
else
{
@@ -134,7 +135,7 @@ namespace keepass2android
btnLock.Text = btnLock.Text.Replace("<22>", "ss");
btnLock.Click += (object sender, EventArgs e) =>
{
App.Kp2a.LockDatabase(false);
App.Kp2a.Lock(false);
Finish();
};
pwd.EditorAction += (sender, args) =>
@@ -244,7 +245,7 @@ namespace keepass2android
try
{
FingerprintUnlockMode um;
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""), out um);
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintModePrefKey, ""), out um);
btn.Visibility = (um != FingerprintUnlockMode.Disabled) ? ViewStates.Visible : ViewStates.Gone;
if (um == FingerprintUnlockMode.Disabled)
@@ -258,10 +259,10 @@ namespace keepass2android
FingerprintModule fpModule = new FingerprintModule(this);
Kp2aLog.Log("fpModule.FingerprintManager.IsHardwareDetected=" + fpModule.FingerprintManager.IsHardwareDetected);
if (fpModule.FingerprintManager.IsHardwareDetected) //see FingerprintSetupActivity
_fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDb().CurrentFingerprintPrefKey, this,
App.Kp2a.GetDb().CurrentFingerprintPrefKey);
_fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
}
if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDb().CurrentFingerprintPrefKey)))
if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
{
try
{
@@ -321,14 +322,6 @@ namespace keepass2android
_fingerprintIdentifier = null;
}
private void ClearFingerprintUnlockData()
{
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintPrefKey, "");
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString());
edit.Commit();
}
private void OnUnlock(int quickUnlockLength, EditText pwd)
{
var expectedPasswordPart = ExpectedPasswordPart;
@@ -340,7 +333,7 @@ namespace keepass2android
else
{
Kp2aLog.Log("QuickUnlock not successful!");
App.Kp2a.LockDatabase(false);
App.Kp2a.Lock(false);
Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show();
}
Finish();
@@ -350,7 +343,7 @@ namespace keepass2android
{
get
{
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDbForQuickUnlock().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
String password = kcpPassword.Password.ReadString();
var passwordStringInfo = new System.Globalization.StringInfo(password);
@@ -427,7 +420,7 @@ namespace keepass2android
private void CheckIfUnloaded()
{
if (App.Kp2a.GetDb() == null)
if (App.Kp2a.OpenDatabases.Any() == false)
{
Finish();
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:background="@drawable/splash_bg_selector"
android:fitsSystemWindows="true"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<android.support.v7.widget.Toolbar
android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleTextStyle="@style/MyTitleTextStyle"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:minHeight="?attr/actionBarSize"
android:background="#00000000" />
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="16dp"
android:background="@drawable/storagetype_grid_bg"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:layout_marginTop="0dp"
android:columnWidth="140dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center" />
</LinearLayout>

View File

@@ -62,6 +62,11 @@
android:title="@string/sort_menu"
app:showAsAction="never"
/>
<item android:id="@+id/menu_open_other_db"
android:title="@string/open_other_db"
app:showAsAction="never"
/>
</menu>

View File

@@ -63,6 +63,7 @@
<string name="unlock_database_title">Unlock database</string>
<string name="brackets">Brackets</string>
<string name="cancel">Cancel</string>
<string name="Ok">Ok</string>
<string name="ClearClipboard">Clipboard cleared.</string>
@@ -210,7 +211,7 @@
<string name="omitbackup_title">Don\'t search backup and recycle bin entries</string>
<string name="omitbackup_summary">Omit \'Backup\' and Recycle Bin group from search results</string>
<string name="pass_filename">KeePass database filename</string>
<string name="password_title">Enter database password</string>
<string name="password_title">Enter databoase password</string>
<string name="master_key_type">Select master key type:</string>
<string name="progress_create">Creating new database…</string>
<string name="create_database">Create database</string>
@@ -430,6 +431,10 @@
<string name="AskOverwriteBinary_no">Rename</string>
<string name="AttachFailed">Failed to add file attachment.</string>
<string name="RecycleBin">Recycle Bin</string>
<string name="UpdatingTemplateIds">Updating template entries </string>
<string name="AskDeletePermanentlyEntry">Do you want to delete this entry permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyGroup">Do you want to delete this group permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyItems">Do you want to delete the selected elements permanently? Press No to recycle.</string>
@@ -731,6 +736,12 @@
</string>
<string name="open_other_db">Open another database…</string>
<string name="select_database">Select database</string>
<string name="ChangleLegacyTemplateIds_Title">Identical template entry ids</string>
<string name="ChangleLegacyTemplateIds_Message">Your database contains template entries with the same UUIDs as template entries in another open database. In order to use both databases simultaneously, Keepass2Android will modify the IDs of the database you are about to open.</string>
<string name="DbUnlockedChannel_name">Database unlocked</string>
<string name="DbUnlockedChannel_desc">Notification about the database being unlocked</string>

View File

@@ -6,25 +6,155 @@ using System.Text;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Text;
using Android.Util;
using Android.Views;
using Android.Widget;
using keepass2android.Io;
using keepass2android.Utils;
using KeeChallenge;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using Object = Java.Lang.Object;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, MainLauncher = false, Theme = "@style/MyTheme_Blue", LaunchMode = LaunchMode.SingleInstance)]
public class SelectCurrentDbActivity : Activity
public class SelectCurrentDbActivity : AppCompatActivity
{
public class OpenDatabaseAdapter : BaseAdapter
{
private readonly SelectCurrentDbActivity _context;
internal List<Database> _displayedDatabases;
public OpenDatabaseAdapter(SelectCurrentDbActivity context)
{
_context = context;
Update();
}
public override Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public static float convertDpToPixel(float dp, Context context)
{
return Util.convertDpToPixel(dp, context);
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
Button btn;
if (convertView == null)
{
// if it's not recycled, initialize some attributes
btn = new Button(_context);
btn.LayoutParameters = new GridView.LayoutParams((int) convertDpToPixel(140, _context),
(int) convertDpToPixel(150, _context));
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg);
btn.SetPadding((int) convertDpToPixel(4, _context),
(int) convertDpToPixel(20, _context),
(int) convertDpToPixel(4, _context),
(int) convertDpToPixel(4, _context));
btn.SetTextSize(ComplexUnitType.Sp, 11);
btn.SetTextColor(new Color(115, 115, 115));
btn.SetSingleLine(false);
btn.Gravity = GravityFlags.Center;
btn.Click += (sender, args) =>
{
int pos;
int.TryParse(((Button) sender).Tag.ToString(), out pos);
if (pos < _displayedDatabases.Count)
_context.OnItemSelected(_displayedDatabases[pos]);
else
{
_context.OnOpenOther();
}
};
}
else
{
btn = (Button) convertView;
}
btn.Tag = position.ToString();
string displayName;
Drawable drawable;
if (position < _displayedDatabases.Count)
{
var db = _displayedDatabases[position];
drawable = App.Kp2a.GetResourceDrawable("ic_storage_" + Util.GetProtocolId(db.Ioc));
displayName = db.KpDatabase.Name;
displayName += "\n" + App.Kp2a.GetFileStorage(db.Ioc).GetDisplayName(db.Ioc);
}
else
{
displayName = _context.GetString(Resource.String.start_open_file);
drawable = App.Kp2a.GetResourceDrawable("ic_nav_changedb");
}
var str = new SpannableString(displayName);
btn.TextFormatted = str;
//var drawable = ContextCompat.GetDrawable(context, Resource.Drawable.Icon);
btn.SetCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
return btn;
}
public override int Count
{
get { return _displayedDatabases.Count+1; }
}
public void Update()
{
_displayedDatabases = App.Kp2a.OpenDatabases.ToList();
}
}
private void OnOpenOther()
{
StartFileSelect();
}
private void OnItemSelected(Database selectedDatabase)
{
App.Kp2a.CurrentDb = selectedDatabase;
AppTask.LaunchFirstGroupActivity(this);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.open_db_selection);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = GetString(Resource.String.select_database);
if ((AppTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
{
AppTask = new NullTask();
@@ -33,6 +163,12 @@ namespace keepass2android
{
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
}
_adapter = new OpenDatabaseAdapter(this);
var gridView = FindViewById<GridView>(Resource.Id.gridview);
gridView.ItemClick += (sender, args) => OnItemSelected(_adapter._displayedDatabases[args.Position]);
gridView.Adapter = _adapter;
}
@@ -44,54 +180,78 @@ namespace keepass2android
protected override void OnResume()
{
base.OnResume();
if (!IsFinishing)
if (!IsFinishing && !LaunchingPasswordActivity)
{
if (App.Kp2a.GetDb() == null)
if (App.Kp2a.OpenDatabases.Any() == false)
{
// Load default database
ISharedPreferences prefs = Android.Preferences.PreferenceManager.GetDefaultSharedPreferences(this);
String defaultFileName = prefs.GetString(PasswordActivity.KeyDefaultFilename, "");
if (defaultFileName.Length > 0)
{
try
{
PasswordActivity.Launch(this, LoadIoc(defaultFileName), AppTask);
return;
}
catch (Exception e)
{
Toast.MakeText(this, e.Message, ToastLength.Long);
// Ignore exception
}
}
Intent intent = new Intent(this, typeof(FileSelectActivity));
AppTask.ToIntent(intent);
intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent);
StartFileSelect();
return;
}
if (_loadAnotherDatabase)
{
StartFileSelect();
_loadAnotherDatabase = false;
return;
}
//database loaded
if (App.Kp2a.QuickLocked)
{
var i = new Intent(this, typeof(QuickUnlock));
Util.PutIoConnectionToIntent(App.Kp2a.GetDb().Ioc, i);
Util.PutIoConnectionToIntent(App.Kp2a.GetDbForQuickUnlock().Ioc, i);
Kp2aLog.Log("Starting QuickUnlock");
StartActivityForResult(i, 0);
return;
}
else
//database(s) unlocked
if (App.Kp2a.OpenDatabases.Count() == 1)
{
AppTask.LaunchFirstGroupActivity(this);
return;
}
//more than one database open or user requested to load another db. Don't launch another activity.
_adapter.Update();
_adapter.NotifyDataSetChanged();
}
base.OnResume();
}
protected override void OnPause()
{
LaunchingPasswordActivity = false;
base.OnPause();
}
private void StartFileSelect()
{
Intent intent = new Intent(this, typeof(FileSelectActivity));
AppTask.ToIntent(intent);
intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent);
}
internal AppTask AppTask;
private bool _loadAnotherDatabase;
private OpenDatabaseAdapter _adapter;
public override void OnBackPressed()
{
base.OnBackPressed();
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
{
App.Kp2a.Lock();
}
//by leaving the app with the back button, the user probably wants to cancel the task
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
AppTask = new NullTask();
Finish();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
@@ -104,15 +264,10 @@ namespace keepass2android
switch (resultCode)
{
case KeePass.ExitNormal: // Returned to this screen using the Back key
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
if (App.Kp2a.OpenDatabases.Count() == 1)
{
App.Kp2a.LockDatabase();
OnBackPressed();
}
//by leaving the app with the back button, the user probably wants to cancel the task
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
AppTask = new NullTask();
Finish();
break;
case KeePass.ExitLock:
// The database has already been locked, and the quick unlock screen will be shown if appropriate
@@ -128,18 +283,21 @@ namespace keepass2android
break;
case KeePass.ExitReloadDb:
if (App.Kp2a.GetDb() != null)
if (App.Kp2a.CurrentDb!= null)
{
//remember the composite key for reloading:
var compositeKey = App.Kp2a.GetDb().KpDatabase.MasterKey;
var ioc = App.Kp2a.GetDb().Ioc;
var compositeKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
var ioc = App.Kp2a.CurrentDb.Ioc;
//lock the database:
App.Kp2a.LockDatabase(false);
App.Kp2a.CloseDatabase(App.Kp2a.CurrentDb);
LaunchPasswordActivityForReload(ioc, compositeKey);
}
break;
case KeePass.ExitLoadAnotherDb:
_loadAnotherDatabase = true;
break;
}
@@ -147,7 +305,10 @@ namespace keepass2android
private void LaunchPasswordActivityForReload(IOConnectionInfo ioc, CompositeKey compositeKey)
{
LaunchingPasswordActivity = true;
PasswordActivity.Launch(this, ioc, AppTask, compositeKey);
}
public bool LaunchingPasswordActivity { get; set; }
}
}

View File

@@ -104,13 +104,13 @@ namespace keepass2android
_finish.Filename = _dlg.Keyfile;
}
FingerprintUnlockMode um;
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""), out um);
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).GetString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, ""), out um);
if (um == FingerprintUnlockMode.FullUnlock)
{
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintPrefKey, "");
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString());
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, "");
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString());
edit.Commit();
Toast.MakeText(_dlg.Context, Resource.String.fingerprint_reenable, ToastLength.Long).Show();

View File

@@ -26,6 +26,7 @@ using Android.Views;
using Android.Widget;
using Android.Content.PM;
using Android.Preferences;
using KeePassLib;
using KeePassLib.Utility;
namespace keepass2android
@@ -63,9 +64,6 @@ namespace keepass2android
}
private Database _db;
public override bool IsSearchResult
{
get { return true; }
@@ -78,8 +76,6 @@ namespace keepass2android
//if user presses back to leave this activity:
SetResult(Result.Canceled);
_db = App.Kp2a.GetDb();
UpdateBottomBarElementVisibility(Resource.Id.select_other_entry, true);
UpdateBottomBarElementVisibility(Resource.Id.add_url_entry, true);
@@ -107,24 +103,41 @@ namespace keepass2android
{
try
{
foreach (var db in App.Kp2a.OpenDatabases)
{
PwGroup resultsForThisDb;
//first: search for exact url
Group = _db.SearchForExactUrl(url);
resultsForThisDb = db.SearchForExactUrl(url);
if (!url.StartsWith("androidapp://"))
{
//if no results, search for host (e.g. "accounts.google.com")
if (!Group.Entries.Any())
Group = _db.SearchForHost(url, false);
if (!resultsForThisDb.Entries.Any())
resultsForThisDb = db.SearchForHost(url, false);
//if still no results, search for host, allowing subdomains ("www.google.com" in entry is ok for "accounts.google.com" in search (but not the other way around)
if (!Group.Entries.Any())
Group = _db.SearchForHost(url, true);
if (!resultsForThisDb.Entries.Any())
resultsForThisDb = db.SearchForHost(url, true);
}
//if no results returned up to now, try to search through other fields as well:
if (!Group.Entries.Any())
Group = _db.SearchForText(url);
if (!resultsForThisDb.Entries.Any())
resultsForThisDb = db.SearchForText(url);
//search for host as text
if (!Group.Entries.Any())
Group = _db.SearchForText(UrlUtil.GetHost(url.Trim()));
if (!resultsForThisDb.Entries.Any())
resultsForThisDb = db.SearchForText(UrlUtil.GetHost(url.Trim()));
if (Group == null)
{
Group = resultsForThisDb;
}
else
{
foreach (var entry in resultsForThisDb.Entries)
{
Group.AddEntry(entry, false,false);
}
}
}
} catch (Exception e)
{
@@ -164,7 +177,7 @@ namespace keepass2android
View createUrlEntry = FindViewById (Resource.Id.add_url_entry);
if (App.Kp2a.GetDb().CanWrite)
if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
{
createUrlEntry.Visibility = ViewStates.Visible;
createUrlEntry.Click += (sender, e) =>
@@ -194,5 +207,10 @@ namespace keepass2android
{
get { return Resource.Layout.searchurlresults; }
}
public override bool EntriesBelongToCurrentDatabaseOnly
{
get { return false; }
}
}}

View File

@@ -14,9 +14,11 @@ namespace keepass2android
public void OnOpenEntry()
{
if (App.Kp2a.LastOpenedEntry == null)
return;
foreach (ITotpPluginAdapter adapter in _pluginAdapters)
{
TotpData totpData = adapter.GetTotpData(App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
TotpData totpData = adapter.GetTotpData(App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
if (totpData.IsTotpEnry)
{
new UpdateTotpTimerTask(Application.Context, adapter).Run();

View File

@@ -27,10 +27,10 @@ namespace PluginTOTP
{
try
{
if (App.Kp2a.GetDb().LastOpenedEntry == null)
if (App.Kp2a.LastOpenedEntry == null)
return; //DB was locked
Dictionary<string, string> entryFields = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
Dictionary<string, string> entryFields = App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
//mute warnings to avoid repeated display of the toasts
TotpData totpData = _adapter.GetTotpData(entryFields, _context, true /*mute warnings*/);
if (totpData.IsTotpEnry)
@@ -58,10 +58,10 @@ namespace PluginTOTP
private void UpdateEntryData(string totp)
{
//update the Entry output in the App database and notify the CopyToClipboard service
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(_totp, new ProtectedString(true, totp));
App.Kp2a.LastOpenedEntry.OutputStrings.Set(_totp, new ProtectedString(true, totp));
Intent updateKeyboardIntent = new Intent(_context, typeof(CopyToClipboardService));
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
updateKeyboardIntent.PutExtra("entry", App.Kp2a.GetDb().LastOpenedEntry.Uuid.ToHexString());
updateKeyboardIntent.PutExtra("entry", App.Kp2a.LastOpenedEntry.Uuid.ToHexString());
_context.StartService(updateKeyboardIntent);
}
@@ -73,7 +73,7 @@ namespace PluginTOTP
i.SetPackage(_context.PackageName);
i.PutExtra(Strings.ExtraSender, _context.PackageName);
i.PutExtra(Strings.ExtraFieldValue, totp);
i.PutExtra(Strings.ExtraEntryId, App.Kp2a.GetDb().LastOpenedEntry.Entry.Uuid.ToHexString());
i.PutExtra(Strings.ExtraEntryId, App.Kp2a.LastOpenedEntry.Entry.Uuid.ToHexString());
i.PutExtra(Strings.ExtraFieldId, _totp);
i.PutExtra(Strings.ExtraFieldProtected, true);

View File

@@ -46,20 +46,20 @@ namespace keepass2android
public const String KeyServercredmode = "serverCredRememberMode";
public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i)
public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i, string prefix="")
{
i.PutExtra(KeyFilename, ioc.Path);
i.PutExtra(KeyServerusername, ioc.UserName);
i.PutExtra(KeyServerpassword, ioc.Password);
i.PutExtra(KeyServercredmode, (int)ioc.CredSaveMode);
i.PutExtra(prefix+KeyFilename, ioc.Path);
i.PutExtra(prefix + KeyServerusername, ioc.UserName);
i.PutExtra(prefix + KeyServerpassword, ioc.Password);
i.PutExtra(prefix + KeyServercredmode, (int)ioc.CredSaveMode);
}
public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i)
public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i, string prefix="")
{
ioc.Path = i.GetStringExtra(KeyFilename);
ioc.UserName = i.GetStringExtra(KeyServerusername) ?? "";
ioc.Password = i.GetStringExtra(KeyServerpassword) ?? "";
ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(KeyServercredmode, (int)IOCredSaveMode.NoSave);
ioc.Path = i.GetStringExtra(prefix + KeyFilename);
ioc.UserName = i.GetStringExtra(prefix + KeyServerusername) ?? "";
ioc.Password = i.GetStringExtra(prefix + KeyServerpassword) ?? "";
ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(prefix + KeyServercredmode, (int)IOCredSaveMode.NoSave);
}
public static Bitmap DrawableToBitmap(Drawable drawable)
@@ -558,6 +558,15 @@ namespace keepass2android
int width = (int)(0.9 * context.Resources.GetDimension(Android.Resource.Dimension.NotificationLargeIconWidth));
return Bitmap.CreateScaledBitmap(unscaled, width, height, true);
}
public static string GetProtocolId(IOConnectionInfo ioc)
{
string displayPath = App.Kp2a.GetFileStorage(ioc).GetDisplayName(ioc);
int protocolSeparatorPos = displayPath.IndexOf("://", StringComparison.Ordinal);
string protocolId = protocolSeparatorPos < 0 ?
"file" : displayPath.Substring(0, protocolSeparatorPos);
return protocolId;
}
}
}

View File

@@ -18,6 +18,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Security;
using Android.App;
using Android.Content;
@@ -40,6 +41,7 @@ using TwofishCipher;
using Keepass2android.Pluginsdk;
using keepass2android.Io;
using keepass2android.addons.OtpKeyProv;
using keepass2android.database.edit;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
#if !NoNet
@@ -100,19 +102,19 @@ namespace keepass2android
/// </summary>
public class Kp2aApp: IKp2aApp, ICacheSupervisor
{
public void LockDatabase(bool allowQuickUnlock = true)
public void Lock(bool allowQuickUnlock = true)
{
if (GetDb() != null)
if (OpenDatabases.Any())
{
if (QuickUnlockEnabled && allowQuickUnlock &&
GetDb().KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) &&
!((KcpPassword)App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty)
GetDbForQuickUnlock().KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) &&
!((KcpPassword)App.Kp2a.GetDbForQuickUnlock().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty)
{
if (!QuickLocked)
{
Kp2aLog.Log("QuickLocking database");
QuickLocked = true;
GetDb().LastOpenedEntry = null;
LastOpenedEntry = null;
BroadcastDatabaseAction(Application.Context, Strings.ActionLockDatabase);
}
else
@@ -126,8 +128,10 @@ namespace keepass2android
BroadcastDatabaseAction(Application.Context, Strings.ActionCloseDatabase);
// Couldn't quick-lock, so unload database instead
_db = null;
// Couldn't quick-lock, so unload database(s) instead
_openDatabases.Clear();
_currentDatabase = null;
LastOpenedEntry = null;
QuickLocked = false;
}
}
@@ -142,18 +146,13 @@ namespace keepass2android
public void BroadcastDatabaseAction(Context ctx, string action)
{
foreach (Database db in OpenDatabases)
{
Intent i = new Intent(action);
//seems like this can happen. This code is for debugging.
if (App.Kp2a.GetDb().Ioc == null)
{
Kp2aLog.LogUnexpectedError(new Exception("App.Kp2a.GetDb().Ioc is null"));
return;
}
i.PutExtra(Strings.ExtraDatabaseFileDisplayname, App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).GetDisplayName(App.Kp2a.GetDb().Ioc));
i.PutExtra(Strings.ExtraDatabaseFilepath, App.Kp2a.GetDb().Ioc.Path);
i.PutExtra(Strings.ExtraDatabaseFileDisplayname, GetFileStorage(db.Ioc).GetDisplayName(db.Ioc));
i.PutExtra(Strings.ExtraDatabaseFilepath, db.Ioc.Path);
foreach (var plugin in new PluginDatabase(ctx).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions))
{
i.SetPackage(plugin);
@@ -161,10 +160,11 @@ namespace keepass2android
}
}
}
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey,
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
public Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
var createBackup = prefs.GetBoolean(Application.Context.GetString(Resource.String.CreateBackups_key), true)
@@ -180,8 +180,25 @@ namespace keepass2android
memoryStream.Seek(0, SeekOrigin.Begin);
}
_db = CreateNewDatabase();
_db.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
foreach (Database openDb in _openDatabases)
{
if (openDb.Ioc.IsSameFileAs(ioConnectionInfo))
{
//TODO check this earlier and simply open the database's root group
throw new Exception("Database already loaded!");
}
}
var newDb = new Database(new DrawableFactory(), this);
newDb.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
_currentDatabase = newDb;
_openDatabases.Add(newDb);
if (createBackup)
{
@@ -201,10 +218,13 @@ namespace keepass2android
using (var transaction = new LocalFileStorage(App.Kp2a).OpenWriteTransaction(targetIoc, false))
{
var file = transaction.OpenFile();
using (var file = transaction.OpenFile())
{
backupCopy.CopyTo(file);
transaction.CommitWrite();
}
}
Java.Lang.Object baseIocDisplayName = baseDisplayName;
string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(ioConnectionInfo.Path);
@@ -226,6 +246,50 @@ namespace keepass2android
}
UpdateOngoingNotification();
return newDb;
}
public Database FindDatabaseForEntryId(PwUuid entryKey)
{
foreach (Database db in OpenDatabases)
{
if (db.Entries.ContainsKey(entryKey))
return db;
}
return null;
}
public void CloseDatabase(Database db)
{
if (!_openDatabases.Contains(db))
throw new Exception("Cannot close database which is not open!");
if (_openDatabases.Count == 1)
{
Lock(false);
return;
}
if (LastOpenedEntry != null && db.Entries.ContainsKey(LastOpenedEntry.Uuid))
{
LastOpenedEntry = null;
}
_openDatabases.Remove(db);
if (_currentDatabase == db)
_currentDatabase = _openDatabases.First();
UpdateOngoingNotification();
//TODO broadcast event so affected activities can close/update?
}
public Database FindDatabaseForGroupId(PwUuid groupKey)
{
foreach (Database db in OpenDatabases)
{
if (db.Groups.ContainsKey(groupKey))
return db;
}
return null;
}
internal void UnlockDatabase()
@@ -258,7 +322,7 @@ namespace keepass2android
public bool DatabaseIsUnlocked
{
get { return GetDb() != null && !QuickLocked; }
get { return OpenDatabases.Any() && !QuickLocked; }
}
#region QuickUnlock
@@ -287,8 +351,6 @@ namespace keepass2android
#endregion
private Database _db;
/// <summary>
/// See comments to EntryEditActivityState.
/// </summary>
@@ -297,9 +359,49 @@ namespace keepass2android
public FileDbHelper FileDbHelper;
private List<IFileStorage> _fileStorages;
public Database GetDb()
private readonly List<Database> _openDatabases = new List<Database>();
private Database _currentDatabase;
public IEnumerable<Database> OpenDatabases
{
return _db;
get { return _openDatabases; }
}
public readonly HashSet<PwGroup> dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
public HashSet<PwGroup> DirtyGroups { get { return dirty; } }
public void MarkAllGroupsAsDirty()
{
foreach (var db in OpenDatabases)
foreach (PwGroup group in db.Groups.Values)
{
DirtyGroups.Add(group);
}
}
/// <summary>
/// Information about the last opened entry. Includes the entry but also transformed fields.
/// </summary>
public PwEntryOutput LastOpenedEntry { get; set; }
public Database CurrentDb
{
get { return _currentDatabase; }
set
{
if (!OpenDatabases.Contains(value))
throw new Exception("Cannot set database as current. Not in list of opened databases!");
_currentDatabase = value;
}
}
public Database GetDbForQuickUnlock()
{
return OpenDatabases.FirstOrDefault();
}
@@ -325,16 +427,25 @@ namespace keepass2android
public void CheckForOpenFileChanged(Activity activity)
{
if (GetDb()?.DidOpenFileChange() == true)
if (CurrentDb?.DidOpenFileChange() == true)
{
if (GetDb().ReloadRequested)
if (CurrentDb.ReloadRequested)
{
LockDatabase(false);
activity.SetResult(KeePass.ExitReloadDb);
activity.Finish();
}
else
{
AskForReload(activity);
}
}
}
public void LockSingleDatabase(Database databaseToLock, bool allowQuickUnlock)
{
//TODO implement
throw new Exception("lock single is not implemented");
}
private void AskForReload(Activity activity)
@@ -347,7 +458,7 @@ namespace keepass2android
builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes),
(dlgSender, dlgEvt) =>
{
GetDb().ReloadRequested = true;
CurrentDb.ReloadRequested = true;
activity.SetResult(KeePass.ExitReloadDb);
activity.Finish();
@@ -724,7 +835,8 @@ namespace keepass2android
internal void OnTerminate()
{
_db = null;
_openDatabases.Clear();
_currentDatabase = null;
if (FileDbHelper != null && FileDbHelper.IsOpen())
{
@@ -752,8 +864,9 @@ namespace keepass2android
public Database CreateNewDatabase()
{
_db = new Database(new DrawableFactory(), this);
return _db;
_currentDatabase = new Database(new DrawableFactory(), this);
_openDatabases.Add(_currentDatabase);
return _currentDatabase;
}
internal void ShowToast(string message)
@@ -893,9 +1006,44 @@ namespace keepass2android
Application.Context.GetString(Resource.String.LockWhenScreenOff_key),
false))
{
App.Kp2a.LockDatabase();
App.Kp2a.Lock();
}
}
public Database GetDatabase(IOConnectionInfo dbIoc)
{
foreach (Database db in OpenDatabases)
{
if (db.Ioc.IsSameFileAs(dbIoc))
return db;
}
throw new Exception("Database not found for dbIoc!");
}
public PwGroup FindGroup(PwUuid uuid)
{
PwGroup result;
foreach (Database db in OpenDatabases)
{
if (db.Groups.TryGetValue(uuid, out result))
return result;
}
return null;
}
public IStructureItem FindStructureItem(PwUuid uuid)
{
foreach (Database db in OpenDatabases)
{
PwGroup resultGroup;
if (db.Groups.TryGetValue(uuid, out resultGroup))
return resultGroup;
PwEntry resultEntry;
if (db.Entries.TryGetValue(uuid, out resultEntry))
return resultEntry;
}
return null;
}
}

View File

@@ -344,7 +344,7 @@ namespace keepass2android
activity.StartNotificationsService(false);
}
virtual public void PopulatePasswordAccessServiceIntent(Intent intent)
public virtual void PopulatePasswordAccessServiceIntent(Intent intent)
{
}
@@ -434,7 +434,8 @@ namespace keepass2android
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{
App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor;
if (App.Kp2a.LastOpenedEntry != null)
App.Kp2a.LastOpenedEntry.SearchUrl = UrlToSearchFor;
base.CompleteOnCreateEntryActivity(activity);
}
}
@@ -554,10 +555,11 @@ namespace keepass2android
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{
App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor;
if (App.Kp2a.LastOpenedEntry != null)
App.Kp2a.LastOpenedEntry.SearchUrl = UrlToSearchFor;
//if the database is readonly (or no URL exists), don't offer to modify the URL
if ((App.Kp2a.GetDb().CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
if ((App.Kp2a.CurrentDb.CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
{
base.CompleteOnCreateEntryActivity(activity);
return;
@@ -790,6 +792,7 @@ namespace keepass2android
#endif
private LinkedList<string> _groupUuid;
private readonly Database _db;
protected AppTask TaskToBeLaunchedAfterNavigation;
protected String FullGroupName {
@@ -814,7 +817,8 @@ namespace keepass2android
/// <param name="groups">Groups.</param>
/// <param name="taskToBeLaunchedAfterNavigation">Task to be launched after navigation.</param>
/// <param name="toastEnable">If set to <c>true</c>, toast will be displayed after navigation.</param>
protected NavigateAndLaunchTask(PwGroup groups, AppTask taskToBeLaunchedAfterNavigation, bool toastEnable = false) {
protected NavigateAndLaunchTask(Database db, PwGroup groups, AppTask taskToBeLaunchedAfterNavigation, bool toastEnable = false) {
_db = db;
TaskToBeLaunchedAfterNavigation = taskToBeLaunchedAfterNavigation;
PopulateGroups (groups);
ToastEnable = toastEnable;
@@ -943,7 +947,7 @@ namespace keepass2android
PwUuid nextGroupPwUuid = new PwUuid (MemUtil.HexStringToByteArray (nextGroupUuid));
// Create Group Activity
PwGroup nextGroup = App.Kp2a.GetDb ().Groups[nextGroupPwUuid];
PwGroup nextGroup = _db.Groups[nextGroupPwUuid];
GroupActivity.Launch (groupBaseActivity, nextGroup, this);
}
return;
@@ -968,12 +972,9 @@ namespace keepass2android
public class NavigateToFolder: NavigateAndLaunchTask {
public NavigateToFolder()
{
}
public NavigateToFolder(PwGroup groups, bool toastEnable = false)
: base(groups, new NullTask(), toastEnable)
public NavigateToFolder(Database db, PwGroup groups, bool toastEnable = false)
: base(db, groups, new NullTask(), toastEnable)
{
}
@@ -981,14 +982,9 @@ namespace keepass2android
public class NavigateToFolderAndLaunchMoveElementTask: NavigateAndLaunchTask {
public NavigateToFolderAndLaunchMoveElementTask()
{
}
public NavigateToFolderAndLaunchMoveElementTask(PwGroup groups, List<PwUuid> uuids, bool toastEnable = false)
:base(groups, new MoveElementsTask() { Uuids = uuids }, toastEnable) {
public NavigateToFolderAndLaunchMoveElementTask(Database db, PwGroup groups, List<PwUuid> uuids, bool toastEnable = false)
:base(db, groups, new MoveElementsTask() { Uuids = uuids }, toastEnable) {
}
public override void Setup(Bundle b) {

View File

@@ -17,10 +17,10 @@ namespace keepass2android
switch (intent.Action)
{
case Intents.LockDatabase:
App.Kp2a.LockDatabase();
App.Kp2a.Lock();
break;
case Intents.CloseDatabase:
App.Kp2a.LockDatabase(false /*no quick unlock*/);
App.Kp2a.Lock(false /*no quick unlock*/);
break;
}
}

View File

@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Database;
@@ -140,7 +141,6 @@ namespace keepass2android
intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int) SelectStorageLocationActivity.WritableRequirements.WriteDesired);
intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false);
StartActivityForResult(intent, RequestCodeSelectIoc);
};
openFileButton.Click += openFileButtonClick;
@@ -151,7 +151,9 @@ namespace keepass2android
//ShowFilenameDialog(false, true, true, Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path), "", Intents.RequestCodeFileBrowseForCreate)
Intent i = new Intent(this, typeof (CreateDatabaseActivity));
this.AppTask.ToIntent(i);
StartActivityForResult(i, 0);
i.SetFlags(ActivityFlags.ForwardResult);
StartActivity(i);
Finish();
};
createNewButton.Click += createNewButtonClick;
@@ -460,15 +462,9 @@ namespace keepass2android
base.OnStart();
Kp2aLog.Log("FileSelect.OnStart");
var db = App.Kp2a.GetDb();
if (db != null)
{
LaunchPasswordActivityForIoc(db.Ioc);
}
else
{
//if no database is loaded: load the most recent database
if ( (Intent.GetBooleanExtra(NoForwardToPasswordActivity, false)==false) && _dbHelper.HasRecentFiles())
if ( (Intent.GetBooleanExtra(NoForwardToPasswordActivity, false)==false) && _dbHelper.HasRecentFiles() && !App.Kp2a.OpenDatabases.Any())
{
ICursor filesCursor = _dbHelper.FetchAllFiles();
StartManagingCursor(filesCursor);
@@ -479,7 +475,7 @@ namespace keepass2android
LaunchPasswordActivityForIoc(ioc);
}
}
}
}

View File

@@ -1885,6 +1885,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_storage_nextcloud.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\open_db_selection.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">

View File

@@ -47,6 +47,7 @@ namespace keepass2android.search
private const string GetIconPathQuery = "get_icon";
private const string IconIdParameter = "IconId";
private const string CustomIconUuidParameter = "CustomIconUuid";
private const string DatabaseIndexParameter = "DatabaseIndex";
private static UriMatcher UriMatcher = BuildUriMatcher();
@@ -77,10 +78,25 @@ namespace keepass2android.search
if (!String.IsNullOrEmpty(searchString))
{
try
{
List<EntryListCursor.EntryWithContext> entriesWithContext = new List<EntryListCursor.EntryWithContext>();
int dbIndex = 0;
foreach (var db in App.Kp2a.OpenDatabases)
{
var resultsContexts = new Dictionary<PwUuid, KeyValuePair<string, string>>();
var result = App.Kp2a.GetDb().Search(new SearchParameters { SearchString = searchString }, resultsContexts );
return new GroupCursor(result, resultsContexts);
PwGroup group = db.Search(new SearchParameters { SearchString = searchString }, resultsContexts);
foreach (var entry in group.Entries)
{
KeyValuePair<string, string> context;
resultsContexts.TryGetValue(entry.Uuid, out context);
entriesWithContext.Add(new EntryListCursor.EntryWithContext(entry, context, dbIndex));
}
dbIndex++;
}
return new EntryListCursor(entriesWithContext);
}
catch (Exception e)
{
@@ -116,8 +132,12 @@ namespace keepass2android.search
case UriMatches.GetIcon:
var iconId = (PwIcon)Enum.Parse(typeof(PwIcon), uri.GetQueryParameter(IconIdParameter));
var customIconUuid = new PwUuid(MemUtil.HexStringToByteArray(uri.GetQueryParameter(CustomIconUuidParameter)));
int databaseIndex = int.Parse(uri.GetQueryParameter(DatabaseIndexParameter));
List<Database> databases = App.Kp2a.OpenDatabases.ToList();
Database database = databases[databaseIndex];
var iconDrawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(App.Context, App.Kp2a.GetDb().KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
var iconDrawable = database.DrawableFactory.GetIconDrawable(App.Context, database.KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
if (iconDrawable?.Bitmap != null)
{
@@ -186,8 +206,10 @@ namespace keepass2android.search
#endregion
private class GroupCursor : AbstractCursor
private class EntryListCursor : AbstractCursor
{
private readonly List<EntryWithContext> _entriesWithContexts;
private static readonly string[] ColumnNames = new[] { Android.Provider.BaseColumns.Id,
SearchManager.SuggestColumnText1,
SearchManager.SuggestColumnText2,
@@ -195,20 +217,30 @@ namespace keepass2android.search
SearchManager.SuggestColumnIntentDataId,
};
private readonly PwGroup mGroup;
private readonly IDictionary<PwUuid, KeyValuePair<string, string>> mResultContexts;
public GroupCursor(PwGroup group, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts)
public struct EntryWithContext
{
System.Diagnostics.Debug.Assert(!group.Groups.Any(), "Expecting a flat list of groups");
public readonly PwEntry entry;
public readonly KeyValuePair<string, string> resultContext;
public readonly int DatabaseIndex;
mGroup = group;
mResultContexts = resultContexts;
public EntryWithContext(PwEntry entry, KeyValuePair<string, string> mResultContext, int databaseIndex)
{
this.entry = entry;
this.resultContext = mResultContext;
DatabaseIndex = databaseIndex;
}
}
public EntryListCursor(List<EntryWithContext> entriesWithContexts)
{
_entriesWithContexts = entriesWithContexts;
}
public override int Count
{
get { return (int)Math.Min(mGroup.GetEntriesCount(false), int.MaxValue); }
get { return _entriesWithContexts.Count; }
}
public override string[] GetColumnNames()
@@ -231,7 +263,10 @@ namespace keepass2android.search
{
get
{
return mGroup.Entries.GetAt((uint)MPos);
if (MPos < _entriesWithContexts.Count)
return _entriesWithContexts[MPos].entry;
return null;
}
}
@@ -255,12 +290,9 @@ namespace keepass2android.search
case 1: // SuggestColumnText1
return CurrentEntry.Strings.ReadSafe(PwDefs.TitleField);
case 2: // SuggestColumnText2
KeyValuePair<string, string> context;
if (mResultContexts.TryGetValue(CurrentEntry.Uuid, out context))
{
return Internationalise(context);
}
return null;
if (MPos < _entriesWithContexts.Count)
return Internationalise(_entriesWithContexts[MPos].resultContext);
return "";
case 3: // SuggestColumnIcon1
var builder = new Android.Net.Uri.Builder();
builder.Scheme(ContentResolver.SchemeContent);
@@ -268,6 +300,7 @@ namespace keepass2android.search
builder.Path(GetIconPathQuery);
builder.AppendQueryParameter(IconIdParameter, CurrentEntry.IconId.ToString());
builder.AppendQueryParameter(CustomIconUuidParameter, CurrentEntry.CustomIconUuid.ToHexString());
builder.AppendQueryParameter(DatabaseIndexParameter, _entriesWithContexts[MPos].DatabaseIndex.ToString());
return builder.Build().ToString();
case 4: // SuggestColumnIntentDataId
return CurrentEntry.Uuid.ToHexString();

View File

@@ -56,15 +56,10 @@ namespace keepass2android.search
ProcessIntent(Intent);
}
protected override bool AddEntryEnabled
public override bool EntriesBelongToCurrentDatabaseOnly
{
get { return false; }
}
protected override bool AddGroupEnabled
{
get { return false; }
}
protected override void OnNewIntent(Intent intent)
@@ -97,8 +92,21 @@ namespace keepass2android.search
private void Query (SearchParameters searchParams)
{
Group = null;
try {
Group = App.Kp2a.GetDb().Search (searchParams, null);
foreach (var db in App.Kp2a.OpenDatabases)
{
PwGroup resultsForThisDb = db.Search(searchParams, null);
if (Group == null)
Group = resultsForThisDb;
else
{
foreach (var entry in resultsForThisDb.Entries)
{
Group.AddEntry(entry, false);
}
}
}
} catch (Exception e) {
Kp2aLog.LogUnexpectedError(e);
Toast.MakeText(this,e.Message, ToastLength.Long).Show();

View File

@@ -35,6 +35,7 @@ using KeePassLib;
using KeePassLib.Utility;
using Android.Views.InputMethods;
using KeePass.Util.Spr;
using KeePassLib.Serialization;
namespace keepass2android
{
@@ -292,19 +293,21 @@ namespace keepass2android
PwEntryOutput entry;
try
{
if ((App.Kp2a.GetDb().LastOpenedEntry != null)
&& (entryId.Equals(App.Kp2a.GetDb().LastOpenedEntry.Uuid)))
if ((App.Kp2a.LastOpenedEntry != null)
&& (entryId.Equals(App.Kp2a.LastOpenedEntry.Uuid)))
{
entry = App.Kp2a.GetDb().LastOpenedEntry;
entry = App.Kp2a.LastOpenedEntry;
}
else
{
entry = new PwEntryOutput(App.Kp2a.GetDb().Entries[entryId], App.Kp2a.GetDb().KpDatabase);
Database entryDb = App.Kp2a.FindDatabaseForEntryId(entryId);
entry = new PwEntryOutput(entryDb.Entries[entryId], entryDb);
}
}
catch (Exception)
catch (Exception e)
{
Kp2aLog.LogUnexpectedError(e);
//seems like restarting the service happened after closing the DB
StopSelf();
return StartCommandResult.NotSticky;
@@ -400,9 +403,10 @@ namespace keepass2android
var hadKeyboardData = ClearNotifications();
String entryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);
Database db = App.Kp2a.FindDatabaseForEntryId(entry.Uuid);
var bmp = Util.DrawableToBitmap(App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this,
App.Kp2a.GetDb().KpDatabase, entry.Entry.IconId, entry.Entry.CustomIconUuid, false));
var bmp = Util.DrawableToBitmap(db.DrawableFactory.GetIconDrawable(this,
db.KpDatabase, entry.Entry.IconId, entry.Entry.CustomIconUuid, false));
if (!(((entry.Entry.CustomIconUuid != null) && (!entry.Entry.CustomIconUuid.Equals(PwUuid.Zero))))
@@ -807,7 +811,7 @@ namespace keepass2android
//check if we have a last opened entry
//this should always be non-null, but if the OS has killed the app, it might occur.
if (App.Kp2a.GetDb().LastOpenedEntry == null)
if (App.Kp2a.LastOpenedEntry == null)
{
Intent i = new Intent(context, typeof(AppKilledInfo));
i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
@@ -817,7 +821,7 @@ namespace keepass2android
if (action.Equals(Intents.CopyUsername))
{
String username = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.UserNameField);
String username = App.Kp2a.LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.UserNameField);
if (username.Length > 0)
{
CopyToClipboardService.CopyValueToClipboardWithTimeout(context, username);
@@ -826,7 +830,7 @@ namespace keepass2android
}
else if (action.Equals(Intents.CopyPassword))
{
String password = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.PasswordField);
String password = App.Kp2a.LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.PasswordField);
if (password.Length > 0)
{
CopyToClipboardService.CopyValueToClipboardWithTimeout(context, password);

View File

@@ -28,7 +28,7 @@ namespace keepass2android.services.Kp2aAutofill
{
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later
Intent i = new Intent(this, typeof(FileSelectActivity));
Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
//don't show user notifications when an entry is opened.
var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false, AutoReturnFromQuery = autoReturnFromQuery };
task.ToIntent(i);
@@ -39,9 +39,9 @@ namespace keepass2android.services.Kp2aAutofill
protected override FilledAutofillFieldCollection GetDataset(Intent data)
{
if (App.Kp2a.GetDb()==null || (App.Kp2a.QuickLocked))
if (App.Kp2a.CurrentDb==null || (App.Kp2a.QuickLocked))
return null;
var entryOutput = App.Kp2a.GetDb().LastOpenedEntry;
var entryOutput = App.Kp2a.LastOpenedEntry;
return GetFilledAutofillFieldCollectionFromEntry(entryOutput, this);
}

View File

@@ -33,9 +33,9 @@ namespace keepass2android.services
protected override FilledAutofillFieldCollection GetSuggestedEntry(string query)
{
if (App.Kp2a.GetDb()?.LastOpenedEntry?.SearchUrl == query)
if (App.Kp2a.LastOpenedEntry?.SearchUrl == query)
return ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry(
App.Kp2a.GetDb()?.LastOpenedEntry, this);
App.Kp2a.LastOpenedEntry, this);
return null;
}
@@ -43,7 +43,7 @@ namespace keepass2android.services
{
var intent = new Intent(this, typeof(FileSelectActivity));
var intent = new Intent(this, typeof(SelectCurrentDbActivity));
Dictionary<string, string> outputFields = new Dictionary<string, string>();
foreach (var p in parser.ClientFormData.HintMap)

View File

@@ -26,7 +26,7 @@ namespace keepass2android.services
public Intent GetRestartAppIntent(Context context)
{
var intent = new Intent(context, typeof(FileSelectActivity));
var intent = new Intent(context, typeof(SelectCurrentDbActivity));
intent.AddFlags(ActivityFlags.ForwardResult);
return intent;
}

View File

@@ -97,7 +97,7 @@ namespace keepass2android
Kp2aLog.Log("OngoingNotificationsService.OnTaskRemoved: " + rootIntent.Action);
// If the user has closed the task (probably by swiping it out of the recent apps list) then lock the database
App.Kp2a.LockDatabase();
App.Kp2a.Lock();
}
public override void OnDestroy()
@@ -111,7 +111,7 @@ namespace keepass2android
// If the service is killed, then lock the database immediately
if (App.Kp2a.DatabaseIsUnlocked)
{
App.Kp2a.LockDatabase(false);
App.Kp2a.Lock(false);
}
UnregisterReceiver(_screenOffReceiver);
@@ -228,16 +228,22 @@ namespace keepass2android
private static string GetDatabaseName()
{
var db = App.Kp2a.GetDb().KpDatabase;
var name = db.Name;
if (String.IsNullOrEmpty(name))
string displayString = "";
foreach (Database db in App.Kp2a.OpenDatabases)
{
var kpDatabase = db.KpDatabase;
var dbname = kpDatabase.Name;
if (String.IsNullOrEmpty(dbname))
{
//todo: if paranoid ("don't remember recent files") return "***"
name = App.Kp2a.GetFileStorage(db.IOConnectionInfo).GetFilenameWithoutPathAndExt(db.IOConnectionInfo);
dbname = App.Kp2a.GetFileStorage(kpDatabase.IOConnectionInfo).GetFilenameWithoutPathAndExt(kpDatabase.IOConnectionInfo);
}
if (displayString != "")
displayString = displayString + ", ";
displayString += dbname;
}
return name;
return displayString;
}
#endregion

View File

@@ -18,8 +18,8 @@ namespace keepass2android.settings
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
@@ -29,7 +29,7 @@ namespace keepass2android.settings
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamIterations, value);
App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamIterations, value);
}
}
}
@@ -50,8 +50,8 @@ namespace keepass2android.settings
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
@@ -61,7 +61,7 @@ namespace keepass2android.settings
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt32(Argon2Kdf.ParamParallelism, (uint) value);
App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt32(Argon2Kdf.ParamParallelism, (uint) value);
}
}
}
@@ -82,8 +82,8 @@ namespace keepass2android.settings
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
@@ -93,7 +93,7 @@ namespace keepass2android.settings
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamMemory, value);
App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamMemory, value);
}
}
}

View File

@@ -423,7 +423,7 @@ namespace keepass2android
FindPreference(GetString(Resource.String.design_key)).PreferenceChange += (sender, args) => Activity.Recreate();
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
if (db != null)
{
ListPreference kdfPref = (ListPreference) FindPreference(GetString(Resource.String.kdf_key));
@@ -457,7 +457,7 @@ namespace keepass2android
algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index);
algorithmPref.PreferenceChange += AlgorithmPrefChange;
algorithmPref.Summary =
CipherPool.GlobalPool.GetCipher(App.Kp2a.GetDb().KpDatabase.DataCipherUuid).DisplayName;
CipherPool.GlobalPool.GetCipher(App.Kp2a.CurrentDb.KpDatabase.DataCipherUuid).DisplayName;
UpdateImportDbPref();
UpdateImportKeyfilePref();
}
@@ -504,8 +504,8 @@ namespace keepass2android
FindPreference("IconSetKey").PreferenceChange += (sender, args) =>
{
if (App.Kp2a.GetDb() != null)
App.Kp2a.GetDb().DrawableFactory.Clear();
if (App.Kp2a.CurrentDb!= null)
App.Kp2a.CurrentDb.DrawableFactory.Clear();
};
@@ -565,11 +565,11 @@ namespace keepass2android
private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{
var db = App.Kp2a.GetDb();
var db = App.Kp2a.CurrentDb;
var previousCipher = db.KpDatabase.DataCipherUuid;
db.KpDatabase.DataCipherUuid = new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue));
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) =>
SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{
if (!success)
{
@@ -586,7 +586,7 @@ namespace keepass2android
private void UpdateKdfScreen()
{
var db = App.Kp2a.GetDb();
var db = App.Kp2a.CurrentDb;
var kdf = KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid);
var kdfpref = FindPreference(GetString(Resource.String.kdf_key));
@@ -624,7 +624,7 @@ namespace keepass2android
private void OnKdfChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{
var db = App.Kp2a.GetDb();
var db = App.Kp2a.CurrentDb;
var previousKdfParams = db.KpDatabase.KdfParameters;
Kp2aLog.Log("previous kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString() );
db.KpDatabase.KdfParameters =
@@ -634,7 +634,7 @@ namespace keepass2android
Kp2aLog.Log("--new kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString());
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) =>
SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{
if (!success)
{
@@ -669,7 +669,7 @@ namespace keepass2android
private void PrepareTemplates(Database db)
{
Preference pref = FindPreference("AddTemplates_pref_key");
if ((!db.DatabaseFormat.SupportsTemplates) || (AddTemplateEntries.ContainsAllTemplates(App.Kp2a)))
if ((!db.DatabaseFormat.SupportsTemplates) || (AddTemplateEntries.ContainsAllTemplates(App.Kp2a.CurrentDb)))
{
pref.Enabled = false;
}
@@ -692,7 +692,7 @@ namespace keepass2android
private void PrepareMasterPassword()
{
Preference changeMaster = FindPreference(GetString(Resource.String.master_pwd_key));
if (App.Kp2a.GetDb().CanWrite)
if (App.Kp2a.CurrentDb.CanWrite)
{
changeMaster.Enabled = true;
changeMaster.PreferenceClick += delegate { new SetPasswordDialog(Activity).Show(); };
@@ -717,7 +717,7 @@ namespace keepass2android
String previousName = db.KpDatabase.Name;
db.KpDatabase.Name = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) =>
SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{
if (!success)
{
@@ -755,7 +755,7 @@ namespace keepass2android
String previousUsername = db.KpDatabase.DefaultUserName;
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) =>
SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{
if (!success)
{
@@ -791,8 +791,8 @@ namespace keepass2android
private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e)
{
//ensure the user gets a matching database
if (App.Kp2a.GetDb() != null && !App.Kp2a.GetDb().Ioc.IsLocalFile())
App.Kp2a.LockDatabase(false);
if (App.Kp2a.CurrentDb!= null && !App.Kp2a.CurrentDb.Ioc.IsLocalFile())
App.Kp2a.LockSingleDatabase(App.Kp2a.CurrentDb, false);
if (!(bool)e.NewValue)
{
@@ -842,7 +842,7 @@ namespace keepass2android
importDb.Enabled = false;
return;
}
CompositeKey masterKey = App.Kp2a.GetDb().KpDatabase.MasterKey;
CompositeKey masterKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
if (masterKey.ContainsType(typeof(KcpKeyFile)))
{
IOConnectionInfo iocKeyfile = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
@@ -871,12 +871,12 @@ namespace keepass2android
{
try
{
CompositeKey masterKey = App.Kp2a.GetDb().KpDatabase.MasterKey;
CompositeKey masterKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
var sourceIoc = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).ResetIoc(newIoc);
var keyfileString = IOConnectionInfo.SerializeToString(newIoc);
App.Kp2a.StoreOpenedFileAsRecent(App.Kp2a.GetDb().Ioc, keyfileString);
App.Kp2a.StoreOpenedFileAsRecent(App.Kp2a.CurrentDb.Ioc, keyfileString);
return () =>
{
UpdateImportKeyfilePref();
@@ -914,7 +914,7 @@ namespace keepass2android
//Import db/key file preferences:
Preference importDb = FindPreference("import_db_prefs");
bool isLocalOrContent =
App.Kp2a.GetDb().Ioc.IsLocalFile() || App.Kp2a.GetDb().Ioc.Path.StartsWith("content://");
App.Kp2a.CurrentDb.Ioc.IsLocalFile() || App.Kp2a.CurrentDb.Ioc.Path.StartsWith("content://");
if (!isLocalOrContent)
{
importDb.Summary = GetString(Resource.String.OnlyAvailableForLocalFiles);
@@ -922,7 +922,7 @@ namespace keepass2android
}
else
{
if (IoUtil.IsInInternalDirectory(App.Kp2a.GetDb().Ioc.Path, Activity))
if (IoUtil.IsInInternalDirectory(App.Kp2a.CurrentDb.Ioc.Path, Activity))
{
importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory);
importDb.Enabled = false;
@@ -941,7 +941,7 @@ namespace keepass2android
{
try
{
var sourceIoc = App.Kp2a.GetDb().Ioc;
var sourceIoc = App.Kp2a.CurrentDb.Ioc;
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
return () =>
{
@@ -949,7 +949,12 @@ namespace keepass2android
builder
.SetMessage(Resource.String.DatabaseFileMoved);
builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) =>
PasswordActivity.Launch(Activity, newIoc, new NullTask(), App.Kp2a.GetDb().KpDatabase.MasterKey));
{
var key = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
App.Kp2a.CloseDatabase(App.Kp2a.CurrentDb);
PasswordActivity.Launch(Activity, newIoc, new NullTask(), key);
});
builder.Show();
};

View File

@@ -77,7 +77,7 @@ namespace keepass2android.settings
paramValue = 1;
}
Database db = App.Kp2a.GetDb();
Database db = App.Kp2a.CurrentDb;
ulong oldValue = ParamValue;
@@ -89,7 +89,7 @@ namespace keepass2android.settings
ParamValue = paramValue;
Handler handler = new Handler();
SaveDb save = new SaveDb((Activity)Context, App.Kp2a, new KdfNumberParamPreference.AfterSave((Activity)Context, handler, oldValue, this));
SaveDb save = new SaveDb((Activity)Context, App.Kp2a, App.Kp2a.CurrentDb, new KdfNumberParamPreference.AfterSave((Activity)Context, handler, oldValue, this));
ProgressTask pt = new ProgressTask(App.Kp2a, (Activity)Context, save);
pt.Run();
@@ -118,7 +118,7 @@ namespace keepass2android.settings
} else {
DisplayMessage(_ctx);
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, _oldRounds);
App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, _oldRounds);
}
base.Run();
@@ -140,18 +140,18 @@ namespace keepass2android.settings
get
{
AesKdf kdf = new AesKdf();
if (!kdf.Uuid.Equals(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid))
if (!kdf.Uuid.Equals(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid))
return (uint) PwDefs.DefaultKeyEncryptionRounds;
else
{
ulong uRounds = App.Kp2a.GetDb().KpDatabase.KdfParameters.GetUInt64(
ulong uRounds = App.Kp2a.CurrentDb.KpDatabase.KdfParameters.GetUInt64(
AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds);
uRounds = Math.Min(uRounds, 0xFFFFFFFEUL);
return (uint) uRounds;
}
}
set { App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); }
set { App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); }
}
public RoundsPreference(Context context, IAttributeSet attrs):base(context, attrs)

View File

@@ -83,7 +83,7 @@ namespace keepass2android
public static void Resume(Activity act)
{
if ( App.Kp2a.GetDb() != null)
if ( App.Kp2a.CurrentDb!= null)
{
Timeout.Cancel(act);
}
@@ -92,14 +92,13 @@ namespace keepass2android
static bool IocChanged(IOConnectionInfo ioc, IOConnectionInfo other)
{
if ((ioc == null) || (other == null)) return false;
return ioc.GetDisplayName() != other.GetDisplayName();
return !ioc.IsSameFileAs(other);
}
public static bool CheckShutdown(Activity act, IOConnectionInfo ioc) {
public static bool CheckDbChanged(Activity act, IOConnectionInfo ioc) {
if (( !App.Kp2a.DatabaseIsUnlocked )
|| (IocChanged(ioc, App.Kp2a.GetDb().Ioc))) //file was changed from ActionSend-Intent
|| (IocChanged(ioc, App.Kp2a.CurrentDb.Ioc))) //file was changed from ActionSend-Intent
{
App.Kp2a.LockDatabase();
return true;
}
return false;

View File

@@ -71,8 +71,9 @@ namespace keepass2android.view
_textView = (TextView)ev.FindViewById(Resource.Id.entry_text);
_textView.TextSize = PrefsUtil.GetListTextSize(groupActivity);
Database db = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
ev.FindViewById(Resource.Id.entry_icon_bkg).Visibility = App.Kp2a.GetDb().DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
ev.FindViewById(Resource.Id.entry_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
_textviewDetails = (TextView)ev.FindViewById(Resource.Id.entry_text_detail);
_textviewDetails.TextSize = PrefsUtil.GetListDetailTextSize(groupActivity);
@@ -106,15 +107,16 @@ namespace keepass2android.view
ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
Database db = App.Kp2a.FindDatabaseForEntryId(_entry.Uuid);
ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon);
bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now;
if (isExpired)
{
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, Context, App.Kp2a.GetDb().KpDatabase, PwIcon.Expired, PwUuid.Zero, false);
db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, PwIcon.Expired, PwUuid.Zero, false);
} else
{
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, Context, App.Kp2a.GetDb().KpDatabase, pw.IconId, pw.CustomIconUuid, false);
db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, pw.IconId, pw.CustomIconUuid, false);
}
String title = pw.Strings.ReadSafe(PwDefs.TitleField);
@@ -138,7 +140,7 @@ namespace keepass2android.view
_textView.SetTextColor(new Color((int)_defaultTextColor));
String detail = pw.Strings.ReadSafe(PwDefs.UserNameField);
detail = SprEngine.Compile(detail, new SprContext(_entry, App.Kp2a.GetDb().KpDatabase, SprCompileFlags.All));
detail = SprEngine.Compile(detail, new SprContext(_entry, db.KpDatabase, SprCompileFlags.All));
if ((_showDetail == false) || (String.IsNullOrEmpty(detail)))
{

View File

@@ -63,7 +63,9 @@ namespace keepass2android.view
_label = (TextView) gv.FindViewById(Resource.Id.group_label);
_label.TextSize = size-8;
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = App.Kp2a.GetDb().DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
@@ -79,7 +81,8 @@ namespace keepass2android.view
_pwGroup = pw;
ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _groupBaseActivity, App.Kp2a.GetDb().KpDatabase, pw.IconId, pw.CustomIconUuid, true);
Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
db.DrawableFactory.AssignDrawableTo(iv, _groupBaseActivity, db.KpDatabase, pw.IconId, pw.CustomIconUuid, true);
gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;