Beispiel #1
0
        /// <summary>
        /// Constructs the RootViewModel with the specified parameters.
        /// </summary>
        /// <param name="activationMode">How the app was launched.</param>
        /// <param name="openedFile">The file the app was opened to (or null).</param>
        /// <param name="passwordGenViewModel">The ViewModel for the password generation flyout.</param>
        /// <param name="helpViewModel">The ViewModel for the help flyout.</param>
        /// <param name="appSettingsViewModel">The ViewModel for the settings flyout.</param>
        /// <param name="clipboardViewModel">a ViewModel over a clipboard clear timer.</param>
        /// <param name="taskNotificationService">A service used to control the UI for blocking operations.</param>
        /// <param name="clipboardService">A service for accessing the clipboard.</param>
        /// <param name="settingsService">A service for accessing app settings.</param>
        /// <param name="idleTimer">A timer used for computing idle timer.</param>
        public RootViewModel(
            ActivationMode activationMode,
            ITestableFile openedFile,
            IPasswordGenViewModel passwordGenViewModel,
            IHelpViewModel helpViewModel,
            IAppSettingsViewModel appSettingsViewModel,
            IClipboardClearTimerViewModel clipboardViewModel,
            ITaskNotificationService taskNotificationService,
            ISensitiveClipboardService clipboardService,
            IAppSettingsService settingsService
            )
        {
            ActivationMode = activationMode;
            CandidateFile  = openedFile;

            PasswordGenViewModel = passwordGenViewModel ?? throw new ArgumentNullException(nameof(passwordGenViewModel));
            HelpViewModel        = helpViewModel ?? throw new ArgumentNullException(nameof(helpViewModel));
            AppSettingsViewModel = appSettingsViewModel ?? throw new ArgumentNullException(nameof(appSettingsViewModel));

            TaskNotificationService = taskNotificationService ?? throw new ArgumentNullException(nameof(taskNotificationService));

            ClipboardClearViewModel = clipboardViewModel ?? throw new ArgumentNullException(nameof(clipboardViewModel));
            this.clipboardService   = clipboardService ?? throw new ArgumentNullException(nameof(clipboardService));

            this.settingsService = settingsService;
        }
        /// <summary>
        /// Opens the specified folder with the specified file highlighted/selected.
        /// </summary>
        /// <param name="folder">The folder to launch.</param>
        /// <param name="fileToSelect">The file to select in the launched folder.</param>
        /// <returns>A task that resolves when the operation is completed.</returns>
        public async Task LaunchFolderWithSelectionAsync(IStorageFolder folder, ITestableFile fileToSelect)
        {
            FolderLauncherOptions options = new FolderLauncherOptions();

            options.ItemsToSelect.Add(fileToSelect.AsIStorageItem);
            await Launcher.LaunchFolderAsync(folder, options);
        }
Beispiel #3
0
        /// <summary>
        /// Attempts to decrypt a document using the provided information.
        /// </summary>
        /// <param name="stream">A stream representing the entire file (including header)</param>
        /// <param name="password">The password to the document (may be empty but not null)</param>
        /// <param name="keyfile">The keyfile for the document (may be null)</param>
        /// <param name="token">A token allowing the task to be cancelled.</param>
        /// <returns>A task representing the result of the decryption.</returns>
        public async Task <KdbxDecryptionResult> DecryptFileAsync(
            IRandomAccessStream stream,
            string password,
            ITestableFile keyfile,
            CancellationToken token
            )
        {
            DebugHelper.Assert(password != null);
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            IList <ISecurityToken> tokenList = new List <ISecurityToken>();

            if (!String.IsNullOrEmpty(password))
            {
                tokenList.Add(new MasterPassword(password));
            }

            if (keyfile != null)
            {
                tokenList.Add(new KeyFile(keyfile));
            }

            IBuffer raw32 = await KeyHelper.GetRawKey(tokenList);

            return(await DecryptFile(stream, raw32, token));
        }
Beispiel #4
0
        /// <summary>
        /// Activates the dashboard ViewModel by resolving each stored file
        /// to update the descriptors and remove bad bookmarks.
        /// </summary>
        /// <returns>A Task representing the activation.</returns>
        public override async Task ActivateAsync()
        {
            await base.ActivateAsync();

            List <StoredFileDescriptor> badDescriptors = new List <StoredFileDescriptor>();

            foreach (StoredFileDescriptor descriptor in StoredFiles)
            {
                WireDescriptorEvents(descriptor);
                ITestableFile file = await GetFileAsync(descriptor);

                if (file != null)
                {
                    descriptor.IsAppOwned = await this.proxyProvider.PathIsInScopeAsync(file.AsIStorageItem2);
                }
                else
                {
                    badDescriptors.Add(descriptor);
                }
            }

            Task[] forgetTasks = new Task[badDescriptors.Count];
            for (int i = 0; i < forgetTasks.Length; i++)
            {
                StoredFileDescriptor descriptor = badDescriptors[i];
                forgetTasks[i] = descriptor.ForgetCommand.ExecuteAsync(null);
            }

            await Task.WhenAll(forgetTasks);
        }
Beispiel #5
0
        /// <summary>
        /// Asynchronously removes a credential. Completes silently if credential is not found.
        /// </summary>
        /// <param name="database">The database to delete data for.</param>
        /// <returns>A task that finishes when the database is removed.</returns>
        public Task DeleteAsync(ITestableFile database)
        {
            if (database == null)
            {
                throw new ArgumentNullException(nameof(database));
            }

            return(DeleteAsync(GetUserNameToken(database)));
        }
Beispiel #6
0
        /// <summary>
        /// Assembles a <see cref="StorageFileDatabaseCandidate"/> that wraps
        /// <paramref name="file"/> and initializes the cached file for reading.
        /// </summary>
        /// <param name="file">The file to wrap.</param>
        /// <returns>An initialized <see cref="StorageFileDatabaseCandidate"/>.</returns>
        public async Task <IDatabaseCandidate> AssembleAsync(ITestableFile file)
        {
            bool isAppOwned = await this.proxyProvider.PathIsInScopeAsync(file.AsIStorageItem2).ConfigureAwait(false);

            StorageFileDatabaseCandidate candidate = new StorageFileDatabaseCandidate(file, isAppOwned);
            await candidate.GenerateReadOnlyCachedCopyAsync();

            return(candidate);
        }
Beispiel #7
0
        /// <summary>
        /// Asynchronously stores the key for a database in a secure location.
        /// The existing credential is overwritten.
        /// </summary>
        /// <param name="database">Data identifying the key for future retrieval.</param>
        /// <param name="key">The key to store.</param>
        /// <returns>A task representing whether the storage is successful.</returns>
        public Task <bool> TryStoreRawKeyAsync(ITestableFile database, IBuffer key)
        {
            if (database == null)
            {
                throw new ArgumentNullException(nameof(database));
            }

            return(TryStoreRawKeyAsync(GetUserNameToken(database), key));
        }
Beispiel #8
0
        /// <summary>
        /// Asynchronously fetches data representing the raw
        /// aggregate key for a database.
        /// </summary>
        /// <param name="database">Data identifying the key to fetch.</param>
        /// <returns>A task representing the key data, which will be null if no
        /// stored credential exists.</returns>
        public Task <IBuffer> GetRawKeyAsync(ITestableFile database)
        {
            if (database == null)
            {
                throw new ArgumentNullException(nameof(database));
            }

            return(GetRawKeyAsync(GetUserNameToken(database)));
        }
Beispiel #9
0
        /// <summary>
        /// Helper to generate a new, cached candidate file using the underlying proxy provider.
        /// </summary>
        /// <returns>A cached, local database candidate.</returns>
        private async Task <IDatabaseCandidate> GetCachedCandidateAsync()
        {
            ITestableFile newCandidateFile = await this.proxyProvider.CreateWritableProxyAsync(CandidateFile.File);

            IDatabaseCandidate newCandidate = await this.candidateFactory.AssembleAsync(newCandidateFile);

            DebugHelper.Assert(newCandidateFile != CandidateFile);

            return(newCandidate);
        }
 /// <summary>
 /// Adds a file to the list of files provided by subscribers. Null values are ignored.
 /// </summary>
 /// <param name="file">The file to add and eventually return to the event raiser.</param>
 public void AddFile(ITestableFile file)
 {
     if (file != null)
     {
         lock (this.providedFiles)
         {
             this.providedFiles.Add(file);
         }
     }
 }
Beispiel #11
0
        public async Task TestProxyInScope()
        {
            StorageFile existingFile = await this.rootFolder.CreateFileAsync("tmp.txt", CreationCollisionOption.ReplaceExisting);

            ITestableFile testFile = existingFile.AsWrapper();

            Assert.IsTrue(await this.provider.PathIsInScopeAsync(existingFile));
            ITestableFile proxy = await this.provider.CreateWritableProxyAsync(testFile);

            Assert.AreSame(testFile, proxy);
        }
        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);
        }
Beispiel #13
0
 /// <summary>
 /// Initializes dependencies.
 /// </summary>
 /// <param name="document">The document whose master key may be updated.</param>
 /// <param name="databaseFile">The underlying file to persist changes to.</param>
 /// <param name="credentialProvider">A provider that manages changes to credentials for the database.</param>
 /// <param name="fileService">The service used to pick a new keyfile.</param>
 public MasterKeyChangeViewModel(
     KdbxDocument document,
     ITestableFile databaseFile,
     IDatabaseCredentialProvider credentialProvider,
     IFileAccessService fileService
     ) : base(fileService)
 {
     this.document           = document ?? throw new ArgumentNullException(nameof(document));
     this.databaseFile       = databaseFile;
     this.credentialProvider = credentialProvider ?? throw new ArgumentNullException(nameof(credentialProvider));
 }
Beispiel #14
0
 /// <summary>
 /// Navigates to the proper view for opening a database file.
 /// </summary>
 /// <param name="file">The file being opened.</param>
 /// <param name="isSample">Whether we are unlocking a sample file.</param>
 public async void OpenFile(ITestableFile file, bool isSample = false)
 {
     DebugHelper.Trace("Navigating RootView to Database Unlocker...");
     this.contentFrame.Navigate(typeof(DatabaseUnlockView),
                                new NavigationParameter(
                                    new {
         file         = await DatabaseCandidateFactory.AssembleAsync(file),
         isSampleFile = isSample
     }
                                    )
                                );
 }
Beispiel #15
0
        public string Add(ITestableFile file, string metadata)
        {
            string token = Guid.NewGuid().ToString();

            this.backingData[token] = file;
            this.publicData[token]  = new AccessListEntry
            {
                Token    = token,
                Metadata = metadata
            };
            return(token);
        }
Beispiel #16
0
        public async Task TestProxy()
        {
            ITestableFile existingFile = await Utils.GetDatabaseByName("StructureTesting.kdbx");

            Assert.IsFalse(await this.provider.PathIsInScopeAsync(existingFile.AsIStorageItem2), "Initial file should be out of scope");

            ITestableFile proxy = await this.provider.CreateWritableProxyAsync(existingFile);

            Assert.AreNotSame(existingFile, proxy, "Proxy and original file should not be the same object");
            Assert.AreNotEqual(existingFile.AsIStorageFile, proxy.AsIStorageFile, "Proxy and original file should not be equal");

            Assert.IsTrue(await this.provider.PathIsInScopeAsync(proxy.AsIStorageItem2), "Proxy should be in the right place");
            Assert.IsTrue(await proxy.CheckWritableAsync(), "Proxy should be writable");
        }
        /// <summary>
        /// Constructs a database candidate from the specified IStorageFile.
        /// </summary>
        /// <param name="candidate">The file representing the database candidate.</param>
        /// <param name="isAppOwned">Whether this file is controlled by the app.</param>
        public StorageFileDatabaseCandidate(ITestableFile candidate, bool isAppOwned)
        {
            this.candidate  = candidate ?? throw new ArgumentNullException(nameof(candidate));
            this.isAppOwned = isAppOwned;
            LastModified    = null;
            Size            = 0;

            // XXX:
            // This is horrible, obviously. It's a hack and it isn't localized.
            // That's because it should be temporary, until Microsoft fixes OneDrive.
            CannotRememberText = null;
            if (this.candidate.AsIStorageItem.Path.Contains(OneDrivePathFragment))
            {
                CannotRememberText =
                    "Disabled for OneDrive on phone - it currently does not provide apps with persistent access to your cloud files";
            }
        }
Beispiel #18
0
        /// <summary>
        /// Asynchronously clears and adds back <see cref="StoredFileDescriptor"/> to updated
        /// <see cref="StoredFiles"/>.
        /// </summary>
        /// <returns></returns>
        private async Task ResyncFiles()
        {
            ClearAllFiles();
            foreach (ITestableFile file in await this.proxyProvider.GetKnownProxiesAsync()
                     .ConfigureAwait(false)
                     )
            {
                var allStoredFiles = this.accessList.Entries
                                     .Select(e => new { Entry = e, FileTask = this.accessList.GetFileAsync(e.Token) });

                AccessListEntry?entry = null;
                foreach (var stored in allStoredFiles)
                {
                    ITestableFile storedFile = await stored.FileTask.ConfigureAwait(false);

                    if (storedFile.AsIStorageItem.Path == file.AsIStorageItem.Path)
                    {
                        entry = stored.Entry;
                    }
                }

                // If we couldn't find the file in the access list, add it.
                // This asserts because these lists shouldn't be out of sync in the first place.
                if (!entry.HasValue)
                {
                    string metadata = file.AsIStorageItem.Name;
                    entry = new AccessListEntry
                    {
                        Metadata = metadata,
                        Token    = this.accessList.Add(file, metadata)
                    };

                    DebugHelper.Assert(false);
                }

                StoredFileDescriptor descriptor = new StoredFileDescriptor(
                    entry.Value
                    );
                descriptor.IsAppOwned = await this.proxyProvider.PathIsInScopeAsync(file.AsIStorageItem2);

                // Wire events
                WireDescriptorEvents(descriptor);
                AddFile(descriptor);
            }
        }
Beispiel #19
0
        /// <summary>
        /// Attempts to load a recent database from a StoredFileDescriptor.
        /// </summary>
        /// <param name="descriptor">The descriptor to load.</param>
        private async Task AttemptToLoadRecentDatabase(StoredFileDescriptor descriptor)
        {
            if (descriptor == null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            ITestableFile storedFile = await ViewModel.GetFileAsync(descriptor);

            if (storedFile == null)
            {
                Debug.WriteLine("Warning: Could not fetch StorageFile. Forgetting descriptor.");
                descriptor.ForgetCommand.Execute(null);
            }
            else
            {
                Debug.WriteLine("Retrieved StorageFile from descriptor.");
                NavigateToOpenedFile(await DatabaseCandidateFactory.AssembleAsync(storedFile));
            }
        }
        /// <summary>
        /// Helper to prompt the user - if necessary - when updating a cached file.
        /// If there is a name mismatch or the replacement is older than the original,
        /// the user is prompted.
        /// </summary>
        /// <param name="original"></param>
        /// <param name="replacement"></param>
        /// <returns>Whether to proceed with the update.</returns>
        private async Task <bool> CheckShouldProceedWithUpdateAsync(ITestableFile original, ITestableFile replacement)
        {
            DateTimeOffset originalModified = await original.GetLastModifiedAsync().ConfigureAwait(false);

            DateTimeOffset replacementModified = await replacement.GetLastModifiedAsync().ConfigureAwait(false);

            bool relativeTimeIsSafe = replacementModified >= originalModified;
            bool nameIsSafe         = original.Name == replacement.Name;

            if (relativeTimeIsSafe && nameIsSafe)
            {
                return(true);
            }

            return(await this.updatePrompter.PromptYesNoAsync(
                       replacement.Name,
                       originalModified,
                       replacementModified
                       ));
        }
Beispiel #21
0
        /// <summary>
        /// Assembles a writer with the given security tokens.
        /// </summary>
        /// <param name="password"></param>
        /// <param name="keyFile"></param>
        /// <param name="cipher">The algorithm to use for encrypting the database.</param>
        /// <param name="kdfParams">Information about how to transform the user's key.</param>
        /// <returns></returns>
        public IKdbxWriter Assemble(string password, ITestableFile keyFile, EncryptionAlgorithm cipher, KdfParameters kdfParams)
        {
            IList <ISecurityToken> tokens = new List <ISecurityToken>();

            if (!String.IsNullOrEmpty(password))
            {
                tokens.Add(new MasterPassword(password));
            }

            if (keyFile != null)
            {
                tokens.Add(new KeyFile(keyFile));
            }

            return(new KdbxWriter(
                       tokens,
                       cipher,
                       RngAlgorithm.Salsa20,
                       CompressionAlgorithm.GZip,
                       kdfParams
                       ));
        }
Beispiel #22
0
        /// <summary>
        /// Initializes the instance.
        /// </summary>
        /// <param name="syncContext">Context to use for marshalling to the UI thread.</param>
        /// <param name="timerFactory">Used to create a timer.</param>
        /// <param name="file">The file on disk represented by this database.</param>
        /// <param name="fileIsSample">Whether this file is a sample file.</param>
        /// <param name="document">The decrypted database.</param>
        /// <param name="resourceProvider">A IResourceProvider for the View.</param>
        /// <param name="rng">A random number generator used to protect strings.</param>
        /// <param name="navigationViewModel">A ViewModel representing the navigation of the database.</param>
        /// <param name="masterKeyViewModel">A ViewModel that allows configuring the database's master key.</param>
        /// <param name="persistenceService">A service used to save the database.</param>
        /// <param name="identityService">A service used to authenticate the user.</param>
        /// <param name="credentialStorage">A service used to update saved credentials.</param>
        /// <param name="settingsService">A service used to access app settings.</param>
        /// <param name="clipboardService">A service used to access the clipboard for credentials.</param>
        public DatabaseParentViewModel(
            ISyncContext syncContext,
            ITimerFactory timerFactory,
            ITestableFile file,
            bool fileIsSample,
            KdbxDocument document,
            IResourceProvider resourceProvider,
            IRandomNumberGenerator rng,
            IDatabaseNavigationViewModel navigationViewModel,
            IMasterKeyViewModel masterKeyViewModel,
            IDatabasePersistenceService persistenceService,
            IIdentityVerificationService identityService,
            ICredentialStorageProvider credentialStorage,
            IAppSettingsService settingsService,
            ISensitiveClipboardService clipboardService
            ) : base(document, persistenceService)
        {
            if (timerFactory == null)
            {
                throw new ArgumentNullException(nameof(timerFactory));
            }

            this.syncContext = syncContext ?? throw new ArgumentNullException(nameof(syncContext));
            this.idleTimer   = timerFactory.Assemble(TimeSpan.FromSeconds(1));

            this.file             = file ?? throw new ArgumentNullException(nameof(file));
            this.fileIsSample     = fileIsSample;
            this.document         = document ?? throw new ArgumentNullException(nameof(document));
            this.resourceProvider = resourceProvider ?? throw new ArgumentNullException(nameof(resourceProvider));
            this.rng = rng ?? throw new ArgumentNullException(nameof(rng));
            this.navigationViewModel = navigationViewModel ?? throw new ArgumentNullException(nameof(navigationViewModel));
            this.settingsViewModel   = new DatabaseSettingsViewModel(PersistenceService.SettingsProvider);
            this.masterKeyViewModel  = masterKeyViewModel ?? throw new ArgumentNullException(nameof(masterKeyViewModel));
            this.identityService     = identityService ?? throw new ArgumentNullException(nameof(identityService));
            this.credentialProvider  = credentialStorage ?? throw new ArgumentNullException(nameof(credentialStorage));
            this.settingsService     = settingsService ?? throw new ArgumentNullException(nameof(settingsService));
            this.clipboardService    = clipboardService ?? throw new ArgumentNullException(nameof(clipboardService));
        }
Beispiel #23
0
        /// <summary>
        /// Returns a writable copy of the specified file in the root folder.
        /// If the original file already meets these criteria, it is returned as-is.
        /// </summary>
        /// <param name="original">The file to generate a writable proxy for in the expected location.</param>
        /// <returns>A copy of <paramref name="original"/> (if necessary) that is in the right spot and is writable.</returns>
        public async Task <ITestableFile> CreateWritableProxyAsync(ITestableFile original)
        {
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            string originalPath = original.Path;

            if (await PathIsInScopeAsync(original.AsIStorageItem2).ConfigureAwait(false))
            {
                if (await original.AsIStorageFile.CheckWritableAsync().ConfigureAwait(false))
                {
                    DebugHelper.Trace($"Existing file {originalPath} does not need to be proxied");
                    return(original);
                }
                else
                {
                    DebugHelper.Trace($"Existing file {originalPath} could not be used as a proxy because it's not writable");
                }
            }
            else
            {
                DebugHelper.Trace($"Existing file {originalPath} could not be used as a proxy because it's in the wrong path");
            }

            StorageFile proxy = await original.AsIStorageFile.CopyAsync(ProxyFolder, original.AsIStorageItem.Name, NameCollisionOption.GenerateUniqueName)
                                .AsTask().ConfigureAwait(false);

            await proxy.ClearFileAttributesAsync(FileAttributes.ReadOnly).ConfigureAwait(false);

            DebugHelper.Assert(await proxy.CheckWritableAsync());

            DebugHelper.Trace($"Existing file {originalPath} proxied as {proxy.Path}");

            return(proxy.AsWrapper());
        }
Beispiel #24
0
        /// <summary>
        /// Asynchronously exports the specified file to the specified location.
        /// </summary>
        /// <param name="file">The file to export.</param>
        /// <param name="targetLocation">The location to export to.</param>
        /// <returns>A task that resolves to the exported file location.</returns>
        public async Task <ITestableFile> ExportAsync(StoredFileDescriptor file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            // If this is not a valid descriptor it should be forgotten
            ITestableFile fileToCopy = await this.accessList.GetFileAsync(file.Token).ConfigureAwait(false);

            if (fileToCopy == null)
            {
                await file.ForgetCommand.ExecuteAsync(null).ConfigureAwait(false);

                return(null);
            }

            ITestableFile savedFile = await this.fileService.PickFileForSaveAsync(file.Metadata)
                                      .ConfigureAwait(false);

            if (savedFile != null)
            {
                try
                {
                    await fileToCopy.AsIStorageFile.CopyAndReplaceAsync(savedFile.AsIStorageFile)
                    .AsTask().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    DebugHelper.Assert(false, "Should not have problems exporting files");
                    DebugHelper.Trace($"Failed to export: {ex}");
                    return(null);
                }
            }

            return(savedFile);
        }
        /// <summary>
        /// Intended to be registered as a handler for <see cref="StoredFileDescriptor.UpdateRequested"/>.
        /// </summary>
        /// <param name="sender">The descriptor being updated.</param>
        /// <param name="args">EventArgs used to request the file to update with.</param>
        private async void UpdateRequestedHandler(StoredFileDescriptor sender, RequestUpdateDescriptorEventArgs args)
        {
            if (!sender.IsAppOwned)
            {
                DebugHelper.Assert(false, "This should be impossible");
                return;
            }

            ITestableFile file = await this.fileService.PickFileForOpenAsync().ConfigureAwait(false);

            if (file != null)
            {
                DebugHelper.Trace($"Updating cached file");
                ITestableFile storedFile = await GetFileAsync(sender).ConfigureAwait(false);

                if (await CheckShouldProceedWithUpdateAsync(storedFile, file).ConfigureAwait(false))
                {
                    await file.AsIStorageFile.CopyAndReplaceAsync(storedFile.AsIStorageFile)
                    .AsTask().ConfigureAwait(false);

                    await storedFile.ClearReadOnlyFlag().ConfigureAwait(false);
                }
            }
        }
Beispiel #26
0
            /// <summary>
            /// Initializes the class.
            /// </summary>
            /// <param name="databaseName">Name of the document file this instance represents.</param>
            /// <param name="password">Password ot use for document decryption.</param>
            /// <param name="keyfileName">File name of the keyfile to use for decryption.</param>
            /// <param name="isSample">Whether this represents a PassKeep sample document.</param>
            public static async Task <DatabaseInfo> Create(string databaseName, string password = "", string keyfileName = null, bool isSample = false)
            {
                if (String.IsNullOrEmpty(databaseName))
                {
                    throw new ArgumentNullException(nameof(databaseName));
                }

                ITestableFile database = await GetDatabaseByName(databaseName);

                ITestableFile keyfile = null;

                if (!String.IsNullOrEmpty(keyfileName))
                {
                    keyfile = (await Utils.GetPackagedFile("Keys", keyfileName)).AsWrapper();
                }

                IList <ISecurityToken> tokens = new List <ISecurityToken>();

                if (!string.IsNullOrEmpty(password))
                {
                    tokens.Add(new MasterPassword(password));
                }
                if (keyfile != null)
                {
                    tokens.Add(new KeyFile(keyfile));
                }

                return(new DatabaseInfo
                {
                    Database = database,
                    Password = password,
                    RawKey = await KeyHelper.GetRawKey(tokens),
                    Keyfile = keyfile,
                    IsSample = isSample
                });
            }
Beispiel #27
0
        public DatabaseCreationViewModel(
            ISyncContext syncContext,
            ITestableFile file,
            IDatabaseSettingsViewModelFactory settingsVmFactory,
            IMasterKeyChangeViewModelFactory keyChangeVmFactory,
            IKdbxWriterFactory writerFactory,
            IDatabaseAccessList futureAccessList,
            ITaskNotificationService taskNotificationService,
            IDatabaseCandidateFactory candidateFactory,
            IFileAccessService fileAccessService
            ) : base(fileAccessService)
        {
            this.syncContext             = syncContext ?? throw new ArgumentNullException(nameof(syncContext));
            File                         = file ?? throw new ArgumentNullException(nameof(file));
            Settings                     = settingsVmFactory?.Assemble() ?? throw new ArgumentNullException(nameof(settingsVmFactory));
            this.keyChangeVmFactory      = keyChangeVmFactory ?? throw new ArgumentNullException(nameof(keyChangeVmFactory));
            this.writerFactory           = writerFactory ?? throw new ArgumentNullException(nameof(writerFactory));
            this.futureAccessList        = futureAccessList ?? throw new ArgumentNullException(nameof(futureAccessList));
            this.taskNotificationService = taskNotificationService ?? throw new ArgumentNullException(nameof(taskNotificationService));
            this.candidateFactory        = candidateFactory ?? throw new ArgumentNullException(nameof(candidateFactory));

            CreateEmpty = true;
            Remember    = true;
        }
Beispiel #28
0
 /// <summary>
 /// Constructs the message.
 /// </summary>
 public DatabaseCandidateMessage(ITestableFile file, bool isSample)
 {
     File     = file;
     IsSample = isSample;
 }
Beispiel #29
0
        protected override async Task HandleCredentialsAsync(string confirmedPassword, ITestableFile chosenKeyFile)
        {
            LogCurrentFunction();

            IList <ISecurityToken> tokens = new List <ISecurityToken>();

            if (!String.IsNullOrEmpty(confirmedPassword))
            {
                tokens.Add(new MasterPassword(confirmedPassword));
            }

            if (chosenKeyFile != null)
            {
                tokens.Add(new KeyFile(chosenKeyFile));
            }

            await this.credentialProvider.UpdateCredentialsAsync(this.document, this.databaseFile, tokens).ConfigureAwait(false);

            LogEventWithContext("UpdateComplete");
        }
Beispiel #30
0
 /// <summary>
 /// Adds the specified file to the access list.
 /// </summary>
 /// <param name="file">The file to add.</param>
 /// <param name="metadata">The metadata to associate with the file.</param>
 /// <returns>A token used for future reference.</returns>
 public string Add(ITestableFile file, string metadata)
 {
     return(this.accessList.Add(file.AsIStorageItem, metadata));
 }