/// <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); }
/// <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)); }
/// <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); }
/// <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))); }
/// <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); }
/// <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)); }
/// <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))); }
/// <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); } } }
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); }
/// <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)); }
/// <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 } ) ); }
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); }
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"; } }
/// <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); } }
/// <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 )); }
/// <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 )); }
/// <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)); }
/// <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()); }
/// <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); } } }
/// <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 }); }
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; }
/// <summary> /// Constructs the message. /// </summary> public DatabaseCandidateMessage(ITestableFile file, bool isSample) { File = file; IsSample = isSample; }
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"); }
/// <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)); }