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:
@@ -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.
|
||||
|
||||
47
src/Kp2aBusinessLogic/ElementAndDatabaseId.cs
Normal file
47
src/Kp2aBusinessLogic/ElementAndDatabaseId.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -87,9 +87,6 @@ namespace keepass2android
|
||||
ReadOnlyReason_ReadOnlyFlag,
|
||||
ReadOnlyReason_ReadOnlyKitKat,
|
||||
ReadOnlyReason_LocalBackup,
|
||||
UpdatingTemplateIds,
|
||||
ChangleLegacyTemplateIds_Message,
|
||||
ChangleLegacyTemplateIds_Title,
|
||||
Ok,
|
||||
cancel
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ namespace keepass2android
|
||||
}), _app.CurrentDb, false, remoteData);
|
||||
_saveDb.Run();
|
||||
|
||||
_app.CurrentDb.UpdateGlobals();
|
||||
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ namespace keepass2android
|
||||
//small.
|
||||
MergeIn(fileStorage, ioc);
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
_db.UpdateGlobals();
|
||||
Finish(true);
|
||||
};
|
||||
RunInWorkerThread(runHandler);
|
||||
|
||||
@@ -67,5 +67,4 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="libs\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_") )
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
304
src/keepass2android/KeeAutoExec.cs
Normal file
304
src/keepass2android/KeeAutoExec.cs
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -213,5 +213,10 @@ namespace keepass2android
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override ElementAndDatabaseId FullGroupId
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,11 @@ namespace keepass2android.search
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override ElementAndDatabaseId FullGroupId
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user