Ejemplo n.º 1
0
        public async Task <KeyManager> GenerateWalletAsync(string walletName)
        {
            var selectedDevice = SelectedDevice;

            try
            {
                if (selectedDevice?.Fingerprint is null)
                {
                    throw new Exception("Cannot be null.");
                }

                await StopDetectionAsync();

                var fingerPrint = (HDFingerprint)selectedDevice.Fingerprint;
                using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3));
                var extPubKey = await Client.GetXpubAsync(
                    selectedDevice.Model,
                    selectedDevice.Path,
                    KeyManager.DefaultAccountKeyPath,
                    cts.Token).ConfigureAwait(false);

                var path = WalletManager.WalletDirectories.GetWalletFilePaths(walletName).walletFilePath;

                return(KeyManager.CreateNewHardwareWalletWatchOnly(fingerPrint, extPubKey, path));
            }
            catch (Exception)
            {
                StartDetection();
                throw;
            }
        }
        public static async Task <KeyManager> GenerateWalletAsync(HwiEnumerateEntry device, string walletFilePath, Network network, CancellationToken cancelToken)
        {
            if (device.Fingerprint is null)
            {
                throw new Exception("Fingerprint cannot be null.");
            }

            var client      = new HwiClient(network);
            var fingerPrint = (HDFingerprint)device.Fingerprint;

            using var cts    = new CancellationTokenSource(TimeSpan.FromMinutes(3));
            using var genCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancelToken);

            var extPubKey = await client.GetXpubAsync(
                device.Model,
                device.Path,
                KeyManager.GetAccountKeyPath(network),
                genCts.Token).ConfigureAwait(false);

            return(KeyManager.CreateNewHardwareWalletWatchOnly(fingerPrint, extPubKey, network, walletFilePath));
        }
Ejemplo n.º 3
0
    private static KeyManager GetKeyManagerByColdcardJson(WalletManager manager, JObject jsonWallet, string walletFullPath)
    {
        var xpubString = jsonWallet["ExtPubKey"]?.ToString()
                         ?? throw new ArgumentNullException($"Can't get KeyManager, ExtPubKey was null.");

        var mfpString = jsonWallet["MasterFingerprint"]?.ToString()
                        ?? throw new ArgumentNullException($"Can't get KeyManager, MasterFingerprint was null.");

        // 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 = jsonWallet["ColdCardFirmwareVersion"]?.ToString();
        var reverseByteOrder      = false;

        if (coldCardVersionString is null)
        {
            reverseByteOrder = true;
        }
        else
        {
            Version coldCardVersion = new(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);

        if (manager.WalletExists(mfp))
        {
            throw new InvalidOperationException(WalletExistsErrorMessage);
        }

        ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);

        return(KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, manager.Network, walletFullPath));
    }
Ejemplo n.º 4
0
        public LoadWalletViewModel(WalletManagerViewModel owner, LoadWalletType loadWalletType)
            : base(loadWalletType == LoadWalletType.Password ? "Test Password" : (loadWalletType == LoadWalletType.Desktop ? "Load Wallet" : "Hardware Wallet"))
        {
            Owner          = owner;
            Password       = "";
            LoadWalletType = loadWalletType;
            Wallets        = new ObservableCollection <LoadWalletEntry>();
            WalletLock     = new object();

            this.WhenAnyValue(x => x.SelectedWallet)
            .Subscribe(selectedWallet => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsWalletOpened)
            .Subscribe(isWalletOpened => TrySetWalletStates());

            this.WhenAnyValue(x => x.IsBusy)
            .Subscribe(x => TrySetWalletStates());

            this.WhenAnyValue(x => x.Password).Subscribe(async x =>
            {
                try
                {
                    if (x.NotNullAndNotEmpty())
                    {
                        char lastChar = x.Last();
                        if (lastChar == '\r' || lastChar == '\n')                         // If the last character is cr or lf then act like it'd be a sign to do the job.
                        {
                            Password = x.TrimEnd('\r', '\n');
                            await LoadKeyManagerAsync(requirePassword: true, isHardwareWallet: false);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogTrace(ex);
                }
            });

            LoadCommand           = ReactiveCommand.CreateFromTask(async() => await LoadWalletAsync(), this.WhenAnyValue(x => x.CanLoadWallet));
            TestPasswordCommand   = ReactiveCommand.CreateFromTask(async() => await LoadKeyManagerAsync(requirePassword: true, isHardwareWallet: false), this.WhenAnyValue(x => x.CanTestPassword));
            OpenFolderCommand     = ReactiveCommand.Create(OpenWalletsFolder);
            ImportColdcardCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                try
                {
                    var ofd = new OpenFileDialog
                    {
                        AllowMultiple = false,
                        Title         = "Import Coldcard"
                    };

                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                    }

                    var selected = await ofd.ShowAsync(Application.Current.MainWindow, 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 fingerpring 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;
                            }
                        }
                        HDFingerprint mfp   = NBitcoinHelpers.BetterParseHDFingerprint(mfpString, reverseByteOrder: reverseByteOrder);
                        ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);
                        Logger.LogInfo <LoadWalletViewModel>("Creating new wallet file.");
                        var walletName     = Global.GetNextHardwareWalletName(customPrefix: "Coldcard");
                        var walletFullPath = Global.GetWalletFullPath(walletName);
                        KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath);
                        owner.SelectLoadWallet();
                    }
                }
                catch (Exception ex)
                {
                    SetWarningMessage(ex.ToTypeMessageString());
                    Logger.LogError <LoadWalletViewModel>(ex);
                }
            }, outputScheduler: RxApp.MainThreadScheduler);

            OpenBrowserCommand = ReactiveCommand.Create <string>(x =>
            {
                IoHelpers.OpenBrowser(x);
            });

            OpenBrowserCommand.ThrownExceptions.Subscribe(Logger.LogWarning <LoadWalletViewModel>);
            LoadCommand.ThrownExceptions.Subscribe(Logger.LogWarning <LoadWalletViewModel>);
            TestPasswordCommand.ThrownExceptions.Subscribe(Logger.LogWarning <LoadWalletViewModel>);
            OpenFolderCommand.ThrownExceptions.Subscribe(Logger.LogWarning <LoadWalletViewModel>);
            ImportColdcardCommand.ThrownExceptions.Subscribe(Logger.LogWarning <LoadWalletViewModel>);

            SetLoadButtonText();

            IsHwWalletSearchTextVisible = LoadWalletType == LoadWalletType.Hardware;
        }
Ejemplo n.º 5
0
        public LoadWalletViewModel(WalletManagerViewModel owner, LoadWalletType loadWalletType)
            : base(loadWalletType == LoadWalletType.Password ? "Test Password" : (loadWalletType == LoadWalletType.Desktop ? "Load Wallet" : "Hardware Wallet"))
        {
            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(async() => await LoadWalletAsync(), this.WhenAnyValue(x => x.CanLoadWallet));
            TestPasswordCommand   = ReactiveCommand.CreateFromTask(async() => await LoadKeyManagerAsync(requirePassword: true, isHardwareWallet: false), 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;
                        }
                    }
                    HDFingerprint mfp   = NBitcoinHelpers.BetterParseHDFingerprint(mfpString, reverseByteOrder: reverseByteOrder);
                    ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);
                    Logger.LogInfo("Creating a new wallet file.");
                    var walletName     = Global.GetNextHardwareWalletName(customPrefix: "Coldcard");
                    var walletFullPath = Global.GetWalletFullPath(walletName);
                    KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath);
                    owner.SelectLoadWallet();
                }
            });

            EnumerateHardwareWalletsCommand = ReactiveCommand.CreateFromTask(async() => await EnumerateHardwareWalletsAsync());

            OpenBrowserCommand = ReactiveCommand.Create <string>(x => IoHelpers.OpenBrowser(x));

            Observable.Merge(OpenBrowserCommand.ThrownExceptions)
            .Merge(LoadCommand.ThrownExceptions)
            .Merge(TestPasswordCommand.ThrownExceptions)
            .Merge(OpenFolderCommand.ThrownExceptions)
            .Merge(ImportColdcardCommand.ThrownExceptions)
            .Merge(EnumerateHardwareWalletsCommand.ThrownExceptions)
            .Subscribe(ex =>
            {
                NotificationHelpers.Error(ex.ToTypeMessageString());
                Logger.LogError(ex);
            });

            SetLoadButtonText();
        }
Ejemplo n.º 6
0
        public ConnectHardwareWalletViewModel(WalletManagerViewModel owner) : base("Hardware Wallet")
        {
            Global  = Locator.Current.GetService <Global>();
            Owner   = owner;
            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());

            this.WhenAnyValue(x => x.IsBusy)
            .Subscribe(_ => TrySetWalletStates());

            LoadCommand           = ReactiveCommand.CreateFromTask(LoadWalletAsync, this.WhenAnyValue(x => x.CanLoadWallet));
            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 is { } && 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();
                }
            });