예제 #1
0
        public async Task Initialize()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            MethodInfo testMethod = GetType().GetRuntimeMethod(
                TestContext.TestName, new Type[0]
                );

            var specAttr = testMethod.GetCustomAttribute <DetailsForAttribute>();
            var dataAttr = testMethod.GetCustomAttribute <TestDataAttribute>();

            Assert.IsTrue(specAttr != null || dataAttr != null);

            try
            {
                Utils.DatabaseInfo databaseInfo = await Utils.GetDatabaseInfoForTest(TestContext);

                KdbxReader reader = new KdbxReader();

                using (IRandomAccessStream stream = await databaseInfo.Database.AsIStorageFile.OpenReadAsync())
                {
                    Assert.IsFalse((await reader.ReadHeaderAsync(stream, cts.Token)).IsError);
                    KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, databaseInfo.Password, databaseInfo.Keyfile, cts.Token);

                    Assert.IsFalse(decryption.Result.IsError);
                    this.document = decryption.GetDocument();

                    if (specAttr != null && (dataAttr == null || !dataAttr.SkipInitialization))
                    {
                        IDatabaseNavigationViewModel navVm = new DatabaseNavigationViewModel();
                        navVm.SetGroup(this.document.Root.DatabaseGroup);

                        IDatabasePersistenceService persistenceService = new DummyPersistenceService();

                        this.instantiationTime = DateTime.Now;
                        if (specAttr.IsNew)
                        {
                            this.expectedParent = this.document.Root.DatabaseGroup;
                            this.viewModel      = GetNewViewModel(navVm, persistenceService, this.document, this.expectedParent);
                        }
                        else
                        {
                            this.expectedParent = this.document.Root.DatabaseGroup;
                            this.viewModel      = GetExistingViewModel(
                                navVm,
                                persistenceService,
                                this.document,
                                specAttr.IsOpenedReadOnly
                                );
                        }
                    }
                    else
                    {
                        this.expectedParent = null;
                        Assert.IsTrue(dataAttr.SkipInitialization);
                    }
                }
            }
            catch (InvalidOperationException) { }
        }
예제 #2
0
        public async Task Initialize()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            this.clipboardService = new SensitiveClipboardService(this.clipboard);

            try
            {
                Utils.DatabaseInfo databaseInfo = await Utils.GetDatabaseInfoForTest(TestContext);

                KdbxReader reader = new KdbxReader();

                using (IRandomAccessStream stream = await databaseInfo.Database.AsIStorageFile.OpenReadAsync())
                {
                    Assert.IsFalse((await reader.ReadHeaderAsync(stream, cts.Token)).IsError);
                    KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, databaseInfo.Password, databaseInfo.Keyfile, cts.Token);

                    Assert.IsFalse(decryption.Result.IsError);
                    this.viewModel = new DatabaseViewModel(
                        decryption.GetDocument(),
                        new MockResourceProvider(),
                        reader.HeaderData.GenerateRng(),
                        new DatabaseNavigationViewModel(),
                        new DummyPersistenceService(),
                        new AppSettingsService(new InMemorySettingsProvider()),
                        this.clipboardService
                        );

                    await this.viewModel.ActivateAsync();
                }
            }
            catch (InvalidOperationException) { }
        }
예제 #3
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");
            }
        }
예제 #4
0
        public async Task ChangePassword()
        {
            string newPw = "TestPW";

            this.masterKeyVm.MasterPassword = newPw;
            Assert.IsFalse(this.masterKeyVm.ConfirmCommand.CanExecute(null), "Should not be able to confirm new password until password is entered twice");
            this.masterKeyVm.ConfirmedPassword = newPw;
            Assert.IsTrue(this.masterKeyVm.ConfirmCommand.CanExecute(null), "Should be able to confirm new password when second password matches");
            this.masterKeyVm.ConfirmedPassword = "******";
            Assert.IsFalse(this.masterKeyVm.ConfirmCommand.CanExecute(null), "Mismatched passwords should not be able to be confirmed");
            this.masterKeyVm.ConfirmedPassword = newPw;

            DateTime lastPasswordChange = this.document.Metadata.MasterKeyChanged.Value;

            this.masterKeyVm.ConfirmCommand.Execute(null);
            DateTime passwordChangeTime = DateTime.Parse(this.document.Metadata.MasterKeyChanged.Value.ToString());

            Assert.IsTrue(passwordChangeTime > lastPasswordChange, "MasterKeyChanged value should have changed in document metadata");

            Assert.IsTrue(await this.persistenceService.Save(this.document));

            KdbxReader reader = new KdbxReader();

            using (IRandomAccessStream stream = await this.saveFile.AsIStorageFile.OpenReadAsync())
            {
                await reader.ReadHeaderAsync(stream, CancellationToken.None);

                KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, newPw, null, CancellationToken.None);

                Assert.AreEqual(KdbxParserCode.Success, decryption.Result.Code, "Database should decrypt with the new credentials");
                KdbxDocument document = decryption.GetDocument();
                Assert.AreEqual(passwordChangeTime, document.Metadata.MasterKeyChanged.Value, "MasterKeyChanged timestamp should have been persisted");
            }
        }
예제 #5
0
        public async Task DowngradeCipherSettings()
        {
            DateTime lastPasswordChange = this.document.Metadata.MasterKeyChanged.Value;

            Assert.AreEqual(EncryptionAlgorithm.ChaCha20, this.settingsVm.Cipher, "ChaCha20 should be the encryption algorithm before the test starts");
            this.writer.Cipher = EncryptionAlgorithm.Aes;

            Assert.IsInstanceOfType(this.settingsVm.GetKdfParameters(), typeof(Argon2Parameters), "Argon2 should be the KDF before the test starts according to the VM");
            Assert.IsInstanceOfType(this.writer.KdfParameters, typeof(Argon2Parameters), "Argon2 should be the KDF before the test starts according to the KdbxWriter");

            this.settingsVm.KdfGuid       = AesParameters.AesUuid;
            this.settingsVm.KdfIterations = 6001;

            Assert.IsInstanceOfType(this.writer.KdfParameters, typeof(AesParameters), "Changes to the settings VM should be reflected in the KdbxWriter");
            Assert.IsTrue(await this.persistenceService.Save(this.document));

            KdbxReader reader = new KdbxReader();

            using (IRandomAccessStream stream = await this.saveFile.AsIStorageFile.OpenReadAsync())
            {
                await reader.ReadHeaderAsync(stream, CancellationToken.None);

                Assert.AreEqual(EncryptionAlgorithm.Aes, reader.HeaderData.Cipher, "New reader should have the correct cipher");
                AesParameters aesParams = reader.HeaderData.KdfParameters as AesParameters;
                Assert.IsNotNull(aesParams, "Database should have properly persisted with AES");
                Assert.AreEqual(6001, (int)aesParams.Rounds, "AES iteration count should have been persisted correctly");

                KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, this.dbPassword, this.dbKeyFile, CancellationToken.None);

                Assert.AreEqual(KdbxParserCode.Success, decryption.Result.Code);
                KdbxDocument document = decryption.GetDocument();
                Assert.AreEqual(lastPasswordChange, document.Metadata.MasterKeyChanged.Value, "MasterKeyChanged timestamp should not have changed");
            }
        }
예제 #6
0
        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);
        }
예제 #7
0
        public async Task Initialize()
        {
            Utils.DatabaseInfo databaseInfo = await Utils.GetDatabaseInfoForTest(TestContext);

            KdbxReader reader = new KdbxReader();

            using (IRandomAccessStream stream = await databaseInfo.Database.AsIStorageFile.OpenReadAsync())
            {
                Assert.IsFalse((await reader.ReadHeaderAsync(stream, CancellationToken.None)).IsError);
                KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, databaseInfo.Password, databaseInfo.Keyfile, CancellationToken.None);

                Assert.IsFalse(decryption.Result.IsError);
                this.document = decryption.GetDocument();
                this.rng      = reader.HeaderData.GenerateRng();
            }
        }
예제 #8
0
        public async Task Initialize()
        {
            try
            {
                CancellationTokenSource cts = new CancellationTokenSource();

                Utils.DatabaseInfo databaseInfo = await Utils.GetDatabaseInfoForTest(TestContext);

                KdbxReader reader = new KdbxReader();

                using (IRandomAccessStream stream = await databaseInfo.Database.AsIStorageFile.OpenReadAsync())
                {
                    Assert.IsFalse((await reader.ReadHeaderAsync(stream, cts.Token)).IsError);
                    KdbxDecryptionResult decryption = await reader.DecryptFileAsync(stream, databaseInfo.Password, databaseInfo.Keyfile, cts.Token);

                    Assert.IsFalse(decryption.Result.IsError);
                    this.document = decryption.GetDocument();
                }
            }
            catch (InvalidOperationException) { }

            this.viewModel = new DatabaseNavigationViewModel();
        }
예제 #9
0
        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();
        }