/* This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin. Keepass2Android is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Keepass2Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Keepass2Android. If not, see . */ 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.Interfaces; using KeePassLib.Serialization; namespace keepass2android { public class Database { public Dictionary groups = new Dictionary(new PwUuidEqualityComparer()); public Dictionary entries = new Dictionary(new PwUuidEqualityComparer()); public HashSet dirty = new HashSet(new PwGroupEqualityFromIdComparer()); public PwGroup root; public PwDatabase pm; public IOConnectionInfo mIoc; public DateTime mLastChangeDate; public SearchDbHelper searchHelper; public IDrawableFactory drawableFactory; IKp2aApp app; public Database(IDrawableFactory drawableFactory, IKp2aApp app) { this.drawableFactory = drawableFactory; this.app = app; } private bool loaded = false; private bool mReloadRequested = false; public bool ReloadRequested { get { return mReloadRequested; } set { mReloadRequested = value; } } public bool Loaded { get { return loaded;} set { loaded = value; } } public bool Open { get { return Loaded && (!Locked); } } bool locked; public bool Locked { get { return locked; } set { locked = value; } } public bool DidOpenFileChange() { if ((Loaded == false) || (mIoc.IsLocalFile() == false)) { return false; } return System.IO.File.GetLastWriteTimeUtc(mIoc.Path) > mLastChangeDate; } public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, String password, String keyfile, UpdateStatus status) { mIoc = iocInfo; KeePassLib.PwDatabase pwDatabase = new KeePassLib.PwDatabase(); KeePassLib.Keys.CompositeKey key = new KeePassLib.Keys.CompositeKey(); key.AddUserKey(new KeePassLib.Keys.KcpPassword(password)); if (!String.IsNullOrEmpty(keyfile)) { try { key.AddUserKey(new KeePassLib.Keys.KcpKeyFile(keyfile)); } catch (Exception) { throw new KeyFileException(); } } pwDatabase.Open(iocInfo, key, status); if (iocInfo.IsLocalFile()) { mLastChangeDate = System.IO.File.GetLastWriteTimeUtc(iocInfo.Path); } else { mLastChangeDate = DateTime.MinValue; } root = pwDatabase.RootGroup; populateGlobals(root); Loaded = true; pm = pwDatabase; searchHelper = new SearchDbHelper(app); } bool quickUnlockEnabled = false; public bool QuickUnlockEnabled { get { return quickUnlockEnabled; } set { quickUnlockEnabled = value; } } //KeyLength of QuickUnlock at time of loading the database. //This is important to not allow an attacker to set the length to 1 when QuickUnlock is started already. public int QuickUnlockKeyLength { get; set; } public PwGroup SearchForText(String str) { PwGroup group = searchHelper.searchForText(this, str); return group; } public PwGroup Search(SearchParameters searchParams) { return searchHelper.search(this, searchParams); } public PwGroup SearchForExactUrl(String url) { PwGroup group = searchHelper.searchForExactUrl(this, url); return group; } public PwGroup SearchForHost(String url, bool allowSubdomains) { PwGroup group = searchHelper.searchForHost(this, url, allowSubdomains); return group; } public void SaveData(Context ctx) { pm.UseFileTransactions = app.GetBooleanPreference(PreferenceKey.UseFileTransactions); pm.Save(null); } class SaveStatusLogger: IStatusLogger { #region IStatusLogger implementation public void StartLogging (string strOperation, bool bWriteOperationToLog) { } public void EndLogging () { } public bool SetProgress (uint uPercent) { Android.Util.Log.Debug("DEBUG", "Progress: " + uPercent+"%"); return true; } public bool SetText (string strNewText, LogStatusType lsType) { Android.Util.Log.Debug("DEBUG", strNewText); return true; } public bool ContinueWork () { return true; } #endregion } private void populateGlobals (PwGroup currentGroup) { var childGroups = currentGroup.Groups; var childEntries = currentGroup.Entries; foreach (PwEntry e in childEntries) { entries [e.Uuid] = e; } foreach (PwGroup g in childGroups) { groups[g.Uuid] = g; populateGlobals(g); } } public void Clear() { groups.Clear(); entries.Clear(); dirty.Clear(); drawableFactory.Clear(); root = null; pm = null; mIoc = null; loaded = false; locked = false; mReloadRequested = false; } public void markAllGroupsAsDirty() { foreach ( PwGroup group in groups.Values ) { dirty.Add(group); } } } }