public async Task Init() { // Get database from test attributes Utils.DatabaseInfo dbInfo = await Utils.GetDatabaseInfoForTest(TestContext); // Assert that databases named *ReadOnly* are actually readonly after a clone if (dbInfo.Database.Name.IndexOf("ReadOnly", StringComparison.OrdinalIgnoreCase) >= 0) { Assert.IsFalse( await dbInfo.Database.CheckWritableAsync(), $"This file is expected to be read-only; please verify this before testing: {dbInfo.Database.Name}" ); } this.fileUnderTest = (await dbInfo.Database.AsIStorageFile.CopyAsync( ApplicationData.Current.TemporaryFolder, $"PersistenceTestDb-{Guid.NewGuid()}.kdbx", NameCollisionOption.ReplaceExisting )).AsWrapper(); // Use a KdbxReader to parse the database and get a corresponding writer KdbxReader reader = new KdbxReader(); using (IRandomAccessStream stream = await this.fileUnderTest.AsIStorageFile.OpenReadAsync()) { await reader.ReadHeaderAsync(stream, CancellationToken.None); KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, dbInfo.Password, dbInfo.Keyfile, CancellationToken.None); Assert.AreEqual(KdbxParserCode.Success, decryption.Result.Code); this.document = decryption.GetDocument(); } // Construct a service we can use for the test IKdbxWriter writer = reader.GetWriter(); this.serviceUnderTest = new DefaultFilePersistenceService( writer, writer, new StorageFileDatabaseCandidate(this.fileUnderTest, true), new MockSyncContext(), await this.fileUnderTest.CheckWritableAsync(true) ); }
private async Task RaiseDocumentReady(KdbxDocument document, IDatabaseCandidate candidate) { DebugHelper.Assert(HasGoodHeader); if (!HasGoodHeader) { throw new InvalidOperationException("Document cannot be ready, because the KdbxReader does not have good HeaderData."); } IDatabasePersistenceService persistenceService; if (IsSampleFile) { persistenceService = new DummyPersistenceService(); } else { IKdbxWriter writer = this.kdbxReader.GetWriter(); persistenceService = new DefaultFilePersistenceService( writer, writer, candidate, this.syncContext, await candidate.File.CheckWritableAsync() ); } DocumentReady?.Invoke( this, new DocumentReadyEventArgs( document, candidate, persistenceService, this.kdbxReader.HeaderData.GenerateRng(), this.keyChangeVmFactory ) ); }
/// <summary> /// Uses provided options to generate a database file. /// </summary> protected override async Task HandleCredentialsAsync(string confirmedPassword, ITestableFile chosenKeyFile) { CancellationTokenSource cts = new CancellationTokenSource(); IKdbxWriter writer = this.writerFactory.Assemble( confirmedPassword, chosenKeyFile, Settings.Cipher, Settings.GetKdfParameters() ); IRandomNumberGenerator rng = writer.HeaderData.GenerateRng(); KdbxDocument newDocument = new KdbxDocument(new KdbxMetadata("PassKeep Database")); if (!CreateEmpty) { IList <IKeePassGroup> groups = new List <IKeePassGroup> { new KdbxGroup(newDocument.Root.DatabaseGroup), new KdbxGroup(newDocument.Root.DatabaseGroup), new KdbxGroup(newDocument.Root.DatabaseGroup), new KdbxGroup(newDocument.Root.DatabaseGroup), new KdbxGroup(newDocument.Root.DatabaseGroup), new KdbxGroup(newDocument.Root.DatabaseGroup) }; groups[0].Title.ClearValue = "General"; groups[1].Title.ClearValue = "Windows"; groups[2].Title.ClearValue = "Network"; groups[3].Title.ClearValue = "Internet"; groups[4].Title.ClearValue = "eMail"; groups[5].Title.ClearValue = "Homebanking"; groups[0].IconID = 48; groups[1].IconID = 38; groups[2].IconID = 3; groups[3].IconID = 1; groups[4].IconID = 19; groups[5].IconID = 37; foreach (IKeePassGroup group in groups) { newDocument.Root.DatabaseGroup.Children.Add(group); } IList <IKeePassEntry> entries = new List <IKeePassEntry> { new KdbxEntry(newDocument.Root.DatabaseGroup, rng, newDocument.Metadata), new KdbxEntry(newDocument.Root.DatabaseGroup, rng, newDocument.Metadata) }; entries[0].Title.ClearValue = "Sample Entry"; entries[1].Title.ClearValue = "Sample Entry #2"; entries[0].UserName.ClearValue = "User Name"; entries[1].UserName.ClearValue = "Michael321"; entries[0].Password.ClearValue = "Password"; entries[1].Password.ClearValue = "12345"; entries[0].Url.ClearValue = "http://keepass.info/"; entries[1].Url.ClearValue = "http://keepass.info/help/kb/testform.html"; entries[0].Notes.ClearValue = "Notes"; foreach (IKeePassEntry entry in entries) { newDocument.Root.DatabaseGroup.Children.Add(entry); } } using (IRandomAccessStream stream = await File.AsIStorageFile.OpenAsync(FileAccessMode.ReadWrite)) { Task <bool> writeTask = writer.WriteAsync(stream, newDocument, cts.Token); this.taskNotificationService.PushOperation(writeTask, cts, AsyncOperationType.DatabaseEncryption); if (await writeTask) { this.futureAccessList.Add(File, File.AsIStorageItem.Name); IDatabaseCandidate candidate = await this.candidateFactory.AssembleAsync(File); IDatabasePersistenceService persistenceService = new DefaultFilePersistenceService( writer, writer, candidate, this.syncContext, true); DocumentReady?.Invoke( this, new DocumentReadyEventArgs( newDocument, candidate, persistenceService, writer.HeaderData.GenerateRng(), this.keyChangeVmFactory ) ); } } }
public async Task MultiEdit_Degenerate() { StorageFileDatabaseCandidateFactory factory = new StorageFileDatabaseCandidateFactory(new MockFileProxyProvider { ScopeValue = true }); StorageFolder work = await Utils.GetWorkFolder(); IDatabaseCandidate workDb = await factory.AssembleAsync( (await this.thisTestInfo.Database.AsIStorageFile.CopyAsync(work, "Work.kdbx", NameCollisionOption.ReplaceExisting)) .AsWrapper() ); IKdbxWriter writer; KdbxDocument doc; var reader = new KdbxReader(); using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { ReaderResult headerResult = await reader.ReadHeaderAsync(stream, CancellationToken.None); Assert.AreEqual(headerResult, ReaderResult.Success); } KdbxDecryptionResult bodyResult = null; using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { bodyResult = await reader.DecryptFileAsync(stream, this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None); Assert.AreEqual(bodyResult.Result, ReaderResult.Success); } writer = reader.GetWriter(); doc = bodyResult.GetDocument(); IDatabasePersistenceService persistor = new DefaultFilePersistenceService(writer, writer, workDb, new MockSyncContext(), await workDb.File.CheckWritableAsync()); Assert.IsTrue(persistor.CanSave); Assert.IsTrue(await persistor.Save(doc)); // Remove the last group doc.Root.DatabaseGroup.Children.RemoveAt( doc.Root.DatabaseGroup.Children.IndexOf( doc.Root.DatabaseGroup.Children.Last(node => node is IKeePassGroup) ) ); Assert.IsTrue(await persistor.Save(doc)); reader = new KdbxReader(); using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { ReaderResult headerResult = await reader.ReadHeaderAsync(stream, CancellationToken.None); Assert.AreEqual(headerResult, ReaderResult.Success); } using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { bodyResult = await reader.DecryptFileAsync(stream, this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None); Assert.AreEqual(bodyResult.Result, ReaderResult.Success); } writer = reader.GetWriter(); doc = bodyResult.GetDocument(); doc.Root.DatabaseGroup.Children.RemoveAt( doc.Root.DatabaseGroup.Children.IndexOf( doc.Root.DatabaseGroup.Children.Last(node => node is IKeePassGroup) ) ); Assert.IsTrue(await persistor.Save(doc)); reader = new KdbxReader(); using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { ReaderResult headerResult = await reader.ReadHeaderAsync(stream, CancellationToken.None); Assert.AreEqual(headerResult, ReaderResult.Success); } using (IRandomAccessStream stream = await workDb.GetRandomReadAccessStreamAsync()) { bodyResult = await reader.DecryptFileAsync(stream, this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None); Assert.AreEqual(bodyResult.Result, ReaderResult.Success); } writer = reader.GetWriter(); doc = bodyResult.GetDocument(); }