private void DisplayWalletManager() { var walletManagerViewModel = new WalletManagerViewModel(); IoC.Get <IShell>().AddDocument(walletManagerViewModel); var isAnyDesktopWalletAvailable = Directory.Exists(Global.WalletsDir) && Directory.EnumerateFiles(Global.WalletsDir).Any(); if (isAnyDesktopWalletAvailable) { walletManagerViewModel.SelectLoadWallet(); } else { walletManagerViewModel.SelectGenerateWallet(); } }
private void RecoverWallet(WalletManagerViewModel owner) { WalletName = Guard.Correct(WalletName); MnemonicWords = Guard.Correct(MnemonicWords); Password = Guard.Correct(Password); // Do not let whitespaces to the beginning and to the end. string walletFilePath = WalletManager.WalletDirectories.GetWalletFilePaths(WalletName).walletFilePath; if (string.IsNullOrWhiteSpace(WalletName)) { NotificationHelpers.Error("Invalid wallet name."); } else if (File.Exists(walletFilePath)) { NotificationHelpers.Error("Wallet name is already taken."); } else if (string.IsNullOrWhiteSpace(MnemonicWords)) { NotificationHelpers.Error("Recovery Words were not supplied."); } else { var minGapLimit = int.Parse(MinGapLimit); var keyPath = KeyPath.Parse(AccountKeyPath); try { var mnemonic = new Mnemonic(MnemonicWords); var km = KeyManager.Recover(mnemonic, Password, filePath: null, keyPath, minGapLimit); km.SetNetwork(Global.Network); km.SetFilePath(walletFilePath); WalletManager.AddWallet(km); NotificationHelpers.Success("Wallet was recovered."); owner.SelectLoadWallet(km); } catch (Exception ex) { Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); } } }
public RecoverWalletViewModel(WalletManagerViewModel owner) : base("Recover Wallet") { Global = Locator.Current.GetService <Global>(); MnemonicWords = ""; RecoverCommand = ReactiveCommand.Create(() => { WalletName = Guard.Correct(WalletName); MnemonicWords = Guard.Correct(MnemonicWords); Password = Guard.Correct(Password); // Do not let whitespaces to the beginning and to the end. string walletFilePath = Global.WalletManager.WalletDirectories.GetWalletFilePaths(WalletName).walletFilePath; if (string.IsNullOrWhiteSpace(WalletName)) { NotificationHelpers.Error("Invalid wallet name."); } else if (File.Exists(walletFilePath)) { NotificationHelpers.Error("Wallet name is already taken."); } else if (string.IsNullOrWhiteSpace(MnemonicWords)) { NotificationHelpers.Error("Recovery Words were not supplied."); } else if (string.IsNullOrWhiteSpace(AccountKeyPath)) { NotificationHelpers.Error("The account key path is not valid."); } else if (MinGapLimit < KeyManager.AbsoluteMinGapLimit) { NotificationHelpers.Error($"Min Gap Limit cannot be smaller than {KeyManager.AbsoluteMinGapLimit}."); } else if (MinGapLimit > 1_000_000) { NotificationHelpers.Error($"Min Gap Limit cannot be larger than {1_000_000}."); } else if (!KeyPath.TryParse(AccountKeyPath, out KeyPath keyPath)) { NotificationHelpers.Error("The account key path is not a valid derivation path."); } else { try { var mnemonic = new Mnemonic(MnemonicWords); var km = KeyManager.Recover(mnemonic, Password, filePath: null, keyPath, MinGapLimit); km.SetNetwork(Global.Network); km.SetFilePath(walletFilePath); km.ToFile(); NotificationHelpers.Success("Wallet was recovered."); owner.SelectLoadWallet(); } catch (Exception ex) { Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); } } }); this.WhenAnyValue(x => x.MnemonicWords).Subscribe(UpdateSuggestions); _suggestions = new ObservableCollection <SuggestionViewModel>(); RecoverCommand.ThrownExceptions .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => Logger.LogError(ex)); }
public LoadWalletViewModel(WalletManagerViewModel owner, LoadWalletType loadWalletType) : base(loadWalletType == LoadWalletType.Password ? "Test Password" : loadWalletType == LoadWalletType.Desktop ? "Load Wallet" : "Hardware Wallet") { Global = Locator.Current.GetService <Global>(); Owner = owner; Password = ""; LoadWalletType = loadWalletType; Wallets = new ObservableCollection <LoadWalletEntry>(); IsHwWalletSearchTextVisible = false; this.WhenAnyValue(x => x.SelectedWallet) .Subscribe(_ => TrySetWalletStates()); this.WhenAnyValue(x => x.IsWalletOpened) .Subscribe(_ => TrySetWalletStates()); this.WhenAnyValue(x => x.IsBusy) .Subscribe(_ => TrySetWalletStates()); LoadCommand = ReactiveCommand.CreateFromTask(LoadWalletAsync, this.WhenAnyValue(x => x.CanLoadWallet)); TestPasswordCommand = ReactiveCommand.CreateFromTask(LoadKeyManagerAsync, this.WhenAnyValue(x => x.CanTestPassword)); OpenFolderCommand = ReactiveCommand.Create(OpenWalletsFolder); ImportColdcardCommand = ReactiveCommand.CreateFromTask(async() => { var ofd = new OpenFileDialog { AllowMultiple = false, Title = "Import Coldcard" }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { ofd.Directory = Path.Combine("/media", Environment.UserName); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { ofd.Directory = Environment.GetFolderPath(Environment.SpecialFolder.Personal); } var window = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow; var selected = await ofd.ShowAsync(window, fallBack: true); if (selected != null && selected.Any()) { var path = selected.First(); var jsonString = await File.ReadAllTextAsync(path); var json = JObject.Parse(jsonString); var xpubString = json["ExtPubKey"].ToString(); var mfpString = json["MasterFingerprint"].ToString(); // https://github.com/zkSNACKs/WalletWasabi/pull/1663#issuecomment-508073066 // Coldcard 2.1.0 improperly implemented Wasabi skeleton fingerprint at first, so we must reverse byte order. // The solution was to add a ColdCardFirmwareVersion json field from 2.1.1 and correct the one generated by 2.1.0. var coldCardVersionString = json["ColdCardFirmwareVersion"]?.ToString(); var reverseByteOrder = false; if (coldCardVersionString is null) { reverseByteOrder = true; } else { Version coldCardVersion = new Version(coldCardVersionString); if (coldCardVersion == new Version("2.1.0")) // Should never happen though. { reverseByteOrder = true; } } var bytes = ByteHelpers.FromHex(Guard.NotNullOrEmptyOrWhitespace(nameof(mfpString), mfpString, trim: true)); HDFingerprint mfp = reverseByteOrder ? new HDFingerprint(bytes.Reverse().ToArray()) : new HDFingerprint(bytes); ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString); Logger.LogInfo("Creating a new wallet file."); var walletName = Global.WalletManager.WalletDirectories.GetNextWalletName("Coldcard"); var walletFullPath = Global.WalletManager.WalletDirectories.GetWalletFilePaths(walletName).walletFilePath; KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath); owner.SelectLoadWallet(); } }); EnumerateHardwareWalletsCommand = ReactiveCommand.CreateFromTask(async() => await EnumerateIfHardwareWalletsAsync()); OpenBrowserCommand = ReactiveCommand.CreateFromTask <string>(IoHelpers.OpenBrowserAsync); Observable .Merge(OpenBrowserCommand.ThrownExceptions) .Merge(LoadCommand.ThrownExceptions) .Merge(TestPasswordCommand.ThrownExceptions) .Merge(OpenFolderCommand.ThrownExceptions) .Merge(ImportColdcardCommand.ThrownExceptions) .Merge(EnumerateHardwareWalletsCommand.ThrownExceptions) .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(ex => { Logger.LogError(ex); NotificationHelpers.Error(ex.ToUserFriendlyString()); }); SetLoadButtonText(); }