public async void CredentialStorageFailedHandler(object sender, CredentialStorageFailureEventArgs e)
        {
            using (e.GetDeferral())
            {
                // Prompt the user to delete a credential, then try again
                await new PasswordManagementDialog(
                    await e.GetSavedCredentialsViewModelAsync(),
                    GetString(CredentialStorageFullResourceKey)
                    ).ShowAsync();

                if (!await e.RetryStorage())
                {
                    // Show a dialog explaining that we still can't store the credential
                    MessageDialog failureDialog = new MessageDialog(
                        GetString(CredentialsStorageFailedResourceKey),
                        GetString(CredentialsStorageFailedTitleResourceKey)
                        )
                    {
                        Options = MessageDialogOptions.None
                    };

                    failureDialog.Commands.Add(
                        new UICommand(GetString("OK"))
                        );

                    await failureDialog.ShowAsync();
                }
            }
        }
Example #2
0
        /// <summary>
        /// Attempts to unlock the document file.
        /// </summary>
        /// <param name="storedCredential">The key to use for decryption - if null, the ViewModel's
        /// credentials are used instead.</param>
        private async Task DoUnlockAsync(IBuffer storedCredential)
        {
            DebugHelper.Assert(CanUnlock());
            if (!CanUnlock())
            {
                throw new InvalidOperationException("The ViewModel is not in a state that can unlock the database!");
            }

            CancellationTokenSource cts = new CancellationTokenSource();

            try
            {
                using (IRandomAccessStream stream = await CandidateFile.GetRandomReadAccessStreamAsync())
                {
                    Task <KdbxDecryptionResult> decryptionTask;
                    if (storedCredential != null)
                    {
                        decryptionTask = this.kdbxReader.DecryptFile(stream, storedCredential, cts.Token);
                    }
                    else
                    {
                        decryptionTask = this.kdbxReader.DecryptFileAsync(stream, Password, KeyFile, cts.Token);
                    }

                    if (this.taskNotificationService.CurrentTask == null || this.taskNotificationService.CurrentTask.IsCompleted)
                    {
                        this.taskNotificationService.PushOperation(decryptionTask, cts, AsyncOperationType.DatabaseDecryption);
                    }
                    KdbxDecryptionResult result = await decryptionTask;

                    ParseResult = result.Result;

                    DebugHelper.Trace($"Got ParseResult from database unlock attempt: {ParseResult}");
                    if (!ParseResult.IsError)
                    {
                        // The database candidate to proceed into the next stage with
                        IDatabaseCandidate candidateToUse = CandidateFile;

                        if (CacheDatabase)
                        {
                            // We do not use UseAppControlledDatabaseAsync here because it has extra baggage.
                            // We don't need to refresh the view at this stage, just fire an event using
                            // the cached file.
                            candidateToUse = await GetCachedCandidateAsync();
                        }
                        if (RememberDatabase)
                        {
                            string accessToken = this.futureAccessList.Add(candidateToUse.File, candidateToUse.FileName);
                            DebugHelper.Trace($"Unlock was successful and database was remembered with token: {accessToken}");
                        }
                        else
                        {
                            DebugHelper.Trace("Unlock was successful but user opted not to remember the database.");
                        }

                        if (SaveCredentials)
                        {
                            bool storeCredential = false;

                            // If we were not already using a stored credential, we need user
                            // consent to continue.
                            if (storedCredential == null)
                            {
                                Task <bool> identityTask = this.identityService.VerifyIdentityAsync();
                                if (this.taskNotificationService.CurrentTask == null || this.taskNotificationService.CurrentTask.IsCompleted)
                                {
                                    this.taskNotificationService.PushOperation(identityTask, AsyncOperationType.IdentityVerification);
                                }

                                storeCredential  = await identityTask;
                                storedCredential = result.GetRawKey();
                            }
                            else
                            {
                                // If we have a stored credential, we already got consent.
                                storeCredential = true;
                            }

                            if (storeCredential)
                            {
                                if (!await this.credentialProvider.TryStoreRawKeyAsync(candidateToUse.File, storedCredential))
                                {
                                    EventHandler <CredentialStorageFailureEventArgs> handler = CredentialStorageFailed;
                                    if (handler != null)
                                    {
                                        // If we could not store a credential, give the View a chance to try again.
                                        CredentialStorageFailureEventArgs eventArgs =
                                            new CredentialStorageFailureEventArgs(
                                                this.credentialProvider,
                                                this.credentialViewModelFactory,
                                                candidateToUse,
                                                storedCredential
                                                );

                                        handler(this, eventArgs);
                                        await eventArgs.DeferAsync();
                                    }
                                }
                            }
                        }

                        await RaiseDocumentReady(result.GetDocument(), candidateToUse);
                    }
                }
            }
            catch (COMException)
            {
                // In the Windows 8.1 preview, opening a stream to a SkyDrive file can fail with no workaround.
                ParseResult = new ReaderResult(KdbxParserCode.UnableToReadFile);
            }
        }