/// <summary> /// Creates a ViewModel wrapping a brand new KdbxGroup as a child of the specified parent group. /// </summary> /// <param name="resourceProvider">IResourceProvider for localizing strings.</param> /// <param name="navigationViewModel">A ViewModel used for tracking navigation history.</param> /// <param name="persistenceService">A service used for persisting the document.</param> /// <param name="clipboardService">A service used for accessing the clipboard.</param> /// <param name="settingsService">A service used for accessing app settings.</param> /// <param name="document">A KdbxDocument representing the database we are working on.</param> /// <param name="parentGroup">The IKeePassGroup to use as a parent for the new group.</param> /// <param name="rng">A random number generator used to protect strings in memory.</param> public EntryDetailsViewModel( IResourceProvider resourceProvider, IDatabaseNavigationViewModel navigationViewModel, IDatabasePersistenceService persistenceService, ISensitiveClipboardService clipboardService, IAppSettingsService settingsService, KdbxDocument document, IKeePassGroup parentGroup, IRandomNumberGenerator rng ) : this( resourceProvider, navigationViewModel, persistenceService, clipboardService, settingsService, document, new KdbxEntry(parentGroup, rng, document.Metadata), true, false, rng ) { if (parentGroup == null) { throw new ArgumentNullException(nameof(parentGroup)); } if (rng == null) { throw new ArgumentNullException(nameof(rng)); } }
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) { } }
/// <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> /// Initializes the ViewModel with the specified clipboard access. /// </summary> public PasswordGenViewModel(IPasswordGenerationService passwordService, ISensitiveClipboardService clipboardService) { ClipboardCopyCommand = new ActionCommand( async() => { clipboardService.CopyCredential( await passwordService.Generate(GetCurrentRecipe()), ClipboardOperationType.Password ); } ); }
/// <summary> /// Initializes the ViewModel. /// </summary> /// <param name="entry">The database entry to proxy.</param> /// <param name="isReadOnly">Whether the database can currently be edited.</param> /// <param name="clipboardService">Clipboard service used for requesting credential copies.</param> /// <param name="settingsService">Service used to check settings for launching URLs.</param> public DatabaseEntryViewModel( IKeePassEntry entry, bool isReadOnly, ISensitiveClipboardService clipboardService, IAppSettingsService settingsService ) : base(entry, isReadOnly) { if (entry == null) { throw new ArgumentNullException(nameof(entry)); } this.clipboardService = clipboardService ?? throw new ArgumentNullException(nameof(clipboardService)); this.settingsService = settingsService ?? throw new ArgumentNullException(nameof(settingsService)); this.entryUri = entry.GetLaunchableUri(); RequestCopyUsernameCommand = new ActionCommand( () => { this.clipboardService.CopyCredential(((IKeePassEntry)Node).UserName.ClearValue, ClipboardOperationType.UserName); } ); RequestCopyPasswordCommand = new ActionCommand( () => { this.clipboardService.CopyCredential(((IKeePassEntry)Node).Password.ClearValue, ClipboardOperationType.UserName); } ); RequestCopyUrlCommand = new ActionCommand( () => { this.clipboardService.CopyCredential(((IKeePassEntry)Node).ConstructUriString(), ClipboardOperationType.Other); } ); RequestLaunchUrlCommand = new ActionCommand( () => this.entryUri != null, async() => { if (this.settingsService.CopyPasswordOnUrlOpen) { RequestCopyPasswordCommand.Execute(null); } await Launcher.LaunchUriAsync(this.entryUri); } ); }
/// <summary> /// Creates a ViewModel wrapping an existing KdbxGroup. /// </summary> /// <param name="resourceProvider">IResourceProvider for localizing strings.</param> /// <param name="navigationViewModel">A ViewModel used for tracking navigation history.</param> /// <param name="persistenceService">A service used for persisting the document.</param> /// <param name="clipboardService">A service used for accessing the clipboard.</param> /// <param name="settingsService">A service used to access app settings.</param> /// <param name="document">A KdbxDocument representing the database we are working on.</param> /// <param name="entryToEdit">The entry being viewed.</param> /// <param name="isReadOnly">Whether to open the group in read-only mode.</param> /// <param name="rng">A random number generator used to protect strings in memory.</param> public EntryDetailsViewModel( IResourceProvider resourceProvider, IDatabaseNavigationViewModel navigationViewModel, IDatabasePersistenceService persistenceService, ISensitiveClipboardService clipboardService, IAppSettingsService settingsService, KdbxDocument document, IKeePassEntry entryToEdit, bool isReadOnly, IRandomNumberGenerator rng ) : this(resourceProvider, navigationViewModel, persistenceService, clipboardService, settingsService, document, entryToEdit, false, isReadOnly, rng) { if (entryToEdit == null) { throw new ArgumentNullException(nameof(entryToEdit)); } }
/// <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> /// Passes provided parameters to the base constructor and initializes commands. /// </summary> /// <param name="resourceProvider">IResourceProvider for localizing strings.</param> /// <param name="navigationViewModel"></param> /// <param name="persistenceService"></param> /// <param name="clipboardService"></param> /// <param name="settingsService"></param> /// <param name="document"></param> /// <param name="entry"></param> /// <param name="isNew"></param> /// <param name="isReadOnly"></param> /// <param name="rng"></param> private EntryDetailsViewModel( IResourceProvider resourceProvider, IDatabaseNavigationViewModel navigationViewModel, IDatabasePersistenceService persistenceService, ISensitiveClipboardService clipboardService, IAppSettingsService settingsService, KdbxDocument document, IKeePassEntry entry, bool isNew, bool isReadOnly, IRandomNumberGenerator rng ) : base(navigationViewModel, persistenceService, document, entry, isNew, isReadOnly) { this.resourceProvider = resourceProvider; this.clipboardService = clipboardService; this.settingsService = settingsService; this.rng = rng; this.copyFieldValueCommand = new TypedCommand <IProtectedString>( str => { clipboardService.CopyCredential(str.ClearValue, ClipboardOperationType.Other); } ); this.deleteFieldCommand = new TypedCommand <IProtectedString>( str => !IsReadOnly && PersistenceService.CanSave, str => { DebugHelper.Assert(!IsReadOnly); WorkingCopy.Fields.Remove(str); } ); this.editFieldCommand = new AsyncTypedCommand <IProtectedString>( str => PersistenceService.CanSave, async str => { IsReadOnly = false; await UpdateFieldEditorViewModel(new FieldEditorViewModel(str, this.resourceProvider)); } ); this.newFieldCommand = new AsyncActionCommand( () => PersistenceService.CanSave, async() => { IsReadOnly = false; await UpdateFieldEditorViewModel(new FieldEditorViewModel(this.rng, this.resourceProvider)); } ); this.commitFieldCommand = new AsyncActionCommand( () => FieldEditorViewModel?.CommitCommand.CanExecute(WorkingCopy) ?? false, async() => { FieldEditorViewModel.CommitCommand.Execute(WorkingCopy); await UpdateFieldEditorViewModel(null); } ); PropertyChanged += (s, e) => { if (e.PropertyName == nameof(IsReadOnly)) { ((TypedCommand <IProtectedString>)DeleteFieldCommand).RaiseCanExecuteChanged(); } else if (e.PropertyName == nameof(WorkingCopy)) { OnPropertyChanged(nameof(WorkingCopyViewModel)); } }; }
/// <summary> /// Starts the clipboard timer. /// </summary> /// <param name="sender">The ClipboardService.</param> /// <param name="args">The type of copy operation.</param> private void ClipboardService_CredentialCopied(ISensitiveClipboardService sender, ClipboardOperationType args) { ClipboardClearViewModel.StartTimer(args); }