예제 #1
0
        public async Task CanCreateStores()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var alice = s.RegisterNewUser();
                var store = s.CreateNewStore().storeName;
                s.AddDerivationScheme();
                s.Driver.AssertNoError();
                Assert.Contains(store, s.Driver.PageSource);
                var storeUrl = s.Driver.Url;
                s.ClickOnAllSideMenus();
                s.GoToInvoices();
                var invoiceId = s.CreateInvoice(store);
                s.AssertHappyMessage();
                s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
                var invoiceUrl = s.Driver.Url;

                //let's test archiving an invoice
                Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
                s.AssertHappyMessage();
                Assert.Contains("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                //check that it no longer appears in list
                s.GoToInvoices();
                Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
                //ok, let's unarchive and see that it shows again
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
                s.AssertHappyMessage();
                Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                s.GoToInvoices();
                Assert.Contains(invoiceId, s.Driver.PageSource);

                // When logout we should not be able to access store and invoice details
                s.Driver.FindElement(By.Id("Logout")).Click();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.GoToRegister();
                // When logged we should not be able to access store and invoice details
                var bob = s.RegisterNewUser();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.AssertNotFound();
                s.GoToHome();
                s.Logout();

                // Let's add Bob as a guest to alice's store
                LogIn(s, alice);
                s.Driver.Navigate().GoToUrl(storeUrl + "/users");
                s.Driver.FindElement(By.Id("Email")).SendKeys(bob + Keys.Enter);
                Assert.Contains("User added successfully", s.Driver.PageSource);
                s.Logout();

                // Bob should not have access to store, but should have access to invoice
                LogIn(s, bob);
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.Driver.AssertNoError();

                // Alice should be able to delete the store
                s.Logout();
                LogIn(s, alice);
                s.Driver.FindElement(By.Id("Stores")).Click();
                s.Driver.FindElement(By.LinkText("Remove")).Click();
                s.Driver.FindElement(By.Id("continue")).Click();
                s.Driver.FindElement(By.Id("Stores")).Click();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
            }
        }
예제 #2
0
 public void SetCheckbox(SeleniumTester s, string checkboxId, bool value)
 {
     SetCheckbox(s.Driver.FindElement(By.Id(checkboxId)), value);
 }
예제 #3
0
        public async Task CanUseBIP79Client()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var invoiceRepository = s.Server.PayTester.GetService <InvoiceRepository>();
                // var payjoinRepository = s.Server.PayTester.GetService<PayJoinRepository>();
                // var broadcaster = s.Server.PayTester.GetService<DelayedTransactionBroadcaster>();
                s.RegisterNewUser(true);
                var receiver         = s.CreateNewStore();
                var receiverSeed     = s.GenerateWallet("BTC", "", true, true);
                var receiverWalletId = new WalletId(receiver.storeId, "BTC");

                //payjoin is not enabled by default.
                var invoiceId = s.CreateInvoice(receiver.storeId);
                s.GoToInvoiceCheckout(invoiceId);
                var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
                            .GetAttribute("href");
                Assert.DoesNotContain("bpu=", bip21);

                s.GoToHome();
                s.GoToStore(receiver.storeId);
                //payjoin is not enabled by default.
                Assert.False(s.Driver.FindElement(By.Id("PayJoinEnabled")).Selected);
                s.SetCheckbox(s, "PayJoinEnabled", true);
                s.Driver.FindElement(By.Id("Save")).Click();
                Assert.True(s.Driver.FindElement(By.Id("PayJoinEnabled")).Selected);
                var sender         = s.CreateNewStore();
                var senderSeed     = s.GenerateWallet("BTC", "", true, true);
                var senderWalletId = new WalletId(sender.storeId, "BTC");
                await s.Server.ExplorerNode.GenerateAsync(1);

                await s.FundStoreWallet(senderWalletId);

                invoiceId = s.CreateInvoice(receiver.storeId);
                s.GoToInvoiceCheckout(invoiceId);
                bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
                        .GetAttribute("href");
                Assert.Contains("bpu=", bip21);

                s.GoToWalletSend(senderWalletId);
                s.Driver.FindElement(By.Id("bip21parse")).Click();
                s.Driver.SwitchTo().Alert().SendKeys(bip21);
                s.Driver.SwitchTo().Alert().Accept();
                Assert.False(string.IsNullOrEmpty(s.Driver.FindElement(By.Id("PayJoinEndpointUrl")).GetAttribute("value")));
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click();
                await s.Server.WaitForEvent <NewOnChainTransactionEvent>(() =>
                {
                    s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).ForceClick();
                    return(Task.CompletedTask);
                });

                //no funds in receiver wallet to do payjoin
                s.AssertHappyMessage(StatusMessageModel.StatusSeverity.Warning);
                await TestUtils.EventuallyAsync(async() =>
                {
                    var invoice = await s.Server.PayTester.GetService <InvoiceRepository>().GetInvoice(invoiceId);
                    Assert.Equal(InvoiceStatus.Paid, invoice.Status);
                });

                s.GoToInvoices();
                var paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_{invoiceId}")).FindElement(By.ClassName("payment-value"));
                Assert.False(paymentValueRowColumn.Text.Contains("payjoin", StringComparison.InvariantCultureIgnoreCase));

                //let's do it all again, except now the receiver has funds and is able to payjoin
                invoiceId = s.CreateInvoice(receiver.storeId);
                s.GoToInvoiceCheckout(invoiceId);
                bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
                        .GetAttribute("href");
                Assert.Contains("bpu", bip21);

                s.GoToWalletSend(senderWalletId);
                s.Driver.FindElement(By.Id("bip21parse")).Click();
                s.Driver.SwitchTo().Alert().SendKeys(bip21);
                s.Driver.SwitchTo().Alert().Accept();
                Assert.False(string.IsNullOrEmpty(s.Driver.FindElement(By.Id("PayJoinEndpointUrl")).GetAttribute("value")));
                s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).Clear();
                s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).SendKeys("1");
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click();
                await s.Server.WaitForEvent <NewOnChainTransactionEvent>(() =>
                {
                    s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).ForceClick();
                    return(Task.CompletedTask);
                });

                s.AssertHappyMessage(StatusMessageModel.StatusSeverity.Success);
                await TestUtils.EventuallyAsync(async() =>
                {
                    var invoice  = await invoiceRepository.GetInvoice(invoiceId);
                    var payments = invoice.GetPayments();
                    Assert.Equal(2, payments.Count);
                    var originalPayment = payments[0];
                    var coinjoinPayment = payments[1];
                    Assert.Equal(-1, ((BitcoinLikePaymentData)originalPayment.GetCryptoPaymentData()).ConfirmationCount);
                    Assert.Equal(0, ((BitcoinLikePaymentData)coinjoinPayment.GetCryptoPaymentData()).ConfirmationCount);
                    Assert.False(originalPayment.Accounted);
                    Assert.True(coinjoinPayment.Accounted);
                    Assert.Equal(((BitcoinLikePaymentData)originalPayment.GetCryptoPaymentData()).Value,
                                 ((BitcoinLikePaymentData)coinjoinPayment.GetCryptoPaymentData()).Value);
                    Assert.Equal(originalPayment.GetCryptoPaymentData()
                                 .AssertType <BitcoinLikePaymentData>()
                                 .Value,
                                 coinjoinPayment.GetCryptoPaymentData()
                                 .AssertType <BitcoinLikePaymentData>()
                                 .Value);
                });

                await TestUtils.EventuallyAsync(async() =>
                {
                    var invoice = await s.Server.PayTester.GetService <InvoiceRepository>().GetInvoice(invoiceId);
                    var dto     = invoice.EntityToDTO();
                    Assert.Equal(InvoiceStatus.Paid, invoice.Status);
                });

                s.GoToInvoices();
                paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_{invoiceId}")).FindElement(By.ClassName("payment-value"));
                Assert.False(paymentValueRowColumn.Text.Contains("payjoin", StringComparison.InvariantCultureIgnoreCase));
            }
        }
예제 #4
0
        public async Task NewUserLogin()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                //Register & Log Out
                var email = s.RegisterNewUser();
                s.Logout();
                s.Driver.AssertNoError();
                Assert.Contains("Account/Login", s.Driver.Url);
                // Should show the Tor address
                Assert.Contains("wsaxew3qa5ljfuenfebmaf3m5ykgatct3p6zjrqwoouj3foererde3id.onion", s.Driver.PageSource);

                s.Driver.Navigate().GoToUrl(s.Link("/invoices"));
                Assert.Contains("ReturnUrl=%2Finvoices", s.Driver.Url);

                // We should be redirected to login
                //Same User Can Log Back In
                s.Driver.FindElement(By.Id("Email")).SendKeys(email);
                s.Driver.FindElement(By.Id("Password")).SendKeys("123456");
                s.Driver.FindElement(By.Id("LoginButton")).Click();

                // We should be redirected to invoice
                Assert.EndsWith("/invoices", s.Driver.Url);

                // Should not be able to reach server settings
                s.Driver.Navigate().GoToUrl(s.Link("/server/users"));
                Assert.Contains("ReturnUrl=%2Fserver%2Fusers", s.Driver.Url);

                //Change Password & Log Out
                s.Driver.FindElement(By.Id("MySettings")).Click();
                s.Driver.FindElement(By.Id("ChangePassword")).Click();
                s.Driver.FindElement(By.Id("OldPassword")).SendKeys("123456");
                s.Driver.FindElement(By.Id("NewPassword")).SendKeys("abc???");
                s.Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("abc???");
                s.Driver.FindElement(By.Id("UpdatePassword")).Click();
                s.Driver.FindElement(By.Id("Logout")).Click();
                s.Driver.AssertNoError();

                //Log In With New Password
                s.Driver.FindElement(By.Id("Email")).SendKeys(email);
                s.Driver.FindElement(By.Id("Password")).SendKeys("abc???");
                s.Driver.FindElement(By.Id("LoginButton")).Click();
                Assert.True(s.Driver.PageSource.Contains("Stores"), "Can't Access Stores");

                s.Driver.FindElement(By.Id("MySettings")).Click();
                s.ClickOnAllSideMenus();

                //let's test invite link
                s.Logout();
                s.GoToRegister();
                var newAdminUser = s.RegisterNewUser(true);
                s.GoToServer(ServerNavPages.Users);
                s.Driver.FindElement(By.Id("CreateUser")).Click();

                var usr = RandomUtils.GetUInt256().ToString().Substring(64 - 20) + "@a.com";
                s.Driver.FindElement(By.Id("Email")).SendKeys(usr);
                s.Driver.FindElement(By.Id("Save")).Click();
                var url = s.AssertHappyMessage().FindElement(By.TagName("a")).Text;;
                s.Logout();
                s.Driver.Navigate().GoToUrl(url);
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("Email")).GetAttribute("type"));
                Assert.Equal(usr, s.Driver.FindElement(By.Id("Email")).GetAttribute("value"));

                s.Driver.FindElement(By.Id("Password")).SendKeys("123456");
                s.Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("123456");
                s.Driver.FindElement(By.Id("SetPassword")).Click();
                s.AssertHappyMessage();
                s.Driver.FindElement(By.Id("Email")).SendKeys(usr);
                s.Driver.FindElement(By.Id("Password")).SendKeys("123456");
                s.Driver.FindElement(By.Id("LoginButton")).Click();

                // We should be logged in now
                s.Driver.FindElement(By.Id("mainNav"));
            }
        }
예제 #5
0
        public async Task CanManageWallet()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                s.RegisterNewUser(true);
                s.CreateNewStore();

                // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed
                // to sign the transaction
                var mnemonic = "usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage";
                var root     = new Mnemonic(mnemonic).DeriveExtKey();
                s.AddDerivationScheme("BTC", "ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD");
                var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create("bcrt1qmxg8fgnmkp354vhe78j6sr4ut64tyz2xyejel4", Network.RegTest), Money.Coins(3.0m));
                s.Server.ExplorerNode.Generate(1);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.ClickOnAllSideMenus();

                // Make sure we can rescan, because we are admin!
                s.Driver.FindElement(By.Id("WalletRescan")).ForceClick();
                Assert.Contains("The batch size make sure", s.Driver.PageSource);

                // We setup the fingerprint and the account key path
                s.Driver.FindElement(By.Id("WalletSettings")).ForceClick();
                s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160");
                s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter);

                // Check the tx sent earlier arrived
                s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick();
                var walletTransactionLink = s.Driver.Url;
                Assert.Contains(tx.ToString(), s.Driver.PageSource);


                void SignWith(string signingSource)
                {
                    // Send to bob
                    s.Driver.FindElement(By.Id("WalletSend")).Click();
                    var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);

                    SetTransactionOutput(0, bob, 1);
                    s.Driver.ScrollTo(By.Id("SendMenu"));
                    s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                    s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click();

                    // Input the seed
                    s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter);

                    // Broadcast
                    Assert.Contains(bob.ToString(), s.Driver.PageSource);
                    Assert.Contains("1.00000000", s.Driver.PageSource);
                    s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                    Assert.Equal(walletTransactionLink, s.Driver.Url);
                }

                void SetTransactionOutput(int index, BitcoinAddress dest, decimal amount, bool subtract = false)
                {
                    s.Driver.FindElement(By.Id($"Outputs_{index}__DestinationAddress")).SendKeys(dest.ToString());
                    var amountElement = s.Driver.FindElement(By.Id($"Outputs_{index}__Amount"));

                    amountElement.Clear();
                    amountElement.SendKeys(amount.ToString());
                    var checkboxElement = s.Driver.FindElement(By.Id($"Outputs_{index}__SubtractFeesFromOutput"));

                    if (checkboxElement.Selected != subtract)
                    {
                        checkboxElement.Click();
                    }
                }

                SignWith(mnemonic);
                var accountKey = root.Derive(new KeyPath("m/49'/0'/0'")).GetWif(Network.RegTest).ToString();
                SignWith(accountKey);
            }
        }
예제 #6
0
        public async Task CanUsePullPaymentsViaUI()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                s.RegisterNewUser(true);
                var receiver     = s.CreateNewStore();
                var receiverSeed = s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit);
                await s.Server.ExplorerNode.GenerateAsync(1);

                await s.FundStoreWallet(denomination : 50.0m);

                s.GoToWallet(navPages: WalletsNavPages.PullPayments);
                s.Driver.FindElement(By.Id("NewPullPayment")).Click();
                s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
                s.Driver.FindElement(By.Id("Amount")).Clear();
                s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0" + Keys.Enter);
                s.Driver.FindElement(By.LinkText("View")).Click();

                Thread.Sleep(1000);
                s.GoToWallet(navPages: WalletsNavPages.PullPayments);
                s.Driver.FindElement(By.Id("NewPullPayment")).Click();
                s.Driver.FindElement(By.Id("Name")).SendKeys("PP2");
                s.Driver.FindElement(By.Id("Amount")).Clear();
                s.Driver.FindElement(By.Id("Amount")).SendKeys("100.0" + Keys.Enter);
                // This should select the first View, ie, the last one PP2
                s.Driver.FindElement(By.LinkText("View")).Click();

                Thread.Sleep(1000);
                var address = await s.Server.ExplorerNode.GetNewAddressAsync();

                s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString());
                s.Driver.FindElement(By.Id("ClaimedAmount")).Clear();
                s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("15" + Keys.Enter);
                s.AssertHappyMessage();

                // We should not be able to use an address already used
                s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString());
                s.Driver.FindElement(By.Id("ClaimedAmount")).Clear();
                s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("20" + Keys.Enter);
                s.AssertHappyMessage(StatusMessageModel.StatusSeverity.Error);

                address = await s.Server.ExplorerNode.GetNewAddressAsync();

                s.Driver.FindElement(By.Id("Destination")).Clear();
                s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString());
                s.Driver.FindElement(By.Id("ClaimedAmount")).Clear();
                s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("20" + Keys.Enter);
                s.AssertHappyMessage();
                Assert.Contains("AwaitingPayment", s.Driver.PageSource);

                var viewPullPaymentUrl = s.Driver.Url;
                // This one should have nothing
                s.GoToWallet(navPages: WalletsNavPages.PullPayments);
                var payouts = s.Driver.FindElements(By.ClassName("pp-payout"));
                Assert.Equal(2, payouts.Count);
                payouts[1].Click();
                Assert.Contains("No payout waiting for approval", s.Driver.PageSource);

                // PP2 should have payouts
                s.GoToWallet(navPages: WalletsNavPages.PullPayments);
                payouts = s.Driver.FindElements(By.ClassName("pp-payout"));
                payouts[0].Click();
                Assert.DoesNotContain("No payout waiting for approval", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("selectAllCheckbox")).Click();
                s.Driver.FindElement(By.Id("payCommand")).Click();
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click();
                s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                s.AssertHappyMessage();

                TestUtils.Eventually(() =>
                {
                    s.Driver.Navigate().Refresh();
                    Assert.Contains("badge transactionLabel", s.Driver.PageSource);
                });
                Assert.Equal("Payout", s.Driver.FindElement(By.ClassName("transactionLabel")).Text);

                s.GoToWallet(navPages: WalletsNavPages.Payouts);
                TestUtils.Eventually(() =>
                {
                    s.Driver.Navigate().Refresh();
                    Assert.Contains("No payout waiting for approval", s.Driver.PageSource);
                });
                var txs = s.Driver.FindElements(By.ClassName("transaction-link"));
                Assert.Equal(2, txs.Count);

                s.Driver.Navigate().GoToUrl(viewPullPaymentUrl);
                txs = s.Driver.FindElements(By.ClassName("transaction-link"));
                Assert.Equal(2, txs.Count);
                Assert.Contains("InProgress", s.Driver.PageSource);


                await s.Server.ExplorerNode.GenerateAsync(1);

                TestUtils.Eventually(() =>
                {
                    s.Driver.Navigate().Refresh();
                    Assert.Contains("Completed", s.Driver.PageSource);
                });
                await s.Server.ExplorerNode.GenerateAsync(10);

                var pullPaymentId = viewPullPaymentUrl.Split('/').Last();

                await TestUtils.EventuallyAsync(async() =>
                {
                    using var ctx   = s.Server.PayTester.GetService <ApplicationDbContextFactory>().CreateContext();
                    var payoutsData = await ctx.Payouts.Where(p => p.PullPaymentDataId == pullPaymentId).ToListAsync();
                    Assert.True(payoutsData.All(p => p.State == Data.PayoutState.Completed));
                });
            }
        }
예제 #7
0
        public async Task CanCreateApiKeys()
        {
            //there are 2 ways to create api keys:
            //as a user through your profile
            //as an external application requesting an api key from a user

            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var tester = s.Server;

                var user = tester.NewAccount();
                user.GrantAccess();
                await user.MakeAdmin(false);

                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();

                //not an admin, so this permission should not show
                Assert.DoesNotContain("btcpay.server.canmodifyserversettings", s.Driver.PageSource);
                await user.MakeAdmin();

                s.Logout();
                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                Assert.Contains("btcpay.server.canmodifyserversettings", s.Driver.PageSource);

                //server management should show now
                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true);
                s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true);
                s.SetCheckbox(s, "btcpay.user.canviewprofile", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var superApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

                //this api key has access to everything
                await TestApiAgainstAccessToken(superApiKey, tester, user, Policies.CanModifyServerSettings, Policies.CanModifyStoreSettings, Policies.CanViewProfile);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var serverOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
                                                Policies.CanModifyServerSettings);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var allStoreOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user,
                                                Policies.CanModifyStoreSettings);

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.CssSelector("button[value='btcpay.store.canmodifystoresettings:change-store-mode']")).Click();
                //there should be a store already by default in the dropdown
                var dropdown = s.Driver.FindElement(By.Name("PermissionValues[4].SpecificStores[0]"));
                var option   = dropdown.FindElement(By.TagName("option"));
                var storeId  = option.GetAttribute("value");
                option.Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var selectiveStoreApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user,
                                                Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString());

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var noPermissionsApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user);

                await Assert.ThrowsAnyAsync <HttpRequestException>(async() =>
                {
                    await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id",
                                                           tester.PayTester.HttpClient);
                });

                //let's test the authorized screen now
                //options for authorize are:
                //applicationName
                //redirect
                //permissions
                //strict
                //selectiveStores
                //redirect
                //appidentifier
                var appidentifier = "testapp";
                var callbackUrl   = tester.PayTester.ServerUri + "postredirect-callback-test";
                var authUrl       = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                            new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
                s.Driver.Navigate().GoToUrl(authUrl);
                Assert.Contains(appidentifier, s.Driver.PageSource);
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());
                Assert.DoesNotContain("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                Assert.Equal(callbackUrl, s.Driver.Url);

                var apiKeyRepo  = s.Server.PayTester.GetService <APIKeyRepository>();
                var accessToken = GetAccessTokenFromCallbackResult(s.Driver);

                await TestApiAgainstAccessToken(accessToken, tester, user,
                                                (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions);

                authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                  new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, applicationDetails: (null, new Uri(callbackUrl))).ToString();

                s.Driver.Navigate().GoToUrl(authUrl);
                Assert.DoesNotContain("kukksappname", s.Driver.PageSource);

                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());

                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", false);
                Assert.Contains("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                Assert.Equal(callbackUrl, s.Driver.Url);

                accessToken = GetAccessTokenFromCallbackResult(s.Driver);
                await TestApiAgainstAccessToken(accessToken, tester, user,
                                                (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions);

                //let's test the app identifier system
                authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                  new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri(callbackUrl))).ToString();

                //if it's the same, go to the confirm page
                s.Driver.Navigate().GoToUrl(authUrl);
                s.Driver.FindElement(By.Id("continue")).Click();
                Assert.Equal(callbackUrl, s.Driver.Url);

                //same app but different redirect = nono
                authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                  new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString();

                s.Driver.Navigate().GoToUrl(authUrl);
                Assert.False(s.Driver.Url.StartsWith("https://international.com/callback"));

                // Make sure we can check all permissions when not an admin
                await user.MakeAdmin(false);

                s.Logout();
                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                int checkedPermissionCount = 0;
                foreach (var checkbox in s.Driver.FindElements(By.ClassName("form-check-input")))
                {
                    checkedPermissionCount++;
                    checkbox.Click();
                }
                s.Driver.FindElement(By.Id("Generate")).Click();
                var allAPIKey  = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
                var apikeydata = await TestApiAgainstAccessToken <ApiKeyData>(allAPIKey, $"api/v1/api-keys/current", tester.PayTester.HttpClient);

                Assert.Equal(checkedPermissionCount, apikeydata.Permissions.Length);
            }
        }
예제 #8
0
        public async Task CanUseCodeFlow()
        {
            using (var s = SeleniumTester.Create())
            {
                s.Start();
                var tester = s.Server;

                var user = tester.NewAccount();
                user.GrantAccess();
                var id           = Guid.NewGuid().ToString();
                var redirecturi  = new Uri("http://127.0.0.1/oidc-callback");
                var secret       = "secret";
                var openIdClient = await user.RegisterOpenIdClient(
                    new OpenIddictApplicationDescriptor()
                {
                    ClientId    = id,
                    DisplayName = id,
                    Permissions =
                    {
                        OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
                        OpenIddictConstants.Permissions.GrantTypes.RefreshToken
                    },
                    RedirectUris = { redirecturi }
                }, secret);

                var authorizeUrl = new Uri(tester.PayTester.ServerUri,
                                           $"connect/authorize?response_type=code&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid offline_access&state={Guid.NewGuid().ToString()}");
                s.Driver.Navigate().GoToUrl(authorizeUrl);
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                var url     = s.Driver.Url;
                var results = url.Split("?").Last().Split("&")
                              .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);

                var httpClient = tester.PayTester.HttpClient;

                var httpRequest = new HttpRequestMessage(HttpMethod.Post,
                                                         new Uri(tester.PayTester.ServerUri, "/connect/token"))
                {
                    Content = new FormUrlEncodedContent(new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("grant_type",
                                                          OpenIddictConstants.GrantTypes.AuthorizationCode),
                        new KeyValuePair <string, string>("client_id", openIdClient.ClientId),
                        new KeyValuePair <string, string>("client_secret", secret),
                        new KeyValuePair <string, string>("code", results["code"]),
                        new KeyValuePair <string, string>("redirect_uri", redirecturi.AbsoluteUri)
                    })
                };


                var response = await httpClient.SendAsync(httpRequest);

                Assert.True(response.IsSuccessStatusCode);

                string content = await response.Content.ReadAsStringAsync();

                var result = JObject.Parse(content).ToObject <OpenIdConnectResponse>();

                await TestApiAgainstAccessToken(result.AccessToken, tester, user);

                var refreshedAccessToken = await RefreshAnAccessToken(result.RefreshToken, httpClient, id, secret);

                await TestApiAgainstAccessToken(refreshedAccessToken, tester, user);

                LogoutFlow(tester, id, s);
                s.Driver.Navigate().GoToUrl(authorizeUrl);
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);

                Assert.Throws <NoSuchElementException>(() => s.Driver.FindElement(By.Id("consent-yes")));
                results = url.Split("?").Last().Split("&")
                          .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
                Assert.True(results.ContainsKey("code"));
            }
        }
예제 #9
0
        public async Task CanManageWallet()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                s.RegisterNewUser(true);
                var storeId = s.CreateNewStore();

                // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed
                // to sign the transaction
                var mnemonic = s.GenerateWallet("BTC", "", true, false);

                var invoiceId = s.CreateInvoice(storeId.storeId);
                var invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                var address = invoice.EntityToDTO().Addresses["BTC"];

                var result = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                Assert.True(result.IsWatchOnly);
                s.GoToStore(storeId.storeId);
                mnemonic = s.GenerateWallet("BTC", "", true, true);

                var root = new Mnemonic(mnemonic).DeriveExtKey();
                invoiceId = s.CreateInvoice(storeId.storeId);
                invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                address = invoice.EntityToDTO().Addresses["BTC"];
                result  = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                Assert.False(result.IsWatchOnly);
                var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(address, Network.RegTest), Money.Coins(3.0m));
                s.Server.ExplorerNode.Generate(1);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.ClickOnAllSideMenus();

                // Make sure we can rescan, because we are admin!
                s.Driver.FindElement(By.Id("WalletRescan")).ForceClick();
                Assert.Contains("The batch size make sure", s.Driver.PageSource);

                // We setup the fingerprint and the account key path
                s.Driver.FindElement(By.Id("WalletSettings")).ForceClick();
//                s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160");
//                s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter);

                // Check the tx sent earlier arrived
                s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick();
                var walletTransactionLink = s.Driver.Url;
                Assert.Contains(tx.ToString(), s.Driver.PageSource);


                void SignWith(string signingSource)
                {
                    // Send to bob
                    s.Driver.FindElement(By.Id("WalletSend")).Click();
                    var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);

                    SetTransactionOutput(0, bob, 1);
                    s.Driver.ScrollTo(By.Id("SendMenu"));
                    s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                    s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click();

                    // Input the seed
                    s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter);

                    // Broadcast
                    Assert.Contains(bob.ToString(), s.Driver.PageSource);
                    Assert.Contains("1.00000000", s.Driver.PageSource);
                    s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                    Assert.Equal(walletTransactionLink, s.Driver.Url);
                }

                void SetTransactionOutput(int index, BitcoinAddress dest, decimal amount, bool subtract = false)
                {
                    s.Driver.FindElement(By.Id($"Outputs_{index}__DestinationAddress")).SendKeys(dest.ToString());
                    var amountElement = s.Driver.FindElement(By.Id($"Outputs_{index}__Amount"));

                    amountElement.Clear();
                    amountElement.SendKeys(amount.ToString());
                    var checkboxElement = s.Driver.FindElement(By.Id($"Outputs_{index}__SubtractFeesFromOutput"));

                    if (checkboxElement.Selected != subtract)
                    {
                        checkboxElement.Click();
                    }
                }

                SignWith(mnemonic);
            }
        }
예제 #10
0
        private static async Task CanCreateRefundsCore(SeleniumTester s, TestAccount user, bool multiCurrency, string rateSelection)
        {
            s.GoToHome();
            s.Server.PayTester.ChangeRate("BTC_USD", new Rating.BidAsk(5000.0m, 5100.0m));
            var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice
            {
                Currency = "USD",
                Price    = 5000.0m
            });

            var info     = invoice.CryptoInfo.First(o => o.CryptoCode == "BTC");
            var totalDue = decimal.Parse(info.TotalDue, CultureInfo.InvariantCulture);
            var paid     = totalDue + 0.1m;
            await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(info.Address, Network.RegTest), Money.Coins(paid));

            await s.Server.ExplorerNode.GenerateAsync(1);

            await TestUtils.EventuallyAsync(async() =>
            {
                invoice = await user.BitPay.GetInvoiceAsync(invoice.Id);
                Assert.Equal("confirmed", invoice.Status);
            });

            // BTC crash by 50%
            s.Server.PayTester.ChangeRate("BTC_USD", new Rating.BidAsk(5000.0m / 2.0m, 5100.0m / 2.0m));
            s.GoToStore();
            s.Driver.FindElement(By.Id("BOLT11Expiration")).Clear();
            s.Driver.FindElement(By.Id("BOLT11Expiration")).SendKeys("5" + Keys.Enter);
            s.GoToInvoice(invoice.Id);
            s.Driver.FindElement(By.Id("IssueRefund")).Click();

            if (multiCurrency)
            {
                s.Driver.WaitUntilAvailable(By.Id("RefundForm"), TimeSpan.FromSeconds(1));
                s.Driver.WaitUntilAvailable(By.Id("SelectedPaymentMethod"), TimeSpan.FromSeconds(1));
                s.Driver.FindElement(By.Id("SelectedPaymentMethod")).SendKeys("BTC" + Keys.Enter);
                s.Driver.FindElement(By.Id("ok")).Click();
            }

            s.Driver.WaitUntilAvailable(By.Id("RefundForm"), TimeSpan.FromSeconds(1));
            Assert.Contains("$5,500.00", s.Driver.PageSource);    // Should propose reimburse in fiat
            Assert.Contains("1.10000000 ₿", s.Driver.PageSource); // Should propose reimburse in BTC at the rate of before
            Assert.Contains("2.20000000 ₿", s.Driver.PageSource); // Should propose reimburse in BTC at the current rate
            s.Driver.WaitForAndClick(By.Id(rateSelection));
            s.Driver.FindElement(By.Id("ok")).Click();

            s.Driver.WaitUntilAvailable(By.Id("Destination"), TimeSpan.FromSeconds(1));
            Assert.Contains("pull-payments", s.Driver.Url);
            if (rateSelection == "FiatOption")
            {
                Assert.Contains("$5,500.00", s.Driver.PageSource);
            }
            if (rateSelection == "CurrentOption")
            {
                Assert.Contains("2.20000000 ₿", s.Driver.PageSource);
            }
            if (rateSelection == "RateThenOption")
            {
                Assert.Contains("1.10000000 ₿", s.Driver.PageSource);
            }

            s.GoToInvoice(invoice.Id);
            s.Driver.FindElement(By.Id("IssueRefund")).Click();
            s.Driver.WaitUntilAvailable(By.Id("Destination"), TimeSpan.FromSeconds(1));
            Assert.Contains("pull-payments", s.Driver.Url);
            var client = await user.CreateClient();

            var ppid = s.Driver.Url.Split('/').Last();
            var pps  = await client.GetPullPayments(user.StoreId);

            var pp = Assert.Single(pps, p => p.Id == ppid);

            Assert.Equal(TimeSpan.FromDays(5.0), pp.BOLT11Expiration);
        }
예제 #11
0
 private static void SendAllTo(SeleniumTester s, string address)
 {
     s.Driver.FindElement(By.Name("Outputs[0].DestinationAddress")).SendKeys(address);
     s.Driver.FindElement(By.ClassName("crypto-balance-link")).Click();
     s.Driver.FindElement(By.Id("SignTransaction")).Click();
 }
예제 #12
0
        public async Task CanCreateStores()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var alice     = s.RegisterNewUser();
                var storeData = s.CreateNewStore();
                // verify that hints are displayed on the store page
                Assert.True(s.Driver.PageSource.Contains("Wallet not setup for the store, please provide Derviation Scheme"),
                            "Wallet hint not present");
                Assert.True(s.Driver.PageSource.Contains("Review settings if you want to receive Lightning payments"),
                            "Lightning hint not present");

                s.GoToStores();
                Assert.True(s.Driver.PageSource.Contains("warninghint_" + storeData.storeId),
                            "Warning hint on list not present");

                s.GoToStore(storeData.storeId);
                s.AddDerivationScheme(); // wallet hint should be dismissed
                s.Driver.AssertNoError();
                Assert.False(s.Driver.PageSource.Contains("Wallet not setup for the store, please provide Derviation Scheme"),
                             "Wallet hint not dismissed on derivation scheme add");

                s.Driver.FindElement(By.Id("dismissLightningHint")).Click(); // dismiss lightning hint

                Assert.Contains(storeData.storeName, s.Driver.PageSource);
                var storeUrl = s.Driver.Url;
                s.ClickOnAllSideMenus();
                s.GoToInvoices();
                var invoiceId = s.CreateInvoice(storeData.storeName);
                s.AssertHappyMessage();
                s.Driver.FindElement(By.ClassName("invoice-details-link")).Click();
                var invoiceUrl = s.Driver.Url;

                //let's test archiving an invoice
                Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
                s.AssertHappyMessage();
                Assert.Contains("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                //check that it no longer appears in list
                s.GoToInvoices();
                Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
                //ok, let's unarchive and see that it shows again
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
                s.AssertHappyMessage();
                Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text);
                s.GoToInvoices();
                Assert.Contains(invoiceId, s.Driver.PageSource);

                // When logout we should not be able to access store and invoice details
                s.Driver.FindElement(By.Id("Logout")).Click();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.GoToRegister();
                // When logged we should not be able to access store and invoice details
                var bob = s.RegisterNewUser();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.AssertNotFound();
                s.GoToHome();
                s.Logout();

                // Let's add Bob as a guest to alice's store
                LogIn(s, alice);
                s.Driver.Navigate().GoToUrl(storeUrl + "/users");
                s.Driver.FindElement(By.Id("Email")).SendKeys(bob + Keys.Enter);
                Assert.Contains("User added successfully", s.Driver.PageSource);
                s.Logout();

                // Bob should not have access to store, but should have access to invoice
                LogIn(s, bob);
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
                s.Driver.Navigate().GoToUrl(invoiceUrl);
                s.Driver.AssertNoError();

                // Alice should be able to delete the store
                s.Logout();
                LogIn(s, alice);
                s.Driver.FindElement(By.Id("Stores")).Click();

                // there shouldn't be any hints now
                Assert.False(s.Driver.PageSource.Contains("Review settings if you want to receive Lightning payments"),
                             "Lightning hint should be dismissed at this point");

                s.Driver.FindElement(By.LinkText("Remove")).Click();
                s.Driver.FindElement(By.Id("continue")).Click();
                s.Driver.FindElement(By.Id("Stores")).Click();
                s.Driver.Navigate().GoToUrl(storeUrl);
                Assert.Contains("ReturnUrl", s.Driver.Url);
            }
        }
        public async Task CanUseImplicitFlow()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var tester = s.Server;

                var user = tester.NewAccount();
                user.GrantAccess();
                await user.MakeAdmin();

                var id           = Guid.NewGuid().ToString();
                var redirecturi  = new Uri("http://127.0.0.1/oidc-callback");
                var openIdClient = await user.RegisterOpenIdClient(
                    new OpenIddictApplicationDescriptor()
                {
                    ClientId     = id,
                    DisplayName  = id,
                    Permissions  = { OpenIddictConstants.Permissions.GrantTypes.Implicit },
                    RedirectUris = { redirecturi },
                });

                var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
                                                   $"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid server_management store_management&nonce={Guid.NewGuid().ToString()}");
                s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                var url     = s.Driver.Url;
                var results = url.Split("#").Last().Split("&")
                              .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
                await TestApiAgainstAccessToken(results["access_token"], tester, user);

                //in Implicit mode, you renew your token  by hitting the same endpoint but adding prompt=none. If you are still logged in on the site, you will receive a fresh token.
                var implicitAuthorizeUrlSilentModel = new Uri($"{implicitAuthorizeUrl.OriginalString}&prompt=none");
                s.Driver.Navigate().GoToUrl(implicitAuthorizeUrlSilentModel);
                url     = s.Driver.Url;
                results = url.Split("#").Last().Split("&").ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
                await TestApiAgainstAccessToken(results["access_token"], tester, user);

                var stores = await TestApiAgainstAccessToken <StoreData[]>(results["access_token"],
                                                                           $"api/test/me/stores",
                                                                           tester.PayTester.HttpClient);

                Assert.NotEmpty(stores);

                Assert.True(await TestApiAgainstAccessToken <bool>(results["access_token"],
                                                                   $"api/test/me/stores/{stores[0].Id}/can-edit",
                                                                   tester.PayTester.HttpClient));

                //we dont ask for consent after acquiring it the first time for the same scopes.
                LogoutFlow(tester, id, s);
                s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.Driver.AssertElementNotFound(By.Id("consent-yes"));

                // Let's asks without scopes
                LogoutFlow(tester, id, s);
                id           = Guid.NewGuid().ToString();
                openIdClient = await user.RegisterOpenIdClient(
                    new OpenIddictApplicationDescriptor()
                {
                    ClientId     = id,
                    DisplayName  = id,
                    Permissions  = { OpenIddictConstants.Permissions.GrantTypes.Implicit },
                    RedirectUris = { redirecturi },
                });

                implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
                                               $"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}");
                s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                results = s.Driver.Url.Split("#").Last().Split("&")
                          .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);

                await Assert.ThrowsAnyAsync <HttpRequestException>(async() =>
                {
                    await TestApiAgainstAccessToken <StoreData[]>(results["access_token"],
                                                                  $"api/test/me/stores",
                                                                  tester.PayTester.HttpClient);
                });

                await Assert.ThrowsAnyAsync <HttpRequestException>(async() =>
                {
                    await TestApiAgainstAccessToken <bool>(results["access_token"],
                                                           $"api/test/me/stores/{stores[0].Id}/can-edit",
                                                           tester.PayTester.HttpClient);
                });
            }
        }
예제 #14
0
        public async Task CanCreateApiKeys()
        {
            //there are 2 ways to create api keys:
            //as a user through your profile
            //as an external application requesting an api key from a user

            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var tester = s.Server;

                var user = tester.NewAccount();
                user.GrantAccess();

                await user.CreateStoreAsync();

                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                if (!user.IsAdmin)
                {
                    //not an admin, so this permission should not show
                    Assert.DoesNotContain("ServerManagementPermission", s.Driver.PageSource);
                    await user.MakeAdmin();

                    s.Logout();
                    s.GoToLogin();
                    s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                    s.GoToProfile(ManageNavPages.APIKeys);
                    s.Driver.FindElement(By.Id("AddApiKey")).Click();
                }

                //server management should show now
                s.SetCheckbox(s, "ServerManagementPermission", true);
                s.SetCheckbox(s, "StoreManagementPermission", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var superApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;

                //this api key has access to everything
                await TestApiAgainstAccessToken(superApiKey, tester, user, APIKeyConstants.Permissions.ServerManagement,
                                                APIKeyConstants.Permissions.StoreManagement);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "ServerManagementPermission", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var serverOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
                                                APIKeyConstants.Permissions.ServerManagement);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "StoreManagementPermission", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var allStoreOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user,
                                                APIKeyConstants.Permissions.StoreManagement);

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.CssSelector("button[value=change-store-mode]")).Click();
                //there should be a store already by default in the dropdown
                var dropdown = s.Driver.FindElement(By.Name("SpecificStores[0]"));
                var option   = dropdown.FindElement(By.TagName("option"));
                var storeId  = option.GetAttribute("value");
                option.Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var selectiveStoreApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user,
                                                APIKeyConstants.Permissions.GetStorePermission(storeId));

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var noPermissionsApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user);

                await Assert.ThrowsAnyAsync <HttpRequestException>(async() =>
                {
                    await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id",
                                                           tester.PayTester.HttpClient);
                });


                //let's test the authorized screen now
                //options for authorize are:
                //applicationName
                //redirect
                //permissions
                //strict
                //selectiveStores
                UriBuilder authorize = new UriBuilder(tester.PayTester.ServerUri);
                authorize.Path = "api-keys/authorize";

                authorize.AppendPayloadToQuery(new Dictionary <string, object>()
                {
                    { "redirect", "https://local.local/callback" },
                    { "applicationName", "kukksappname" },
                    { "strict", true },
                    { "selectiveStores", false },
                    {
                        "permissions",
                        new[]
                        {
                            APIKeyConstants.Permissions.StoreManagement,
                            APIKeyConstants.Permissions.ServerManagement
                        }
                    },
                });
                var authUrl = authorize.ToString();
                var perms   = new[]
                {
                    APIKeyConstants.Permissions.StoreManagement, APIKeyConstants.Permissions.ServerManagement
                };
                authUrl = authUrl.Replace("permissions=System.String%5B%5D",
                                          string.Join("&", perms.Select(s1 => $"permissions={s1}")));
                s.Driver.Navigate().GoToUrl(authUrl);
                s.Driver.PageSource.Contains("kukksappname");
                Assert.NotNull(s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("readonly"));
                Assert.True(s.Driver.FindElement(By.Id("StoreManagementPermission")).Selected);
                Assert.NotNull(s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("readonly"));
                Assert.True(s.Driver.FindElement(By.Id("ServerManagementPermission")).Selected);
                Assert.DoesNotContain("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                var url = s.Driver.Url;
                IEnumerable <KeyValuePair <string, string> > results = url.Split("?").Last().Split("&")
                                                                       .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1]));

                var apiKeyRepo = s.Server.PayTester.GetService <APIKeyRepository>();

                await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user,
                                                (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetPermissions());

                authorize      = new UriBuilder(tester.PayTester.ServerUri);
                authorize.Path = "api-keys/authorize";
                authorize.AppendPayloadToQuery(new Dictionary <string, object>()
                {
                    { "strict", false },
                    { "selectiveStores", true },
                    {
                        "permissions",
                        new[]
                        {
                            APIKeyConstants.Permissions.StoreManagement,
                            APIKeyConstants.Permissions.ServerManagement
                        }
                    }
                });
                authUrl = authorize.ToString();
                perms   = new[]
                {
                    APIKeyConstants.Permissions.StoreManagement, APIKeyConstants.Permissions.ServerManagement
                };
                authUrl = authUrl.Replace("permissions=System.String%5B%5D",
                                          string.Join("&", perms.Select(s1 => $"permissions={s1}")));
                s.Driver.Navigate().GoToUrl(authUrl);
                Assert.DoesNotContain("kukksappname", s.Driver.PageSource);

                Assert.Null(s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("readonly"));
                Assert.True(s.Driver.FindElement(By.Id("StoreManagementPermission")).Selected);
                Assert.Null(s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("readonly"));
                Assert.True(s.Driver.FindElement(By.Id("ServerManagementPermission")).Selected);

                s.SetCheckbox(s, "ServerManagementPermission", false);
                Assert.Contains("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                url     = s.Driver.Url;
                results = url.Split("?").Last().Split("&")
                          .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1]));

                await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user,
                                                (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetPermissions());
            }
        }
예제 #15
0
        public async Task CanUseCoinSelection()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var userId  = s.RegisterNewUser(true);
                var storeId = s.CreateNewStore().storeId;
                s.GenerateWallet("BTC", "", false, true);
                var walletId = new WalletId(storeId, "BTC");
                s.GoToWallet(walletId, WalletsNavPages.Receive);
                s.Driver.FindElement(By.Id("generateButton")).Click();
                var addressStr = s.Driver.FindElement(By.Id("vue-address")).GetProperty("value");
                var address    = BitcoinAddress.Create(addressStr, ((BTCPayNetwork)s.Server.NetworkProvider.GetNetwork("BTC")).NBitcoinNetwork);
                await s.Server.ExplorerNode.GenerateAsync(1);

                for (int i = 0; i < 6; i++)
                {
                    await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.0m));
                }
                var targetTx = await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.2m));

                var tx = await s.Server.ExplorerNode.GetRawTransactionAsync(targetTx);

                var spentOutpoint = new OutPoint(targetTx, tx.Outputs.FindIndex(txout => txout.Value == Money.Coins(1.2m)));
                await TestUtils.EventuallyAsync(async() =>
                {
                    var store = await s.Server.PayTester.StoreRepository.FindStore(storeId);
                    var x     = store.GetSupportedPaymentMethods(s.Server.NetworkProvider)
                                .OfType <DerivationSchemeSettings>()
                                .Single(settings => settings.PaymentId.CryptoCode == walletId.CryptoCode);
                    Assert.Contains(
                        await s.Server.PayTester.GetService <BTCPayWalletProvider>().GetWallet(walletId.CryptoCode)
                        .GetUnspentCoins(x.AccountDerivation),
                        coin => coin.OutPoint == spentOutpoint);
                });

                await s.Server.ExplorerNode.GenerateAsync(1);

                s.GoToWallet(walletId, WalletsNavPages.Send);
                s.Driver.FindElement(By.Id("advancedSettings")).Click();
                s.Driver.FindElement(By.Id("toggleInputSelection")).Click();
                s.Driver.WaitForElement(By.Id(spentOutpoint.ToString()));
                Assert.Equal("true", s.Driver.FindElement(By.Name("InputSelection")).GetAttribute("value").ToLowerInvariant());
                var el = s.Driver.FindElement(By.Id(spentOutpoint.ToString()));
                s.Driver.FindElement(By.Id(spentOutpoint.ToString())).Click();
                var inputSelectionSelect = s.Driver.FindElement(By.Name("SelectedInputs"));
                Assert.Single(inputSelectionSelect.FindElements(By.CssSelector("[selected]")));

                var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);
                SetTransactionOutput(s, 0, bob, 0.3m);
                s.Driver.FindElement(By.Id("SendMenu")).Click();
                s.Driver.FindElement(By.Id("spendWithNBxplorer")).Click();
                s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                var happyElement = s.AssertHappyMessage();
                var happyText    = happyElement.Text;
                var txid         = Regex.Match(happyText, @"\((.*)\)").Groups[1].Value;

                tx = await s.Server.ExplorerNode.GetRawTransactionAsync(new uint256(txid));

                Assert.Single(tx.Inputs);
                Assert.Equal(spentOutpoint, tx.Inputs[0].PrevOut);
            }
        }
예제 #16
0
 public void SetCheckbox(SeleniumTester s, string inputName, bool value)
 {
     SetCheckbox(s.Driver.FindElement(By.Name(inputName)), value);
 }
예제 #17
0
        public async Task CanManageWallet()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                s.RegisterNewUser(true);
                var storeId = s.CreateNewStore();

                // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed
                // to sign the transaction
                s.GenerateWallet("BTC", "", true, false);

                //let's test quickly the receive wallet page
                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.Driver.FindElement(By.Id("WalletSend")).Click();
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                //you cant use the Sign with NBX option without saving private keys when generating the wallet.
                Assert.DoesNotContain("nbx-seed", s.Driver.PageSource);

                s.Driver.FindElement(By.Id("WalletReceive")).Click();
                //generate a receiving address
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.True(s.Driver.FindElement(By.ClassName("qr-container")).Displayed);
                var receiveAddr = s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value");
                //unreserve
                s.Driver.FindElement(By.CssSelector("button[value=unreserve-current-address]")).Click();
                //generate it again, should be the same one as before as nothign got used in the meantime
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.True(s.Driver.FindElement(By.ClassName("qr-container")).Displayed);
                Assert.Equal(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));

                //send money to addr and ensure it changed

                var sess = await s.Server.ExplorerClient.CreateWebsocketNotificationSessionAsync();

                sess.ListenAllTrackedSource();
                var nextEvent = sess.NextEventAsync();
                s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(receiveAddr, Network.RegTest),
                                                    Money.Parse("0.1"));
                await nextEvent;
                await Task.Delay(200);

                s.Driver.Navigate().Refresh();
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));
                receiveAddr = s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value");
                //change the wallet and ensure old address is not there and generating a new one does not result in the prev one
                s.GoToStore(storeId.storeId);
                s.GenerateWallet("BTC", "", true, false);
                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();
                s.Driver.FindElement(By.Id("WalletReceive")).Click();
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));


                var invoiceId = s.CreateInvoice(storeId.storeName);
                var invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                var address = invoice.EntityToDTO().Addresses["BTC"];


                //wallet should have been imported to bitcoin core wallet in watch only mode.
                var result = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                Assert.True(result.IsWatchOnly);
                s.GoToStore(storeId.storeId);
                var mnemonic = s.GenerateWallet("BTC", "", true, true);

                //lets import and save private keys
                var root = mnemonic.DeriveExtKey();
                invoiceId = s.CreateInvoice(storeId.storeName);
                invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                address = invoice.EntityToDTO().Addresses["BTC"];
                result  = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                //spendable from bitcoin core wallet!
                Assert.False(result.IsWatchOnly);
                var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(address, Network.RegTest), Money.Coins(3.0m));
                s.Server.ExplorerNode.Generate(1);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.ClickOnAllSideMenus();

                // Make sure we can rescan, because we are admin!
                s.Driver.FindElement(By.Id("WalletRescan")).ForceClick();
                Assert.Contains("The batch size make sure", s.Driver.PageSource);

                // We setup the fingerprint and the account key path
                s.Driver.FindElement(By.Id("WalletSettings")).ForceClick();
                //                s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160");
                //                s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter);

                // Check the tx sent earlier arrived
                s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick();
                var walletTransactionLink = s.Driver.Url;
                Assert.Contains(tx.ToString(), s.Driver.PageSource);


                void SignWith(Mnemonic signingSource)
                {
                    // Send to bob
                    s.Driver.FindElement(By.Id("WalletSend")).Click();
                    var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);

                    SetTransactionOutput(s, 0, bob, 1);
                    s.Driver.ScrollTo(By.Id("SendMenu"));
                    s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                    s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click();

                    // Input the seed
                    s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource.ToString() + Keys.Enter);

                    // Broadcast
                    Assert.Contains(bob.ToString(), s.Driver.PageSource);
                    Assert.Contains("1.00000000", s.Driver.PageSource);
                    s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                    Assert.Equal(walletTransactionLink, s.Driver.Url);
                }

                SignWith(mnemonic);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();
                s.Driver.FindElement(By.Id("WalletSend")).Click();

                var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
                SetTransactionOutput(s, 0, jack, 0.01m);
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();

                s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click();
                Assert.Contains(jack.ToString(), s.Driver.PageSource);
                Assert.Contains("0.01000000", s.Driver.PageSource);
                s.Driver.FindElement(By.CssSelector("button[value=analyze-psbt]")).ForceClick();
                Assert.EndsWith("psbt", s.Driver.Url);
                s.Driver.FindElement(By.CssSelector("#OtherActions")).ForceClick();
                s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                Assert.EndsWith("psbt/ready", s.Driver.Url);
                s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                Assert.Equal(walletTransactionLink, s.Driver.Url);

                var bip21 = invoice.EntityToDTO().CryptoInfo.First().PaymentUrls.BIP21;
                //let's make bip21 more interesting
                bip21 += "&label=Solid Snake&message=Snake? Snake? SNAAAAKE!";
                var parsedBip21 = new BitcoinUrlBuilder(bip21, Network.RegTest);
                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();
                s.Driver.FindElement(By.Id("WalletSend")).Click();
                s.Driver.FindElement(By.Id("bip21parse")).Click();
                s.Driver.SwitchTo().Alert().SendKeys(bip21);
                s.Driver.SwitchTo().Alert().Accept();
                s.AssertHappyMessage(StatusMessageModel.StatusSeverity.Info);
                Assert.Equal(parsedBip21.Amount.ToString(false), s.Driver.FindElement(By.Id($"Outputs_0__Amount")).GetAttribute("value"));
                Assert.Equal(parsedBip21.Address.ToString(), s.Driver.FindElement(By.Id($"Outputs_0__DestinationAddress")).GetAttribute("value"));


                s.GoToWallet(new WalletId(storeId.storeId, "BTC"), WalletsNavPages.Settings);

                s.Driver.FindElement(By.Id("SettingsMenu")).ForceClick();
                s.Driver.FindElement(By.CssSelector("button[value=view-seed]")).Click();
                s.AssertHappyMessage();
                Assert.Equal(mnemonic.ToString(), s.Driver.FindElements(By.ClassName("alert-success")).First().FindElement(By.TagName("code")).Text);
            }
        }
예제 #18
0
        public async Task CanUseEthereum()
        {
            using var s = SeleniumTester.Create("ETHEREUM", true);
            s.Server.ActivateETH();
            await s.StartAsync();

            s.RegisterNewUser(true);

            IWebElement syncSummary = null;

            TestUtils.Eventually(() =>
            {
                syncSummary = s.Driver.FindElement(By.Id("modalDialog"));
                Assert.True(syncSummary.Displayed);
            });
            var web3Link = syncSummary.FindElement(By.LinkText("Configure Web3"));

            web3Link.Click();
            s.Driver.FindElement(By.Id("Web3ProviderUrl")).SendKeys("https://ropsten-rpc.linkpool.io");
            s.Driver.FindElement(By.Id("saveButton")).Click();
            s.AssertHappyMessage();
            TestUtils.Eventually(() =>
            {
                s.Driver.Navigate().Refresh();
                s.Driver.AssertElementNotFound(By.Id("modalDialog"));
            });

            var store = s.CreateNewStore();

            s.Driver.FindElement(By.LinkText("Ethereum")).Click();

            var seed = new Mnemonic(Wordlist.English);

            s.Driver.FindElement(By.Id("ModifyETH")).Click();
            s.Driver.FindElement(By.Id("Seed")).SendKeys(seed.ToString());
            s.SetCheckbox(s.Driver.FindElement(By.Id("StoreSeed")), true);
            s.SetCheckbox(s.Driver.FindElement(By.Id("Enabled")), true);
            s.Driver.FindElement(By.Id("SaveButton")).Click();
            s.AssertHappyMessage();
            s.Driver.FindElement(By.Id("ModifyUSDT20")).Click();
            s.Driver.FindElement(By.Id("Seed")).SendKeys(seed.ToString());
            s.SetCheckbox(s.Driver.FindElement(By.Id("StoreSeed")), true);
            s.SetCheckbox(s.Driver.FindElement(By.Id("Enabled")), true);
            s.Driver.FindElement(By.Id("SaveButton")).Click();
            s.AssertHappyMessage();

            var invoiceId = s.CreateInvoice(store.storeName, 10);

            s.GoToInvoiceCheckout(invoiceId);
            var currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));

            Assert.Contains("ETH", currencyDropdownButton.Text);
            s.Driver.FindElement(By.Id("copy-tab")).Click();

            var ethAddress = s.Driver.FindElements(By.ClassName("copySectionBox"))
                             .Single(element => element.FindElement(By.TagName("label")).Text
                                     .Contains("Address", StringComparison.InvariantCultureIgnoreCase)).FindElement(By.TagName("input"))
                             .GetAttribute("value");

            currencyDropdownButton.Click();
            var elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem"));

            Assert.Equal(2, elements.Count);

            elements.Single(element => element.Text.Contains("USDT20")).Click();
            s.Driver.FindElement(By.Id("copy-tab")).Click();
            var usdtAddress = s.Driver.FindElements(By.ClassName("copySectionBox"))
                              .Single(element => element.FindElement(By.TagName("label")).Text
                                      .Contains("Address", StringComparison.InvariantCultureIgnoreCase)).FindElement(By.TagName("input"))
                              .GetAttribute("value");

            Assert.Equal(usdtAddress, ethAddress);
        }
예제 #19
0
        public async Task CanCreateApiKeys()
        {
            //there are 2 ways to create api keys:
            //as a user through your profile
            //as an external application requesting an api key from a user

            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                var tester = s.Server;

                var user = tester.NewAccount();
                user.GrantAccess();
                await user.MakeAdmin(false);

                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();

                //not an admin, so this permission should not show
                Assert.DoesNotContain("btcpay.server.canmodifyserversettings", s.Driver.PageSource);
                await user.MakeAdmin();

                s.Logout();
                s.GoToLogin();
                s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
                s.GoToProfile(ManageNavPages.APIKeys);
                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                Assert.Contains("btcpay.server.canmodifyserversettings", s.Driver.PageSource);

                //server management should show now
                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true);
                s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true);
                s.SetCheckbox(s, "btcpay.user.canviewprofile", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var superApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;

                //this api key has access to everything
                await TestApiAgainstAccessToken(superApiKey, tester, user, Policies.CanModifyServerSettings, Policies.CanModifyStoreSettings, Policies.CanViewProfile);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var serverOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
                                                Policies.CanModifyServerSettings);


                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true);
                s.Driver.FindElement(By.Id("Generate")).Click();
                var allStoreOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user,
                                                Policies.CanModifyStoreSettings);

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.CssSelector("button[value='btcpay.store.canmodifystoresettings:change-store-mode']")).Click();
                //there should be a store already by default in the dropdown
                var dropdown = s.Driver.FindElement(By.Name("PermissionValues[2].SpecificStores[0]"));
                var option   = dropdown.FindElement(By.TagName("option"));
                var storeId  = option.GetAttribute("value");
                option.Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var selectiveStoreApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user,
                                                Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString());

                s.Driver.FindElement(By.Id("AddApiKey")).Click();
                s.Driver.FindElement(By.Id("Generate")).Click();
                var noPermissionsApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
                await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user);

                await Assert.ThrowsAnyAsync <HttpRequestException>(async() =>
                {
                    await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id",
                                                           tester.PayTester.HttpClient);
                });


                //let's test the authorized screen now
                //options for authorize are:
                //applicationName
                //redirect
                //permissions
                //strict
                //selectiveStores
                var authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                      new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }).ToString();
                s.Driver.Navigate().GoToUrl(authUrl);
                s.Driver.PageSource.Contains("kukksappname");
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());
                Assert.DoesNotContain("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                var url = s.Driver.Url;
                IEnumerable <KeyValuePair <string, string> > results = url.Split("?").Last().Split("&")
                                                                       .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1]));

                var apiKeyRepo = s.Server.PayTester.GetService <APIKeyRepository>();

                await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user,
                                                (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetBlob().Permissions);

                authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                  new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true).ToString();

                s.Driver.Navigate().GoToUrl(authUrl);
                Assert.DoesNotContain("kukksappname", s.Driver.PageSource);

                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());

                s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", false);
                Assert.Contains("change-store-mode", s.Driver.PageSource);
                s.Driver.FindElement(By.Id("consent-yes")).Click();
                url     = s.Driver.Url;
                results = url.Split("?").Last().Split("&")
                          .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1]));

                await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user,
                                                (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetBlob().Permissions);
            }
        }
예제 #20
0
        public async Task CanManageWallet()
        {
            using (var s = SeleniumTester.Create())
            {
                await s.StartAsync();

                s.RegisterNewUser(true);
                var storeId = s.CreateNewStore();

                // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed
                // to sign the transaction
                s.GenerateWallet("BTC", "", true, false);

                //let's test quickly the receive wallet page
                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.Driver.FindElement(By.Id("WalletSend")).Click();
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                //you cant use the Sign with NBX option without saving private keys when generating the wallet.
                Assert.DoesNotContain("nbx-seed", s.Driver.PageSource);

                s.Driver.FindElement(By.Id("WalletReceive")).Click();
                //generate a receiving address
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.True(s.Driver.FindElement(By.ClassName("qr-container")).Displayed);
                var receiveAddr = s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value");
                //unreserve
                s.Driver.FindElement(By.CssSelector("button[value=unreserve-current-address]")).Click();
                //generate it again, should be the same one as before as nothign got used in the meantime
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.True(s.Driver.FindElement(By.ClassName("qr-container")).Displayed);
                Assert.Equal(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));

                //send money to addr and ensure it changed

                var sess = await s.Server.ExplorerClient.CreateWebsocketNotificationSessionAsync();

                sess.ListenAllTrackedSource();
                var nextEvent = sess.NextEventAsync();
                s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(receiveAddr, Network.RegTest),
                                                    Money.Parse("0.1"));
                await nextEvent;
                await Task.Delay(200);

                s.Driver.Navigate().Refresh();
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));
                receiveAddr = s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value");
                //change the wallet and ensure old address is not there and generating a new one does not result in the prev one
                s.GoToStore(storeId.storeId);
                s.GenerateWallet("BTC", "", true, false);
                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();
                s.Driver.FindElement(By.Id("WalletReceive")).Click();
                s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
                Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("vue-address")).GetAttribute("value"));


                var invoiceId = s.CreateInvoice(storeId.storeId);
                var invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                var address = invoice.EntityToDTO().Addresses["BTC"];


                //wallet should have been imported to bitcoin core wallet in watch only mode.
                var result = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                Assert.True(result.IsWatchOnly);
                s.GoToStore(storeId.storeId);
                var mnemonic = s.GenerateWallet("BTC", "", true, true);

                //lets import and save private keys
                var root = new Mnemonic(mnemonic).DeriveExtKey();
                invoiceId = s.CreateInvoice(storeId.storeId);
                invoice   = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);

                address = invoice.EntityToDTO().Addresses["BTC"];
                result  = await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));

                //spendable from bitcoin core wallet!
                Assert.False(result.IsWatchOnly);
                var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(address, Network.RegTest), Money.Coins(3.0m));
                s.Server.ExplorerNode.Generate(1);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();

                s.ClickOnAllSideMenus();

                // Make sure we can rescan, because we are admin!
                s.Driver.FindElement(By.Id("WalletRescan")).ForceClick();
                Assert.Contains("The batch size make sure", s.Driver.PageSource);

                // We setup the fingerprint and the account key path
                s.Driver.FindElement(By.Id("WalletSettings")).ForceClick();
//                s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160");
//                s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter);

                // Check the tx sent earlier arrived
                s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick();
                var walletTransactionLink = s.Driver.Url;
                Assert.Contains(tx.ToString(), s.Driver.PageSource);


                void SignWith(string signingSource)
                {
                    // Send to bob
                    s.Driver.FindElement(By.Id("WalletSend")).Click();
                    var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);

                    SetTransactionOutput(0, bob, 1);
                    s.Driver.ScrollTo(By.Id("SendMenu"));
                    s.Driver.FindElement(By.Id("SendMenu")).ForceClick();
                    s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click();

                    // Input the seed
                    s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter);

                    // Broadcast
                    Assert.Contains(bob.ToString(), s.Driver.PageSource);
                    Assert.Contains("1.00000000", s.Driver.PageSource);
                    s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                    Assert.Equal(walletTransactionLink, s.Driver.Url);
                }

                void SetTransactionOutput(int index, BitcoinAddress dest, decimal amount, bool subtract = false)
                {
                    s.Driver.FindElement(By.Id($"Outputs_{index}__DestinationAddress")).SendKeys(dest.ToString());
                    var amountElement = s.Driver.FindElement(By.Id($"Outputs_{index}__Amount"));

                    amountElement.Clear();
                    amountElement.SendKeys(amount.ToString());
                    var checkboxElement = s.Driver.FindElement(By.Id($"Outputs_{index}__SubtractFeesFromOutput"));

                    if (checkboxElement.Selected != subtract)
                    {
                        checkboxElement.Click();
                    }
                }

                SignWith(mnemonic);

                s.Driver.FindElement(By.Id("Wallets")).Click();
                s.Driver.FindElement(By.LinkText("Manage")).Click();
                s.Driver.FindElement(By.Id("WalletSend")).Click();

                var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
                SetTransactionOutput(0, jack, 0.01m);
                s.Driver.ScrollTo(By.Id("SendMenu"));
                s.Driver.FindElement(By.Id("SendMenu")).ForceClick();

                s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click();
                Assert.Contains(jack.ToString(), s.Driver.PageSource);
                Assert.Contains("0.01000000", s.Driver.PageSource);
                s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick();
                Assert.Equal(walletTransactionLink, s.Driver.Url);
            }
        }