public PwGroup AddTemplates(out List <PwEntry> addedEntries) { if (TemplateEntries.GroupBy(e => e.Uuid).Any(g => g.Count() > 1)) { throw new Exception("invalid UUIDs in template list!"); } PwGroup 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); _app.CurrentDb.KpDatabase.RootGroup.AddGroup(templateGroup, true); _app.CurrentDb.KpDatabase.EntryTemplatesGroup = templateGroup.Uuid; _app.CurrentDb.KpDatabase.EntryTemplatesGroupChanged = DateTime.Now; _app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup); _app.CurrentDb.GroupsById[templateGroup.Uuid] = templateGroup; _app.CurrentDb.Elements.Add(templateGroup); } addedEntries = new List <PwEntry>(); foreach (var template in TemplateEntries) { if (_app.CurrentDb.EntriesById.ContainsKey(template.Uuid)) { continue; } PwEntry entry = CreateEntry(template); templateGroup.AddEntry(entry, true); addedEntries.Add(entry); _app.CurrentDb.EntriesById[entry.Uuid] = entry; } return(templateGroup); }
private void ConvertException(IOConnectionInfo ioc, WebException ex) { var response = ex.Response as HttpWebResponse; if ((response != null) && (response.StatusCode == HttpStatusCode.NotFound)) { throw new FileNotFoundException(ex.Message, ioc.Path, ex); } if (ex.Status == WebExceptionStatus.TrustFailure) { throw new Exception(_app.GetResourceString(UiStringKey.CertificateFailure), ex); } var inner1 = ex.InnerException as IOException; if (inner1 != null) { var inner2 = inner1.InnerException; if (inner2 != null) { if (inner2.Message.Contains("Invalid certificate received from server.")) { throw new Exception(_app.GetResourceString(UiStringKey.CertificateFailure), ex); } } } }
public void UpdateMessage(UiStringKey stringKey) { if (_app != null) { UpdateMessage(_app.GetResourceString(stringKey)); } }
private Exception LogAndConvertJavaException(Exception e) { Kp2aLog.Log(e.Message); if (e is UserInteractionRequiredException) { return(e); } //seems like UserInteractionRequiredException is not propagated correctly into the C# world, we can't catch it // -> rethrow correctly here // Note: the Contains-check looks a bit broad, but it should be safe if (e.ToString().Contains("keepass2android.javafilestorage.UserInteractionRequiredException")) { throw new UserInteractionRequiredException(); } Java.Lang.Exception exception = e as Java.Lang.Exception; if (exception != null) { var ex = new Exception(exception.LocalizedMessage ?? e.Message ?? _app.GetResourceString(UiStringKey.ErrorOcurred) + exception.GetType().Name, e); return(ex); } return(e); }
protected void EnsureRecycleBinExists(ref PwGroup pgRecycleBin, ref bool bGroupListUpdateRequired) { if ((Db == null) || (Db.KpDatabase == null)) { return; } if (pgRecycleBin == Db.KpDatabase.RootGroup) { pgRecycleBin = null; } if (pgRecycleBin == null) { pgRecycleBin = new PwGroup(true, true, App.GetResourceString(UiStringKey.RecycleBin), PwIcon.TrashBin) { EnableAutoType = false, EnableSearching = false, IsExpanded = false }; Db.KpDatabase.RootGroup.AddGroup(pgRecycleBin, true); Db.GroupsById[pgRecycleBin.Uuid] = pgRecycleBin; Db.Elements.Add(pgRecycleBin); Db.KpDatabase.RecycleBinUuid = pgRecycleBin.Uuid; bGroupListUpdateRequired = true; } else { System.Diagnostics.Debug.Assert(pgRecycleBin.Uuid.Equals(Db.KpDatabase.RecycleBinUuid)); } }
private void MergeIn(IFileStorage fileStorage, IOConnectionInfo ioc) { StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase)); PwDatabase pwImp = new PwDatabase(); PwDatabase pwDatabase = _app.GetDb().KpDatabase; pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey); pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep(); pwImp.MasterKey = pwDatabase.MasterKey; var stream = GetStreamForBaseFile(fileStorage, ioc); _app.GetDb().DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null); pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null); }
public PwGroup Search(Database database, SearchParameters sp, IDictionary <PwUuid, KeyValuePair <string, string> > resultContexts) { if (sp.RegularExpression) // Validate regular expression { new Regex(sp.SearchString); } string strGroupName = _app.GetResourceString(UiStringKey.search_results) + " (\"" + sp.SearchString + "\")"; PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) { IsVirtual = true }; PwObjectList <PwEntry> listResults = pgResults.Entries; database.Root.SearchEntries(sp, listResults, resultContexts, new NullStatusLogger()); return(pgResults); }
private static PwEntry CreateCopy(PwEntry entry, IKp2aApp app) { var newEntry = entry.CloneDeep(); newEntry.SetUuid(new PwUuid(true), true); // Create new UUID string strTitle = newEntry.Strings.ReadSafe(PwDefs.TitleField); newEntry.Strings.Set(PwDefs.TitleField, new ProtectedString( false, strTitle + " - " + app.GetResourceString(UiStringKey.DuplicateTitle))); return(newEntry); }
public override void Run() { try { IOConnectionInfo ioc = _app.GetDb().Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (fileStorage is CachingFileStorage) { throw new Exception("Cannot sync a cached database!"); } StatusLogger.UpdateMessage(UiStringKey.CheckingDatabaseForChanges); //download file from remote location and calculate hash: StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile)); MemoryStream remoteData = new MemoryStream(); using ( HashingStreamEx hashingRemoteStream = new HashingStreamEx(fileStorage.OpenFileForRead(ioc), false, new SHA256Managed())) { hashingRemoteStream.CopyTo(remoteData); hashingRemoteStream.Close(); if (!MemUtil.ArraysEqual(_app.GetDb().KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash)) { _app.TriggerReload(_context); Finish(true); } else { Finish(true, _app.GetResourceString(UiStringKey.RemoteDatabaseUnchanged)); } } } catch (Exception e) { Finish(false, e.Message); } }
public void AddToEntry(IKp2aApp app, PwEntry entry, int position) { Dictionary <FieldType, string> fn = new Dictionary <FieldType, string>() { { FieldType.ProtectedInline, "Protected Inline" }, { FieldType.Inline, "Inline" } }; string fieldKey = app.GetResourceString(FieldName); entry.Strings.Set("_etm_position_" + fieldKey, new ProtectedString(false, position.ToString())); entry.Strings.Set("_etm_title_" + fieldKey, new ProtectedString(false, fieldKey)); entry.Strings.Set("_etm_type_" + fieldKey, new ProtectedString(false, fn[Type])); }
public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) { _task = task; _handler = app.UiThreadHandler; _app = app; // Show process dialog _progressDialog = app.CreateProgressDialog(ctx); _progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title)); _progressDialog.SetMessage("Initializing..."); // Set code to run when this is finished _task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog); _task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog)); }
public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) { _task = task; _handler = app.UiThreadHandler; _app = app; // Show process dialog _progressDialog = app.CreateProgressDialog(ctx); _progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title)); _progressDialog.SetMessage("Initializing..."); // Set code to run when this is finished _task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog); _task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog)); }
private void IocForCopySelected(IOConnectionInfo targetIoc) { PerformCopy(() => { IOConnectionInfo sourceIoc = _selectedIoc; try { CopyFile(targetIoc, sourceIoc); } catch (Exception e) { return(() => { ShowToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message); ReturnCancel(); }); } return(() => { ReturnOk(targetIoc); }); }); }
public override void Run() { try { IOConnectionInfo ioc = _app.GetDb().Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (!(fileStorage is CachingFileStorage)) { throw new Exception("Cannot sync a non-cached database!"); } StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase); CachingFileStorage cachingFileStorage = (CachingFileStorage)fileStorage; //download file from remote location and calculate hash: StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile)); string hash; MemoryStream remoteData; try { remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash); } catch (FileNotFoundException) { StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile)); cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); return; } //check if remote file was modified: if (cachingFileStorage.GetBaseVersionHash(ioc) != hash) { //remote file is modified if (cachingFileStorage.HasLocalChanges(ioc)) { //conflict! need to merge _saveDb = new SaveDb(_context, _app, new ActionOnFinish((success, result) => { if (!success) { Finish(false, result); } else { Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); } _saveDb = null; }), false, remoteData); _saveDb.Run(); _app.GetDb().MarkAllGroupsAsDirty(); } else { //only the remote file was modified -> reload database. //note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.) _app.TriggerReload(_context); Finish(true); } } else { //remote file is unmodified if (cachingFileStorage.HasLocalChanges(ioc)) { //but we have local changes -> upload: StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile)); cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)); StatusLogger.UpdateSubMessage(""); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); } else { //files are in sync: just set the result Finish(true, _app.GetResourceString(UiStringKey.FilesInSync)); } } } catch (Exception e) { Finish(false, e.Message); } }
public override void Run() { //check if we will run into problems. Then finish with error before we start doing anything. foreach (var _elementToMove in _elementsToMove) { PwGroup pgParent = _elementToMove.ParentGroup; if (pgParent != _targetGroup) { if (pgParent != null) { PwGroup group = _elementToMove as PwGroup; if (group != null) { if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group))) { Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere)); return; } } } } } HashSet <Database> removeDatabases = new HashSet <Database>(); Database addDatabase = _app.FindDatabaseForElement(_targetGroup); if (addDatabase == null) { Finish(false, "Did not find target database. Did you lock it?"); return; } foreach (var elementToMove in _elementsToMove) { _app.DirtyGroups.Add(elementToMove.ParentGroup); PwGroup pgParent = elementToMove.ParentGroup; if (pgParent != _targetGroup) { if (pgParent != null) // Remove from parent { PwEntry entry = elementToMove as PwEntry; if (entry != null) { var dbRem = _app.FindDatabaseForElement(entry); removeDatabases.Add(dbRem); dbRem.EntriesById.Remove(entry.Uuid); dbRem.Elements.Remove(entry); pgParent.Entries.Remove(entry); _targetGroup.AddEntry(entry, true, true); addDatabase.EntriesById.Add(entry.Uuid, entry); addDatabase.Elements.Add(entry); } else { PwGroup group = (PwGroup)elementToMove; if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group))) { Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere)); return; } var dbRem = _app.FindDatabaseForElement(@group); if (dbRem == null) { Finish(false, "Did not find source database. Did you lock it?"); return; } dbRem.GroupsById.Remove(group.Uuid); dbRem.Elements.Remove(group); removeDatabases.Add(dbRem); pgParent.Groups.Remove(group); _targetGroup.AddGroup(group, true, true); addDatabase.GroupsById.Add(group.Uuid, group); addDatabase.Elements.Add(group); } } } } //first save the database where we added the elements var allDatabasesToSave = new List <Database> { addDatabase }; //then all databases where we removed elements: removeDatabases.RemoveWhere(db => db == addDatabase); allDatabasesToSave.AddRange(removeDatabases); int indexToSave = 0; bool allSavesSuccess = true; void ContinueSave(bool success, string message, Activity activeActivity) { allSavesSuccess &= success; indexToSave++; if (indexToSave == allDatabasesToSave.Count) { OnFinishToRun.SetResult(allSavesSuccess); OnFinishToRun.Run(); return; } SaveDb saveDb = new SaveDb(_ctx, _app, allDatabasesToSave[indexToSave], new ActionOnFinish(activeActivity, ContinueSave), false); saveDb.SetStatusLogger(StatusLogger); saveDb.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1; saveDb.Run(); } SaveDb save = new SaveDb(_ctx, _app, allDatabasesToSave[0], new ActionOnFinish(ActiveActivity, ContinueSave), false); save.SetStatusLogger(StatusLogger); save.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1; save.Run(); }
public override void Run() { if (!_dontSave) { try { if (_db.CanWrite == false) { //this should only happen if there is a problem in the UI so that the user sees an edit interface. Finish(false, "Cannot save changes. File is read-only!"); return; } string message = _app.GetResourceString(UiStringKey.saving_database); if (ShowDatabaseIocInStatus) { message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")"; } StatusLogger.UpdateMessage(message); IOConnectionInfo ioc = _db.Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (_streamForOrigFile == null) { if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); return; } } if ( (_streamForOrigFile != null) || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) || //first try to use the fast change detection (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare: ) { //ask user... _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion, UiStringKey.YesSynchronize, UiStringKey.NoOverwrite, //yes = sync (sender, args) => { Action runHandler = () => { //note: when synced, the file might be downloaded once again from the server. Caching the data //in the hashing function would solve this but increases complexity. I currently assume the files are //small. MergeIn(fileStorage, ioc); PerformSaveWithoutCheck(fileStorage, ioc); _db.UpdateGlobals(); Finish(true); }; RunInWorkerThread(runHandler); }, //no = overwrite (sender, args) => { RunInWorkerThread(() => { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); }); }, //cancel (sender, args) => { RunInWorkerThread(() => Finish(false)); }, _ctx ); } else { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); } } catch (Exception e) { /* TODO KPDesktop: * catch(Exception exSave) * { * MessageService.ShowSaveWarning(pd.IOConnectionInfo, exSave, true); * bSuccess = false; * } */ Kp2aLog.LogUnexpectedError(e); Finish(false, e.Message); return; } } else { Finish(true); } }
public override void Run() { //check if we will run into problems. Then finish with error before we start doing anything. foreach (var _elementToMove in _elementsToMove) { PwGroup pgParent = _elementToMove.ParentGroup; if (pgParent != _targetGroup) { if (pgParent != null) { PwGroup group = _elementToMove as PwGroup; if (group != null) { if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group))) { Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere)); return; } } } } } foreach (var elementToMove in _elementsToMove) { _app.GetDb().Dirty.Add(elementToMove.ParentGroup); PwGroup pgParent = elementToMove.ParentGroup; if (pgParent != _targetGroup) { if (pgParent != null) // Remove from parent { PwEntry entry = elementToMove as PwEntry; if (entry != null) { pgParent.Entries.Remove(entry); _targetGroup.AddEntry(entry, true, true); } else { PwGroup group = (PwGroup)elementToMove; if ((_targetGroup == group) || (_targetGroup.IsContainedIn(group))) { Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere)); return; } pgParent.Groups.Remove(group); _targetGroup.AddGroup(group, true, true); } } } } _onFinishToRun = new ActionOnFinish(ActiveActivity, (success, message, activity) => { if (!success) { // Let's not bother recovering from a failure. _app.LockDatabase(false); } }, OnFinishToRun); // Save SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, false); save.SetStatusLogger(StatusLogger); save.Run(); }
public override void Run() { try { try { //make sure the file data is stored in the recent files list even if loading fails SaveFileData(_ioc, _keyfileOrProvider); StatusLogger.UpdateMessage(UiStringKey.loading_database); //get the stream data into a single stream variable (databaseStream) regardless whether its preloaded or not: MemoryStream preloadedMemoryStream = _databaseData == null ? null : _databaseData.Result; MemoryStream databaseStream; if (preloadedMemoryStream != null) { databaseStream = preloadedMemoryStream; } else { using (Stream s = _app.GetFileStorage(_ioc).OpenFileForRead(_ioc)) { databaseStream = new MemoryStream(); s.CopyTo(databaseStream); databaseStream.Seek(0, SeekOrigin.Begin); } } //ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess: _format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_app.GetFileStorage(_ioc).GetFileExtension(_ioc))); TryLoad(databaseStream); success = true; } catch (Exception e) { this.Exception = e; throw; } } catch (KeyFileException) { Kp2aLog.Log("KeyFileException"); Finish(false, /*TODO Localize: use Keepass error text KPRes.KeyFileError (including "or invalid format")*/ _app.GetResourceString(UiStringKey.keyfile_does_not_exist), false, Exception); } catch (AggregateException e) { string message = e.Message; foreach (var innerException in e.InnerExceptions) { message = innerException.Message; // Override the message shown with the last (hopefully most recent) inner exception Kp2aLog.LogUnexpectedError(innerException); } Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + message, false, Exception); return; } catch (DuplicateUuidsException e) { Kp2aLog.Log(e.ToString()); Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + e.Message + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception); return; } catch (Exception e) { if (!(e is InvalidCompositeKeyException)) { Kp2aLog.LogUnexpectedError(e); } Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception); return; } }
public override void Run() { if (!_dontSave) { try { if (_db.CanWrite == false) { //this should only happen if there is a problem in the UI so that the user sees an edit interface. Finish(false, "Cannot save changes. File is read-only!"); return; } string message = _app.GetResourceString(UiStringKey.saving_database); if (ShowDatabaseIocInStatus) { message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")"; } StatusLogger.UpdateMessage(message); IOConnectionInfo ioc = _db.Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (_streamForOrigFile == null) { if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); return; } } bool hasStreamForOrigFile = (_streamForOrigFile != null); bool hasChangeFast = hasStreamForOrigFile || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion); //first try to use the fast change detection; bool hasHashChanged = hasChangeFast || (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed); //if that fails, hash the file and compare: if (hasHashChanged) { Kp2aLog.Log("Conflict. " + hasStreamForOrigFile + " " + hasChangeFast + " " + hasHashChanged); bool alwaysMerge = (PreferenceManager.GetDefaultSharedPreferences(Application.Context) .GetBoolean("AlwaysMergeOnConflict", false)); if (alwaysMerge) { MergeAndFinish(fileStorage, ioc); } else { //ask user... _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion, UiStringKey.YesSynchronize, UiStringKey.NoOverwrite, //yes = sync (sender, args) => { Action runHandler = () => { MergeAndFinish(fileStorage, ioc); }; RunInWorkerThread(runHandler); }, //no = overwrite (sender, args) => { RunInWorkerThread(() => { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); }); }, //cancel (sender, args) => { RunInWorkerThread(() => Finish(false)); }, _ctx ); } } else { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); } } catch (Exception e) { /* TODO KPDesktop: * catch(Exception exSave) * { * MessageService.ShowSaveWarning(pd.IOConnectionInfo, exSave, true); * bSuccess = false; * } */ Kp2aLog.LogUnexpectedError(e); Finish(false, e.Message); return; } } else { Finish(true); } }