Exemple #1
0
        private async Task RoundTrip()
        {
            ReaderResult initialHeaderResult = await this.reader.ReadHeaderAsync(await this.thisTestInfo.Database.AsIStorageFile.OpenReadAsync(), CancellationToken.None);

            Assert.AreEqual(ReaderResult.Success, initialHeaderResult, "Initial header read should be successful");

            KdbxDecryptionResult result = await this.reader.DecryptFileAsync(await this.thisTestInfo.Database.AsIStorageFile.OpenReadAsync(), this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None);

            Assert.AreEqual(ReaderResult.Success, result.Result, "File should have initially decrypted properly");
            KdbxDocument kdbxDoc = result.GetDocument();
            IKdbxWriter  writer  = this.reader.GetWriter();

            using (var stream = new InMemoryRandomAccessStream())
            {
                bool writeResult = await writer.WriteAsync(stream, kdbxDoc, CancellationToken.None);

                Assert.IsTrue(writeResult, "File should have written successfully");

                stream.Seek(0);
                KdbxReader   newReader = new KdbxReader();
                ReaderResult result2   = await newReader.ReadHeaderAsync(stream, CancellationToken.None);

                Assert.AreEqual(ReaderResult.Success, result2, "Header should been read back successfully after write");

                KdbxDecryptionResult result3 = await newReader.DecryptFileAsync(stream, this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None);

                Assert.AreEqual(ReaderResult.Success, result3.Result, "File should have decrypted successfully after write");

                KdbxDocument roundTrippedDocument = result3.GetDocument();
                Assert.AreEqual(kdbxDoc, roundTrippedDocument, "Round-tripped document should be equal to original document");
            }
        }
 /// <summary>
 /// Initializes the instance.
 /// </summary>
 /// <param name="writer">IKdbxWriter used to persist the document.</param>
 /// <param name="settings">Provider for database serialization settings.</param>
 /// <param name="candidate">Default location to save the document.</param>
 /// <param name="syncContext">ISyncContext for property change notifications.</param>
 /// <param name="canSave">Stupid dumb hack since StorageFiles suck on phone and have inaccurate attributes.</param>
 public DefaultFilePersistenceService(IKdbxWriter writer, IDatabaseSettingsProvider settings, IDatabaseCandidate candidate, ISyncContext syncContext, bool canSave)
 {
     this.saveSemaphore   = new SemaphoreSlim(1, 1);
     this.fileWriter      = writer ?? throw new ArgumentNullException(nameof(writer));
     this.settings        = settings ?? throw new ArgumentNullException(nameof(settings));
     this.defaultSaveFile = candidate ?? throw new ArgumentNullException(nameof(candidate));
     this.syncContext     = syncContext ?? throw new ArgumentNullException(nameof(syncContext));
     CanSave = canSave;
 }
        public async Task Init()
        {
            // Get database from test attributes
            Utils.DatabaseInfo dbInfo = await Utils.GetDatabaseInfoForTest(TestContext);

            this.dbPassword = dbInfo.Password;
            this.dbKeyFile  = dbInfo.Keyfile;

            // 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.saveFile = (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.saveFile.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 services we can use for the test
            this.writer             = reader.GetWriter();
            this.persistenceService = new DefaultFilePersistenceService(
                this.writer,
                this.writer,
                new StorageFileDatabaseCandidate(this.saveFile, true),
                new MockSyncContext(),
                true
                );
            this.credentialStorage = new MockCredentialProvider();
            this.masterKeyVm       = new MasterKeyChangeViewModel(
                this.document,
                this.saveFile,
                new DatabaseCredentialProvider(this.persistenceService, this.credentialStorage),
                new MockFileService()
                );
            this.settingsVm = new DatabaseSettingsViewModel(this.writer);
        }
Exemple #4
0
        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
                    )
                );
        }
Exemple #5
0
        /// <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
                            )
                        );
                }
            }
        }