Exemplo n.º 1
0
        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());
                }
            }
        }
Exemplo n.º 3
0
        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();
        }