public static PwEntry DuplicateTo(this PwEntry entry, PwGroup parent) { PwEntry copy = new PwEntry(false, false); copy.Uuid = entry.Uuid; copy.AssignProperties(entry, false, false, true); //TODO MST: clear this comment and it's ramifications! //HACK: CloneDeep introduces the copy into the parent node, therefore SetParent triggers a change of the parent // which shouldn't be - the extended ProtectionSection in KeeShare should prevent interference, but a // a clean way to clone a node without cloning children and without hooking it into a tree would be nice copy.SetParent(parent); return(copy); }
public override void Run() { if (Success) { // Mark parent group dirty. Even only the last modification date changed, this might affect sort order PwGroup parent = _updatedEntry.ParentGroup; if (parent != null) { // Mark parent group dirty _app.GetDb().Dirty.Add(parent); } } else { StatusLogger.UpdateMessage(UiStringKey.UndoingChanges); // If we fail to save, back out changes to global structure //TODO test fail _updatedEntry.AssignProperties(_backup, false, true, false); } base.Run(); }
/// <summary> /// Synchronize the current database with another one. /// </summary> /// <param name="pwSource">Input database to synchronize with. This input /// database is used to update the current one, but is not modified! You /// must copy the current object if you want a second instance of the /// synchronized database. The input database must not be seen as valid /// database any more after calling <c>Synchronize</c>.</param> /// <param name="mm">Merge method.</param> public void MergeIn(PwDatabase pwSource, PwMergeMethod mm) { if(mm == PwMergeMethod.CreateNewUuids) { pwSource.RootGroup.CreateNewItemUuids(true, true, true); } GroupHandler gh = delegate(PwGroup pg) { if(pg == pwSource.m_pgRootGroup) return true; PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true); if(pgLocal == null) { PwGroup pgSourceParent = pg.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); PwGroup pgNew = new PwGroup(); pgNew.Uuid = pg.Uuid; pgNew.AssignProperties(pg, false); pgLocalContainer.AddGroup(pgNew, true); } else // pgLocal != null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if(mm == PwMergeMethod.OverwriteExisting) pgLocal.AssignProperties(pg, false); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { pgLocal.AssignProperties(pg, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return true; }; EntryHandler eh = delegate(PwEntry pe) { PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true); if(peLocal == null) { PwGroup pgSourceParent = pe.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); PwEntry peNew = new PwEntry(false, false); peNew.Uuid = pe.Uuid; peNew.AssignProperties(pe, false, true); pgLocalContainer.AddEntry(peNew, true); } else // peLocal == null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if(mm == PwMergeMethod.OverwriteExisting) peLocal.AssignProperties(pe, false, true); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { peLocal.AssignProperties(pe, true, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return true; }; if(!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh)) throw new InvalidOperationException(); if(mm == PwMergeMethod.Synchronize) { ApplyDeletions(pwSource.m_vDeletedObjects, true); ApplyDeletions(m_vDeletedObjects, false); } }
/// <summary> /// Exports all entries with the given tag to a new database at the given path. /// </summary> /// <param name="sourceDb">The source database.</param> /// <param name="settings">The settings for this job.</param> private static void CopyToNewDb(PwDatabase sourceDb, Settings settings) { // Create a key for the target database CompositeKey key = new CompositeKey(); bool hasPassword = false; bool hasKeyFile = false; if (!settings.Password.IsEmpty) { byte[] passwordByteArray = settings.Password.ReadUtf8(); key.AddUserKey(new KcpPassword(passwordByteArray)); MemUtil.ZeroByteArray(passwordByteArray); hasPassword = true; } // Load a keyfile for the target database if requested (and add it to the key) if (!string.IsNullOrEmpty(settings.KeyFilePath)) { bool bIsKeyProv = Program.KeyProviderPool.IsKeyProvider(settings.KeyFilePath); if (!bIsKeyProv) { try { key.AddUserKey(new KcpKeyFile(settings.KeyFilePath, true)); hasKeyFile = true; } catch (InvalidDataException exId) { MessageService.ShowWarning(settings.KeyFilePath, exId); } catch (Exception exKf) { MessageService.ShowWarning(settings.KeyFilePath, KPRes.KeyFileError, exKf); } } else { KeyProviderQueryContext ctxKp = new KeyProviderQueryContext( ConnectionInfo, true, false); KeyProvider prov = Program.KeyProviderPool.Get(settings.KeyFilePath); bool bPerformHash = !prov.DirectKey; byte[] pbCustomKey = prov.GetKey(ctxKp); if ((pbCustomKey != null) && (pbCustomKey.Length > 0)) { try { key.AddUserKey(new KcpCustomKey(settings.KeyFilePath, pbCustomKey, bPerformHash)); hasKeyFile = true; } catch (Exception exCkp) { MessageService.ShowWarning(exCkp); } MemUtil.ZeroByteArray(pbCustomKey); } } } // Check if at least a password or a keyfile have been added to the key object if (!hasPassword && !hasKeyFile) { // Fail if not throw new InvalidOperationException("For the target database at least a password or a keyfile is required."); } // Create a new database PwDatabase targetDatabase = new PwDatabase(); // Apply the created key to the new database targetDatabase.New(new IOConnectionInfo(), key); // Copy database settings targetDatabase.Color = sourceDb.Color; targetDatabase.Compression = sourceDb.Compression; targetDatabase.DataCipherUuid = sourceDb.DataCipherUuid; targetDatabase.DefaultUserName = sourceDb.DefaultUserName; targetDatabase.Description = sourceDb.Description; targetDatabase.HistoryMaxItems = sourceDb.HistoryMaxItems; targetDatabase.HistoryMaxSize = sourceDb.HistoryMaxSize; targetDatabase.MaintenanceHistoryDays = sourceDb.MaintenanceHistoryDays; targetDatabase.MasterKeyChangeForce = sourceDb.MasterKeyChangeForce; targetDatabase.MasterKeyChangeRec = sourceDb.MasterKeyChangeRec; targetDatabase.Name = sourceDb.Name; targetDatabase.RecycleBinEnabled = sourceDb.RecycleBinEnabled; if (settings.KeyTransformationRounds == 0) { // keyTransformationRounds was not set -> use the one from the source database settings.KeyTransformationRounds = sourceDb.KdfParameters.GetUInt64(AesKdf.ParamRounds, 0); } // Set keyTransformationRounds (min PwDefs.DefaultKeyEncryptionRounds) targetDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, Math.Max(PwDefs.DefaultKeyEncryptionRounds, settings.KeyTransformationRounds)); // Assign the properties of the source root group to the target root group targetDatabase.RootGroup.AssignProperties(sourceDb.RootGroup, false, true); HandleCustomIcon(targetDatabase, sourceDb, sourceDb.RootGroup); // Overwrite the root group name if requested if (!string.IsNullOrEmpty(settings.RootGroupName)) { targetDatabase.RootGroup.Name = settings.RootGroupName; } // Find all entries matching the tag PwObjectList <PwEntry> entries = new PwObjectList <PwEntry>(); if (!string.IsNullOrEmpty(settings.Tag) && string.IsNullOrEmpty(settings.Group)) { // Tag only export sourceDb.RootGroup.FindEntriesByTag(settings.Tag, entries, true); } else if (string.IsNullOrEmpty(settings.Tag) && !string.IsNullOrEmpty(settings.Group)) { // Tag and group export PwGroup groupToExport = sourceDb.RootGroup.GetFlatGroupList().FirstOrDefault(g => g.Name == settings.Group); if (groupToExport == null) { throw new ArgumentException("No group with the name of the Group-Setting found."); } entries = groupToExport.GetEntries(true); } else if (!string.IsNullOrEmpty(settings.Tag) && !string.IsNullOrEmpty(settings.Group)) { // Tag and group export PwGroup groupToExport = sourceDb.RootGroup.GetFlatGroupList().FirstOrDefault(g => g.Name == settings.Group); if (groupToExport == null) { throw new ArgumentException("No group with the name of the Group-Setting found."); } groupToExport.FindEntriesByTag(settings.Tag, entries, true); } else { throw new ArgumentException("At least one of Tag or ExportFolderName must be set."); } // Copy all entries to the new database foreach (PwEntry entry in entries) { // Get or create the target group in the target database (including hierarchy) PwGroup targetGroup = CreateTargetGroupInDatebase(entry, targetDatabase, sourceDb); // Clone entry PwEntry peNew = new PwEntry(false, false); peNew.Uuid = entry.Uuid; peNew.AssignProperties(entry, false, true, true); // Handle custom icon HandleCustomIcon(targetDatabase, sourceDb, entry); // Add entry to the target group in the new database targetGroup.AddEntry(peNew, true); } // Create target folder (if not exist) string targetFolder = Path.GetDirectoryName(settings.TargetFilePath); if (targetFolder == null) { throw new ArgumentException("Can't get target folder."); } Directory.CreateDirectory(targetFolder); // Save the new database under the target path KdbxFile kdbx = new KdbxFile(targetDatabase); using (FileStream outputStream = new FileStream(settings.TargetFilePath, FileMode.Create)) { kdbx.Save(outputStream, null, KdbxFormat.Default, new NullStatusLogger()); } }