allow opening several databases which contain elements with same IDs (required as KeepassHttp stores their settings in an entry with a fixed ID)

This commit is contained in:
Philipp Crocoll
2018-11-11 06:35:06 +01:00
parent b2d791d6ea
commit f37c0a9124
39 changed files with 554 additions and 286 deletions

View File

@@ -65,9 +65,9 @@
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedJar Include="..\java\KP2AKdbLibrary\bin\kp2akdblibrary.jar">
<InputJar Include="..\java\KP2AKdbLibrary\bin\kp2akdblibrary.jar">
<Link>Jars\kp2akdblibrary.jar</Link>
</EmbeddedJar>
</InputJar>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -0,0 +1,47 @@
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 keepass2android.Io;
using KeePassLib;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
namespace keepass2android
{
public class ElementAndDatabaseId
{
private const char Separator = '+';
public ElementAndDatabaseId(Database db, IStructureItem element)
{
DatabaseId = db.IocAsHexString();
ElementIdString = element.Uuid.ToHexString();
}
public ElementAndDatabaseId(string fullId)
{
string[] parts = fullId.Split(Separator);
if (parts.Length != 2)
throw new Exception("Invalid full id " + fullId);
DatabaseId = parts[0];
ElementIdString = parts[1];
}
public string DatabaseId { get; set; }
public string ElementIdString { get; set; }
public PwUuid ElementId { get { return new PwUuid(MemUtil.HexStringToByteArray(ElementIdString));} }
public string FullId
{
get { return DatabaseId + Separator + ElementIdString; }
}
}
}

View File

@@ -10,6 +10,7 @@ using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using keepass2android.Io;
using KeePassLib.Interfaces;
#if !NoNet
using Keepass2android.Javafilestorage;
#endif
@@ -58,8 +59,7 @@ namespace keepass2android
IEnumerable<Database> OpenDatabases { get; }
void CloseDatabase(Database db);
Database FindDatabaseForGroupId(PwUuid groupKey);
Database FindDatabaseForEntryId(PwUuid entryId);
Database FindDatabaseForElement(IStructureItem element);
/// <summary>
/// Tell the app that the file from ioc was opened with keyfile.
@@ -129,5 +129,6 @@ namespace keepass2android
#endif
}
}

View File

@@ -90,7 +90,6 @@
<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\DeleteMultipleItemsFromOneDatabase.cs" />
<Compile Include="database\edit\EditGroup.cs" />
@@ -104,6 +103,7 @@
<Compile Include="DataExchange\Formats\KeePassKdb2x.cs" />
<Compile Include="DataExchange\Formats\KeePassXml2x.cs" />
<Compile Include="DataExchange\PwExportInfo.cs" />
<Compile Include="ElementAndDatabaseId.cs" />
<Compile Include="Io\AndroidContentStorage.cs" />
<Compile Include="Io\BuiltInFileStorage.cs" />
<Compile Include="Io\CachingFileStorage.cs" />

View File

@@ -103,7 +103,7 @@ namespace keepass2android
PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) {IsVirtual = true};
if (String.IsNullOrWhiteSpace(host))
return pgResults;
foreach (PwEntry entry in database.Entries.Values)
foreach (PwEntry entry in database.EntriesById.Values)
{
string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField);
otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References));

View File

@@ -87,9 +87,6 @@ namespace keepass2android
ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup,
UpdatingTemplateIds,
ChangleLegacyTemplateIds_Message,
ChangleLegacyTemplateIds_Title,
Ok,
cancel
}

View File

@@ -26,6 +26,7 @@ using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using keepass2android.Io;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
using Exception = System.Exception;
using String = System.String;
@@ -33,18 +34,20 @@ using String = System.String;
namespace keepass2android
{
public class Database {
public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
public class Database
{
public HashSet<IStructureItem> Elements = new HashSet<IStructureItem>();
public Dictionary<PwUuid, PwGroup> GroupsById = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
public Dictionary<PwUuid, PwEntry> EntriesById = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
public PwGroup Root;
public PwDatabase KpDatabase;
public IOConnectionInfo Ioc
{
get
{
return KpDatabase?.IOConnectionInfo;
}
}
@@ -203,16 +206,18 @@ namespace keepass2android
{
if (checkForDuplicateUuids)
{
if (Entries.ContainsKey(e.Uuid))
if (EntriesById.ContainsKey(e.Uuid))
{
throw new DuplicateUuidsException("Same UUID for entries '"+Entries[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'.");
throw new DuplicateUuidsException("Same UUID for entries '"+EntriesById[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'.");
}
}
Entries [e.Uuid] = e;
EntriesById [e.Uuid] = e;
Elements.Add(e);
}
Groups[currentGroup.Uuid] = currentGroup;
GroupsById[currentGroup.Uuid] = currentGroup;
Elements.Add(currentGroup);
foreach (PwGroup g in childGroups)
{
if (checkForDuplicateUuids)
@@ -235,8 +240,9 @@ namespace keepass2android
public void UpdateGlobals()
{
Entries.Clear();
Groups.Clear();
EntriesById.Clear();
GroupsById.Clear();
Elements.Clear();
PopulateGlobals(Root);
}
}

View File

@@ -73,6 +73,8 @@ namespace keepass2android
}), _app.CurrentDb, false, remoteData);
_saveDb.Run();
_app.CurrentDb.UpdateGlobals();
_app.MarkAllGroupsAsDirty();
}
else

View File

@@ -87,7 +87,8 @@ namespace keepass2android
_app.DirtyGroups.Add(parent);
// Add entry to global
_db.Entries[_entry.Uuid] = _entry;
_db.EntriesById[_entry.Uuid] = _entry;
_db.Elements.Add(_entry);
} else
{

View File

@@ -70,6 +70,8 @@ namespace keepass2android
Group.CustomIconUuid = _groupCustomIconId;
}
Parent.AddGroup(Group, true);
_app.CurrentDb.GroupsById[Group.Uuid] = Group;
_app.CurrentDb.Elements.Add(Group);
// Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave);
@@ -92,10 +94,12 @@ namespace keepass2android
_addGroup.App.DirtyGroups.Add(_addGroup.Parent);
// Add group to global list
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
_addGroup.Db.GroupsById[_addGroup.Group.Uuid] = _addGroup.Group;
_addGroup.Db.Elements.Add(_addGroup.Group);
} else {
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
_addGroup.Parent.Groups.Remove(_addGroup.Group);
}
base.Run();

View File

@@ -292,7 +292,7 @@ namespace keepass2android
{
string hexId = t.Uuid.ToHexString();
return db.Entries.Any(kvp => kvp.Key.Equals(t.Uuid) ||
return db.EntriesById.Any(kvp => kvp.Key.Equals(t.Uuid) ||
kvp.Value.Strings.ReadSafe(TemplateIdStringKey) == hexId);
});
}
@@ -327,7 +327,7 @@ namespace keepass2android
}
PwGroup templateGroup;
if (!_app.CurrentDb.Groups.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup))
if (!_app.CurrentDb.GroupsById.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup))
{
//create template group
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
@@ -335,30 +335,31 @@ namespace keepass2android
_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;
_app.CurrentDb.GroupsById[templateGroup.Uuid] = templateGroup;
_app.CurrentDb.Elements.Add(templateGroup);
}
addedEntries = new List<PwEntry>();
foreach (var template in TemplateEntries)
{
if (_app.CurrentDb.Entries.ContainsKey(template.Uuid))
if (_app.CurrentDb.EntriesById.ContainsKey(template.Uuid))
continue;
PwEntry entry = CreateEntry(template);
templateGroup.AddEntry(entry, true);
addedEntries.Add(entry);
_app.CurrentDb.Entries[entry.Uuid] = entry;
_app.CurrentDb.EntriesById[entry.Uuid] = entry;
}
return templateGroup;
}
private PwEntry CreateEntry(TemplateEntry template)
{
PwEntry entry = new PwEntry(true, true);
PwEntry entry = new PwEntry(false, true);
entry.Uuid = template.Uuid;
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)
{

View File

@@ -1,76 +0,0 @@
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

@@ -31,7 +31,7 @@ namespace keepass2android
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
Ctx = activiy;
Db = app.FindDatabaseForEntryId(entry.Uuid);
Db = app.FindDatabaseForElement(entry);
_entry = entry;
}

View File

@@ -47,7 +47,7 @@ namespace keepass2android
*/
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
{
base.SetMembers(activity, app.FindDatabaseForGroupId(group.Uuid));
base.SetMembers(activity, app.FindDatabaseForElement(group));
_group = group;
DontSave = dontSave;

View File

@@ -100,7 +100,8 @@ namespace keepass2android
};
Db.KpDatabase.RootGroup.AddGroup(pgRecycleBin, true);
Db.Groups[pgRecycleBin.Uuid] = pgRecycleBin;
Db.GroupsById[pgRecycleBin.Uuid] = pgRecycleBin;
Db.Elements.Add(pgRecycleBin);
Db.KpDatabase.RecycleBinUuid = pgRecycleBin.Uuid;
bGroupListUpdateRequired = true;
@@ -185,7 +186,8 @@ namespace keepass2android
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
pd.DeletedObjects.Add(pdo);
touchedGroups.Add(pgParent);
Db.Entries.Remove(pe.Uuid);
Db.EntriesById.Remove(pe.Uuid);
Db.Elements.Remove(pe);
}
else // Recycle
{
@@ -223,7 +225,9 @@ namespace keepass2android
{
//remove groups from global lists if present there
App.DirtyGroups.Remove(g);
Db.Groups.Remove(g.Uuid);
Db.GroupsById.Remove(g.Uuid);
Db.Elements.Remove(g);
}
}

View File

@@ -26,7 +26,7 @@ namespace keepass2android
public class EditGroup : RunnableOnFinish {
internal Database Db
{
get { return _app.FindDatabaseForGroupId(Group.Uuid); }
get { return _app.FindDatabaseForElement(Group); }
}
public IKp2aApp App { get => _app; }

View File

@@ -151,75 +151,6 @@ namespace keepass2android
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;
}

View File

@@ -52,7 +52,7 @@ namespace keepass2android.database.edit
}
HashSet<Database> removeDatabases = new HashSet<Database>();
Database addDatabase = _app.FindDatabaseForGroupId(_targetGroup.Uuid);
Database addDatabase = _app.FindDatabaseForElement(_targetGroup);
if (addDatabase == null)
{
Finish(false, "Did not find target database. Did you lock it?");
@@ -73,12 +73,14 @@ namespace keepass2android.database.edit
PwEntry entry = elementToMove as PwEntry;
if (entry != null)
{
var dbRem = _app.FindDatabaseForEntryId(entry.Uuid);
var dbRem = _app.FindDatabaseForElement(entry);
removeDatabases.Add(dbRem);
dbRem.Entries.Remove(entry.Uuid);
dbRem.EntriesById.Remove(entry.Uuid);
dbRem.Elements.Remove(entry);
pgParent.Entries.Remove(entry);
_targetGroup.AddEntry(entry, true, true);
addDatabase.Entries.Add(entry.Uuid, entry);
addDatabase.EntriesById.Add(entry.Uuid, entry);
addDatabase.Elements.Add(entry);
}
else
{
@@ -89,18 +91,20 @@ namespace keepass2android.database.edit
return;
}
var dbRem = _app.FindDatabaseForEntryId(@group.Uuid);
var dbRem = _app.FindDatabaseForElement(@group);
if (dbRem == null)
{
Finish(false, "Did not find source database. Did you lock it?");
return;
}
dbRem.Groups.Remove(group.Uuid);
dbRem.GroupsById.Remove(group.Uuid);
dbRem.Elements.Remove(group);
removeDatabases.Add(dbRem);
pgParent.Groups.Remove(group);
_targetGroup.AddGroup(group, true, true);
addDatabase.Groups.Add(group.Uuid, group);
addDatabase.GroupsById.Add(group.Uuid, group);
addDatabase.Elements.Add(group);
}
}

View File

@@ -139,6 +139,7 @@ namespace keepass2android
//small.
MergeIn(fileStorage, ioc);
PerformSaveWithoutCheck(fileStorage, ioc);
_db.UpdateGlobals();
Finish(true);
};
RunInWorkerThread(runHandler);

View File

@@ -67,5 +67,4 @@
<ItemGroup>
<Folder Include="libs\" />
</ItemGroup>
</Project>

View File

@@ -53,11 +53,9 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
<Link>Jars\app-release.aar</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\app-debug.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />

View File

@@ -104,12 +104,13 @@ namespace keepass2android
{
Intent i = new Intent(act, typeof(EntryActivity));
i.PutExtra(KeyEntry, pw.Uuid.ToHexString());
var db = App.Kp2a.FindDatabaseForElement(pw);
i.PutExtra(KeyEntry, new ElementAndDatabaseId(db, pw).FullId);
i.PutExtra(KeyRefreshPos, pos);
if (!App.Kp2a.CurrentDb.Entries.ContainsKey(pw.Uuid))
if (App.Kp2a.CurrentDb != db)
{
App.Kp2a.CurrentDb = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
App.Kp2a.CurrentDb = db;
}
if (flags != null)
@@ -275,7 +276,7 @@ namespace keepass2android
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());
updateKeyboardIntent.PutExtra(KeyEntry, new ElementAndDatabaseId(App.Kp2a.CurrentDb, Entry).FullId);
StartService(updateKeyboardIntent);
//notify plugins
@@ -405,12 +406,13 @@ namespace keepass2android
SetResult(KeePass.ExitNormal);
Intent i = Intent;
PwUuid uuid = new PwUuid(MemUtil.HexStringToByteArray(i.GetStringExtra(KeyEntry)));
ElementAndDatabaseId dbAndElementId = new ElementAndDatabaseId(i.GetStringExtra(KeyEntry));
PwUuid uuid = new PwUuid(MemUtil.HexStringToByteArray(dbAndElementId.ElementIdString));
_pos = i.GetIntExtra(KeyRefreshPos, -1);
_appTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
Entry = db.Entries[uuid];
Entry = db.EntriesById[uuid];
// Refresh Menu contents in case onCreateMenuOptions was called before Entry was set
ActivityCompat.InvalidateOptionsMenu(this);
@@ -482,7 +484,7 @@ namespace keepass2android
{
Intent showNotIntent = new Intent(this, typeof (CopyToClipboardService));
showNotIntent.SetAction(Intents.ShowNotification);
showNotIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
showNotIntent.PutExtra(KeyEntry, new ElementAndDatabaseId(App.Kp2a.CurrentDb, Entry).FullId);
_appTask.PopulatePasswordAccessServiceIntent(showNotIntent);
showNotIntent.PutExtra(KeyCloseAfterCreate, closeAfterCreate);
@@ -1303,7 +1305,7 @@ namespace keepass2android
byte[] pbData = pb.ReadData();
Intent imageViewerIntent = new Intent(this, typeof(ImageViewActivity));
imageViewerIntent.PutExtra("EntryId", Entry.Uuid.ToHexString());
imageViewerIntent.PutExtra("EntryId", new ElementAndDatabaseId(App.Kp2a.CurrentDb, Entry).FullId);
imageViewerIntent.PutExtra("EntryKey", key);
StartActivity(imageViewerIntent);
}

View File

@@ -144,7 +144,7 @@ namespace keepass2android
PwEntry templateEntry = null;
if (!PwUuid.Zero.Equals(templateId))
{
templateEntry = db.Entries[templateId];
templateEntry = db.EntriesById[templateId];
}
if (KpEntryTemplatedEdit.IsTemplate(templateEntry))
@@ -170,7 +170,7 @@ namespace keepass2android
Debug.Assert(entryId != null);
State.EntryInDatabase = db.Entries [entryId];
State.EntryInDatabase = db.EntriesById [entryId];
State.IsNew = false;
@@ -921,7 +921,7 @@ namespace keepass2android
{
if (_additionalKeys == null)
{
_additionalKeys = App.Kp2a.CurrentDb.Entries
_additionalKeys = App.Kp2a.CurrentDb.EntriesById
.Select(kvp => kvp.Value)
.SelectMany(x => x.Strings.GetKeys().Where(k => !PwDefs.IsStandardField(k)))
.Where(k => (k != null) && !k.StartsWith("_etm_") )

View File

@@ -192,7 +192,7 @@ namespace keepass2android
if (id == null) {
Group = db.Root;
} else {
Group = db.Groups[id];
Group = db.GroupsById[id];
}
Log.Warn (Tag, "Retrieved group");
@@ -286,7 +286,7 @@ namespace keepass2android
&& (App.Kp2a.CurrentDb.KpDatabase.RootGroup.FindGroup(App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup, true) != null))
{
templates.AddRange(
App.Kp2a.CurrentDb.Groups[App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup].Entries.OrderBy(
App.Kp2a.CurrentDb.GroupsById[App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup].Entries.OrderBy(
entr => entr.Strings.ReadSafe(PwDefs.TitleField)));
}
if (templates.Count > 1)
@@ -316,6 +316,11 @@ namespace keepass2android
get { return true; }
}
public override ElementAndDatabaseId FullGroupId
{
get { return new ElementAndDatabaseId(App.Kp2a.FindDatabaseForElement(Group), Group); }
}
public override void OnBackPressed()
{
base.OnBackPressed();

View File

@@ -277,7 +277,7 @@ namespace keepass2android
{
applicableInfoTextKeys.Add(backupKey);
}
if (App.Kp2a.CurrentDb.Entries.Count > 15)
if (App.Kp2a.CurrentDb.EntriesById.Count > 15)
{
applicableInfoTextKeys.Add(emergencyKey);
}
@@ -741,9 +741,10 @@ namespace keepass2android
{
var cursor = _suggestionsAdapter.Cursor;
cursor.MoveToPosition(position);
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
var entryId = new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString));
EntryActivity.Launch(_activity, App.Kp2a.FindDatabaseForEntryId(entryId).Entries[entryId], -1, _activity.AppTask);
ElementAndDatabaseId fullId = new ElementAndDatabaseId(cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId)));
var entryId = fullId.ElementId;
EntryActivity.Launch(_activity, App.Kp2a.GetDatabase(fullId.DatabaseId).EntriesById[entryId], -1, _activity.AppTask);
return true;
}
@@ -861,6 +862,8 @@ namespace keepass2android
public abstract bool EntriesBelongToCurrentDatabaseOnly { get; }
public abstract ElementAndDatabaseId FullGroupId { get; }
public override bool OnPrepareOptionsMenu(IMenu menu)
{
@@ -1390,7 +1393,7 @@ namespace keepass2android
new List<KeyValuePair<Database, List<IStructureItem>>>();
foreach (var item in checkedItems)
{
var db = app.FindDatabaseForEntryId(item.Uuid) ?? app.FindDatabaseForGroupId(item.Uuid);
var db = app.FindDatabaseForElement(item);
if (db != null)
{
bool foundDatabase = false;

View File

@@ -118,7 +118,7 @@ namespace keepass2android
if (Intent.HasExtra(KeyGroupUuid))
{
string groupUuid = Intent.Extras.GetString(KeyGroupUuid);
_groupToEdit = App.Kp2a.CurrentDb.Groups[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))];
_groupToEdit = App.Kp2a.CurrentDb.GroupsById[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))];
_selectedIconId = (int) _groupToEdit.IconId;
_selectedCustomIconId = _groupToEdit.CustomIconUuid;
TextView nameField = (TextView)FindViewById(Resource.Id.group_name);

View File

@@ -315,9 +315,12 @@ namespace keepass2android
_activityDesign.ApplyTheme();
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ImageViewActivity);
var uuid = new PwUuid(MemUtil.HexStringToByteArray(Intent.GetStringExtra("EntryId")));
ElementAndDatabaseId fullId = new ElementAndDatabaseId(Intent.GetStringExtra("EntryId"));
var uuid = new PwUuid(MemUtil.HexStringToByteArray(fullId.ElementIdString));
string key = Intent.GetStringExtra("EntryKey");
var binary = App.Kp2a.FindDatabaseForEntryId(uuid).Entries[uuid].Binaries.Get(key);
var binary = App.Kp2a.GetDatabase(fullId.DatabaseId).EntriesById[uuid].Binaries.Get(key);
SupportActionBar.Title = key;
byte[] pbdata = binary.ReadData();

View File

@@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Android.Webkit;
using KeePass.Util.Spr;
using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Security;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace keepass2android
{
public sealed class AutoExecItem
{
private PwEntry m_pe;
public PwEntry Entry
{
get { return m_pe; }
}
private PwDatabase m_pdContext;
public PwDatabase Database
{
get { return m_pdContext; }
}
public bool Enabled = true;
public bool Visible = true;
public long Priority = 0;
public AutoExecItem(PwEntry pe, PwDatabase pdContext)
{
if (pe == null) throw new ArgumentNullException("pe");
m_pe = pe;
m_pdContext = pdContext;
}
}
public sealed class KeeAutoExecExt
{
private static int PrioritySort(AutoExecItem x, AutoExecItem y)
{
if (x == null) { Debug.Assert(false); return ((y == null) ? 0 : -1); }
if (y == null) { Debug.Assert(false); return 1; }
return x.Priority.CompareTo(y.Priority);
}
private static void AddAutoExecEntries(List<PwEntry> l, PwGroup pg)
{
if (pg.Name.Equals("AutoOpen", StrUtil.CaseIgnoreCmp))
l.AddRange(pg.GetEntries(true));
else
{
foreach (PwGroup pgSub in pg.Groups)
AddAutoExecEntries(l, pgSub);
}
}
private static List<AutoExecItem> GetAutoExecItems(PwDatabase pd)
{
List<AutoExecItem> l = new List<AutoExecItem>();
if (pd == null) { Debug.Assert(false); return l; }
if (!pd.IsOpen) return l;
PwGroup pgRoot = pd.RootGroup;
if (pgRoot == null) { Debug.Assert(false); return l; }
List<PwEntry> lAutoEntries = new List<PwEntry>();
AddAutoExecEntries(lAutoEntries, pgRoot);
long lPriStd = 0;
foreach (PwEntry pe in lAutoEntries)
{
string str = pe.Strings.ReadSafe(PwDefs.UrlField);
if (str.Length == 0) continue;
AutoExecItem a = new AutoExecItem(pe, pd);
l.Add(a);
SprContext ctx = new SprContext(pe, pd, SprCompileFlags.All);
if (pe.Expires && (pe.ExpiryTime <= DateTime.UtcNow))
a.Enabled = false;
bool? ob = GetBoolEx(pe, "Enabled", ctx);
if (ob.HasValue) a.Enabled = ob.Value;
ob = GetBoolEx(pe, "Visible", ctx);
if (ob.HasValue) a.Visible = ob.Value;
long lItemPri = lPriStd;
if (GetString(pe, "Priority", ctx, true, out str))
long.TryParse(str, out lItemPri);
a.Priority = lItemPri;
++lPriStd;
}
l.Sort(KeeAutoExecExt.PrioritySort);
return l;
}
private void OnFileOpen(PwDatabase db)
{
List<AutoExecItem> l = GetAutoExecItems(db);
foreach (AutoExecItem a in l)
{
if (!a.Enabled) continue;
try { AutoOpenEntryPriv(a, false); }
catch (Exception ex)
{
MessageService.ShowWarning(ex);
}
}
}
private void AutoOpenEntryPriv(AutoExecItem a, bool bManual)
{
PwEntry pe = a.Entry;
PwDatabase pdContext = a.Database;
SprContext ctxNoEsc = new SprContext(pe, pdContext, SprCompileFlags.All);
SprContext ctxEsc = new SprContext(pe, pdContext, SprCompileFlags.All,
false, true);
string strDb;
if (!GetString(pe, PwDefs.UrlField, ctxEsc, true, out strDb)) return;
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strDb);
//TODO
/*if (ioc.IsLocalFile() && !UrlUtil.IsAbsolutePath(strDb))
ioc = IOConnectionInfo.FromPath(UrlUtil.MakeAbsolutePath(
WinUtil.GetExecutable(), strDb));*/
if (ioc.Path.Length == 0) return;
string strIocUserName;
if (GetString(pe, "IocUserName", ctxNoEsc, true, out strIocUserName))
ioc.UserName = strIocUserName;
string strIocPassword;
if (GetString(pe, "IocPassword", ctxNoEsc, true, out strIocPassword))
ioc.Password = strIocPassword;
if ((strIocUserName.Length != 0) && (strIocPassword.Length != 0))
ioc.IsComplete = true;
string str;
if (GetString(pe, "IocTimeout", ctxNoEsc, true, out str))
{
long l;
if (long.TryParse(str, out l))
ioc.Properties.SetLong(IocKnownProperties.Timeout, l);
}
bool? ob = GetBoolEx(pe, "IocPreAuth", ctxNoEsc);
if (ob.HasValue)
ioc.Properties.SetBool(IocKnownProperties.PreAuth, ob.Value);
if (GetString(pe, "IocUserAgent", ctxNoEsc, true, out str))
ioc.Properties.Set(IocKnownProperties.UserAgent, str);
ob = GetBoolEx(pe, "IocExpect100Continue", ctxNoEsc);
if (ob.HasValue)
ioc.Properties.SetBool(IocKnownProperties.Expect100Continue, ob.Value);
ob = GetBoolEx(pe, "IocPassive", ctxNoEsc);
if (ob.HasValue)
ioc.Properties.SetBool(IocKnownProperties.Passive, ob.Value);
ob = GetBoolEx(pe, "SkipIfNotExists", ctxNoEsc);
if (!ob.HasValue) // Backw. compat.
ob = GetBoolEx(pe, "Skip if not exists", ctxNoEsc);
if (ob.HasValue && ob.Value)
{
if (!IOConnection.FileExists(ioc)) return;
}
CompositeKey ck = new CompositeKey();
if (GetString(pe, PwDefs.PasswordField, ctxNoEsc, false, out str))
ck.AddUserKey(new KcpPassword(str));
if (GetString(pe, PwDefs.UserNameField, ctxNoEsc, false, out str))
{
string strAbs = str;
IOConnectionInfo iocKey = IOConnectionInfo.FromPath(strAbs);
if (iocKey.IsLocalFile() && !UrlUtil.IsAbsolutePath(strAbs))
{
//TODO
/* strAbs = UrlUtil.MakeAbsolutePath(WinUtil.GetExecutable(), strAbs);*/
}
ob = GetBoolEx(pe, "SkipIfKeyFileNotExists", ctxNoEsc);
if (ob.HasValue && ob.Value)
{
IOConnectionInfo iocKeyAbs = IOConnectionInfo.FromPath(strAbs);
if (!IOConnection.FileExists(iocKeyAbs)) return;
}
try { ck.AddUserKey(new KcpKeyFile(strAbs)); }
catch (InvalidOperationException)
{
//TODO
throw new Exception("TODO");
//throw new Exception(strAbs + MessageService.NewParagraph + KPRes.KeyFileError);
}
catch (Exception) { throw; }
}
else // Try getting key file from attachments
{
ProtectedBinary pBin = pe.Binaries.Get("KeyFile.bin");
if (pBin != null)
ck.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromPath(
StrUtil.DataToDataUri(pBin.ReadData(), null))));
}
if (GetString(pe, "KeyProvider", ctxNoEsc, true, out str))
{
/*TODO KeyProvider kp = m_host.KeyProviderPool.Get(str);
if (kp == null)
throw new Exception(@"Unknown key provider: '" + str + @"'!");
KeyProviderQueryContext ctxKP = new KeyProviderQueryContext(
ioc, false, false);
bool bPerformHash = !kp.DirectKey;
byte[] pbProvKey = kp.GetKey(ctxKP);
if ((pbProvKey != null) && (pbProvKey.Length != 0))
{
ck.AddUserKey(new KcpCustomKey(str, pbProvKey, bPerformHash));
MemUtil.ZeroByteArray(pbProvKey);
}
else return; // Provider has shown error message*/
throw new Exception("KeyProvider not supported");
}
ob = GetBoolEx(pe, "UserAccount", ctxNoEsc);
if (ob.HasValue && ob.Value)
ck.AddUserKey(new KcpUserAccount());
if (ck.UserKeyCount == 0) return;
GetString(pe, "Focus", ctxNoEsc, true, out str);
bool bRestoreFocus = str.Equals("Restore", StrUtil.CaseIgnoreCmp);
/*TODO
* PwDatabase pdPrev = m_host.MainWindow.ActiveDatabase;
m_host.MainWindow.OpenDatabase(ioc, ck, true);
if (bRestoreFocus && (pdPrev != null) && !bManual)
{
PwDocument docPrev = m_host.MainWindow.DocumentManager.FindDocument(
pdPrev);
if (docPrev != null) m_host.MainWindow.MakeDocumentActive(docPrev);
else { Debug.Assert(false); }
}*/
}
private static bool GetString(PwEntry pe, string strName, SprContext ctx,
bool bTrim, out string strValue)
{
if ((pe == null) || (strName == null))
{
Debug.Assert(false);
strValue = string.Empty;
return false;
}
string str = pe.Strings.ReadSafe(strName);
if (ctx != null) str = SprEngine.Compile(str, ctx);
if (bTrim) str = str.Trim();
strValue = str;
return (str.Length != 0);
}
private static bool? GetBoolEx(PwEntry pe, string strName, SprContext ctx)
{
string str;
if (GetString(pe, strName, ctx, true, out str))
{
if (str.Equals("True", StrUtil.CaseIgnoreCmp))
return true;
if (str.Equals("False", StrUtil.CaseIgnoreCmp))
return false;
}
return null;
}
}
public class KeeAutoExec
{
}
}

View File

@@ -52,7 +52,7 @@ namespace keepass2android
if (uuidBytes != null)
{
PwUuid templateUuid = new PwUuid(uuidBytes);
return db.Entries.ContainsKey(templateUuid);
return db.EntriesById.ContainsKey(templateUuid);
}
}
return false;
@@ -63,7 +63,7 @@ namespace keepass2android
_db = db;
_entry = entry;
PwUuid templateUuid = new PwUuid(MemUtil.HexStringToByteArray(entry.Strings.ReadSafe(EtmTemplateUuid)));
_templateEntry = db.Entries[templateUuid];
_templateEntry = db.EntriesById[templateUuid];
}
public static void InitializeEntry(PwEntry entry, PwEntry templateEntry)

View File

@@ -432,9 +432,6 @@
<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>
@@ -739,8 +736,6 @@
<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

@@ -213,5 +213,10 @@ namespace keepass2android
{
get { return false; }
}
public override ElementAndDatabaseId FullGroupId
{
get { return null; }
}
}}

View File

@@ -250,15 +250,6 @@ namespace keepass2android
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)
@@ -270,7 +261,7 @@ namespace keepass2android
Lock(false);
return;
}
if (LastOpenedEntry != null && db.Entries.ContainsKey(LastOpenedEntry.Uuid))
if (LastOpenedEntry != null && db.EntriesById.ContainsKey(LastOpenedEntry.Uuid))
{
LastOpenedEntry = null;
}
@@ -282,15 +273,6 @@ namespace keepass2android
//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()
{
@@ -374,7 +356,7 @@ namespace keepass2android
public void MarkAllGroupsAsDirty()
{
foreach (var db in OpenDatabases)
foreach (PwGroup group in db.Groups.Values)
foreach (PwGroup group in db.GroupsById.Values)
{
DirtyGroups.Add(group);
}
@@ -1017,12 +999,22 @@ namespace keepass2android
throw new Exception("Database not found for dbIoc!");
}
public Database GetDatabase(string databaseId)
{
foreach (Database db in OpenDatabases)
{
if (IoUtil.IocAsHexString(db.Ioc) == databaseId)
return db;
}
throw new Exception("Database not found for databaseId!");
}
public PwGroup FindGroup(PwUuid uuid)
{
foreach (Database db in OpenDatabases)
{
PwGroup result;
if (db.Groups.TryGetValue(uuid, out result))
if (db.GroupsById.TryGetValue(uuid, out result))
return result;
}
return null;
@@ -1033,10 +1025,10 @@ namespace keepass2android
foreach (Database db in OpenDatabases)
{
PwGroup resultGroup;
if (db.Groups.TryGetValue(uuid, out resultGroup))
if (db.GroupsById.TryGetValue(uuid, out resultGroup))
return resultGroup;
PwEntry resultEntry;
if (db.Entries.TryGetValue(uuid, out resultEntry))
if (db.EntriesById.TryGetValue(uuid, out resultEntry))
return resultEntry;
}
return null;
@@ -1053,6 +1045,24 @@ namespace keepass2android
return false;
}
public Database FindDatabaseForElement(IStructureItem element)
{
var db = TryFindDatabaseForElement(element);
if (db == null)
throw new Exception("Database element not found!");
return db;
}
public Database TryFindDatabaseForElement(IStructureItem element)
{
foreach (var db in OpenDatabases)
{
if (db.Elements.Contains(element))
return db;
}
return null;
}
}

View File

@@ -782,7 +782,7 @@ namespace keepass2android
// All group Uuid are stored in guuidKey + indice
// The last one is the destination group
public const String NumberOfGroupsKey = "NumberOfGroups";
public const String GUuidKey = "gUuidKey";
public const String GFullIdKey = "gFullIdKey";
public const String FullGroupNameKey = "fullGroupNameKey";
public const String ToastEnableKey = "toastEnableKey";
@@ -791,7 +791,7 @@ namespace keepass2android
private LinkedList<string> groupNameList;
#endif
private LinkedList<string> _groupUuid;
private LinkedList<string> _fullGroupIds;
protected AppTask TaskToBeLaunchedAfterNavigation;
protected String FullGroupName {
@@ -824,7 +824,7 @@ namespace keepass2android
public void PopulateGroups(PwGroup groups) {
_groupUuid = new LinkedList<String>();
_fullGroupIds = new LinkedList<String>();
#if INCLUDE_DEBUG_MOVE_GROUPNAME
groupNameList = new LinkedList<String>{};
@@ -839,7 +839,7 @@ namespace keepass2android
FullGroupName = readGroup.Name + "." + FullGroupName;
}
_groupUuid.AddFirst (MemUtil.ByteArrayToHexString (readGroup.Uuid.UuidBytes));
_fullGroupIds.AddFirst(new ElementAndDatabaseId(App.Kp2a.FindDatabaseForElement(readGroup),readGroup).FullId);
#if INCLUDE_DEBUG_MOVE_GROUPNAME
groupNameList.AddFirst (readGroup.Name);
@@ -860,16 +860,17 @@ namespace keepass2android
{
int numberOfGroups = b.GetInt(NumberOfGroupsKey);
_groupUuid = new LinkedList<String>();
_fullGroupIds = new LinkedList<String>();
#if INCLUDE_DEBUG_MOVE_GROUPNAME
groupNameList = new LinkedList<String>{};
#endif
int i = 0;
while (i < numberOfGroups) {
while (i < numberOfGroups)
{
_groupUuid.AddLast ( b.GetString (GUuidKey + i) ) ;
_fullGroupIds.AddLast ( b.GetString (GFullIdKey + i.ToString(CultureInfo.InvariantCulture)) ) ;
#if INCLUDE_DEBUG_MOVE_GROUPNAME
groupNameList.AddLast ( b.GetString (gNameKey + i);
@@ -887,15 +888,16 @@ namespace keepass2android
get
{
// Return Navigate group Extras
IEnumerator<String> eGroupKeys = _groupUuid.GetEnumerator ();
#if INCLUDE_DEBUG_MOVE_GROUPNAME
IEnumerator<String> eGroupName = groupNameList.GetEnumerator ();
#endif
int i = 0;
while (eGroupKeys.MoveNext()) {
yield return new StringExtra { Key = GUuidKey + i.ToString (CultureInfo.InvariantCulture), Value = eGroupKeys.Current };
foreach (var fullGroupId in _fullGroupIds)
{
yield return new StringExtra { Key = GFullIdKey + i.ToString (CultureInfo.InvariantCulture), Value = fullGroupId };
#if INCLUDE_DEBUG_MOVE_GROUPNAME
eGroupName.MoveNext();
@@ -933,26 +935,29 @@ namespace keepass2android
groupBaseActivity.StartTask (TaskToBeLaunchedAfterNavigation);
return;
} else if (_groupUuid.Contains(groupBaseActivity.UuidGroup)) { // Need to down up in groups tree
} else if ((groupBaseActivity.FullGroupId != null) && _fullGroupIds.Contains(groupBaseActivity.FullGroupId.FullId)) { // Need to down up in groups tree
// Get next Group Uuid
var linkedListNode = _groupUuid.Find(groupBaseActivity.UuidGroup);
var linkedListNode = _fullGroupIds.Find(groupBaseActivity.FullGroupId.FullId);
if (linkedListNode != null)
{
//Note: Resharper says there is a possible NullRefException.
//This is not the case because it was checked above if we're already there or not.
String nextGroupUuid = linkedListNode.Next.Value;
PwUuid nextGroupPwUuid = new PwUuid (MemUtil.HexStringToByteArray (nextGroupUuid));
String nextGroupFullId = linkedListNode.Next.Value;
ElementAndDatabaseId fullId = new ElementAndDatabaseId(nextGroupFullId);
PwUuid nextGroupPwUuid = new PwUuid (MemUtil.HexStringToByteArray (fullId.ElementIdString));
// Create Group Activity
PwGroup nextGroup = App.Kp2a.CurrentDb.Groups[nextGroupPwUuid];
PwGroup nextGroup = App.Kp2a.GetDatabase(fullId.DatabaseId).GroupsById[nextGroupPwUuid];
GroupActivity.Launch (groupBaseActivity, nextGroup, this, new ActivityLaunchModeRequestCode(0));
}
return;
} else { // Need to go up in groups tree
var targetUuid = new PwUuid(MemUtil.HexStringToByteArray(_groupUuid.Last.Value));
var targetDb = App.Kp2a.FindDatabaseForGroupId(targetUuid);
ElementAndDatabaseId fullId = new ElementAndDatabaseId(_fullGroupIds.Last.Value);
var targetDb = App.Kp2a.GetDatabase(fullId.DatabaseId);
if (App.Kp2a.CurrentDb != targetDb)
{
App.Kp2a.CurrentDb = targetDb;
@@ -975,7 +980,8 @@ namespace keepass2android
public bool GroupIsFound(GroupBaseActivity groupBaseActivity)
{
return _groupUuid.Last.Value.Equals (groupBaseActivity.UuidGroup);
var fullId = groupBaseActivity.FullGroupId;
return fullId != null && _fullGroupIds.Last.Value.Equals (fullId.FullId);
}
}

View File

@@ -216,6 +216,7 @@
<Compile Include="ChangeLog.cs" />
<Compile Include="FingerprintUnlockMode.cs" />
<Compile Include="icons\DrawableFactory.cs" />
<Compile Include="KeeAutoExec.cs" />
<Compile Include="KeeChallenge.cs" />
<Compile Include="FixedDrawerLayout.cs" />
<Compile Include="KpEntryTemplatedEdit.cs" />

View File

@@ -303,7 +303,7 @@ namespace keepass2android.search
builder.AppendQueryParameter(DatabaseIndexParameter, _entriesWithContexts[MPos].DatabaseIndex.ToString());
return builder.Build().ToString();
case 4: // SuggestColumnIntentDataId
return CurrentEntry.Uuid.ToHexString();
return new ElementAndDatabaseId(App.Kp2a.FindDatabaseForElement(CurrentEntry),CurrentEntry).FullId;
default:
return null;
}

View File

@@ -61,6 +61,11 @@ namespace keepass2android.search
get { return false; }
}
public override ElementAndDatabaseId FullGroupId
{
get { return null; }
}
protected override void OnNewIntent(Intent intent)
{

View File

@@ -283,25 +283,34 @@ namespace keepass2android
if ((intent.Action == Intents.ShowNotification) || (intent.Action == Intents.UpdateKeyboard))
{
String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry);
String entryId = intent.GetStringExtra(EntryActivity.KeyEntry);
String searchUrl = intent.GetStringExtra(SearchUrlTask.UrlToSearchKey);
PwUuid entryId = PwUuid.Zero;
if (uuidBytes != null)
entryId = new PwUuid(MemUtil.HexStringToByteArray(uuidBytes));
if (entryId == null)
{
Kp2aLog.Log("received intent " + intent.Action + " without KeyEntry!");
#if DEBUG
throw new Exception("invalid intent received!");
#endif
return StartCommandResult.NotSticky;
}
PwEntryOutput entry;
try
{
if ((App.Kp2a.LastOpenedEntry != null)
&& (entryId.Equals(App.Kp2a.LastOpenedEntry.Uuid)))
ElementAndDatabaseId fullId = new ElementAndDatabaseId(entryId);
if (((App.Kp2a.LastOpenedEntry != null)
&& (fullId.ElementId.Equals(App.Kp2a.LastOpenedEntry.Uuid))))
{
entry = App.Kp2a.LastOpenedEntry;
}
else
{
Database entryDb = App.Kp2a.FindDatabaseForEntryId(entryId);
entry = new PwEntryOutput(entryDb.Entries[entryId], entryDb);
Database entryDb = App.Kp2a.GetDatabase(fullId.DatabaseId);
entry = new PwEntryOutput(entryDb.EntriesById[fullId.ElementId], entryDb);
}
}
@@ -403,7 +412,7 @@ namespace keepass2android
var hadKeyboardData = ClearNotifications();
String entryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);
Database db = App.Kp2a.FindDatabaseForEntryId(entry.Uuid);
Database db = App.Kp2a.FindDatabaseForElement(entry.Entry);
var bmp = Util.DrawableToBitmap(db.DrawableFactory.GetIconDrawable(this,
db.KpDatabase, entry.Entry.IconId, entry.Entry.CustomIconUuid, false));

View File

@@ -72,7 +72,7 @@ namespace keepass2android.view
_textView = (TextView)ev.FindViewById(Resource.Id.entry_text);
_textView.TextSize = PrefsUtil.GetListTextSize(groupActivity);
Database db = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
Database db = App.Kp2a.FindDatabaseForElement(pw);
ev.FindViewById(Resource.Id.entry_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
@@ -108,7 +108,7 @@ 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);
Database db = App.Kp2a.FindDatabaseForElement(_entry);
ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon);
bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now;

View File

@@ -63,7 +63,7 @@ namespace keepass2android.view
_label = (TextView) gv.FindViewById(Resource.Id.group_label);
_label.TextSize = size-8;
Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
Database db = App.Kp2a.FindDatabaseForElement(pw);
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
@@ -81,7 +81,7 @@ namespace keepass2android.view
_pwGroup = pw;
ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon);
Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
Database db = App.Kp2a.FindDatabaseForElement(pw);
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;