コード例 #1
0
        public async Task ServerInfoControllerTests()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

                var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri);
                await AssertHttpError(401, async() => await unauthClient.GetServerInfo());

                var user = tester.NewAccount();
                user.GrantAccess();
                var clientBasic = await user.CreateClient();

                var serverInfoData = await clientBasic.GetServerInfo();

                Assert.NotNull(serverInfoData);
                Assert.NotNull(serverInfoData.Version);
                Assert.NotNull(serverInfoData.Onion);
                Assert.True(serverInfoData.FullySynched);
                Assert.Contains("BTC", serverInfoData.SupportedPaymentMethods);
                Assert.Contains("BTC_LightningLike", serverInfoData.SupportedPaymentMethods);
                Assert.NotNull(serverInfoData.SyncStatus);
                Assert.Single(serverInfoData.SyncStatus.Select(s => s.CryptoCode == "BTC"));
            }
        }
コード例 #2
0
        public async Task UsersControllerTests()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

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

                string apiKeyProfile = await GenerateAPIKey(tester, user, Permissions.ProfileManagement);

                string apiKeyInsufficient = await GenerateAPIKey(tester, user, Permissions.StoreManagement);

                var clientProfile      = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyProfile);
                var clientInsufficient = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyInsufficient);

                var apiKeyProfileUserData = await clientProfile.GetCurrentUser();

                Assert.NotNull(apiKeyProfileUserData);
                Assert.Equal(apiKeyProfileUserData.Id, user.UserId);
                Assert.Equal(apiKeyProfileUserData.Email, user.RegisterDetails.Email);

                await Assert.ThrowsAsync <HttpRequestException>(async() => await clientInsufficient.GetCurrentUser());
            }
        }
コード例 #3
0
        public async Task ApiKeysControllerTests()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

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

                string apiKey = await GenerateAPIKey(tester, user, Permissions.ServerManagement, Permissions.StoreManagement);

                var client = new BTCPayServerClient(tester.PayTester.ServerUri, apiKey);
                //Get current api key
                var apiKeyData = await client.GetCurrentAPIKeyInfo();

                Assert.NotNull(apiKeyData);
                Assert.Equal(apiKey, apiKeyData.ApiKey);
                Assert.Equal(user.UserId, apiKeyData.UserId);
                Assert.Equal(2, apiKeyData.Permissions.Length);

                //revoke current api key
                await client.RevokeCurrentAPIKeyInfo();

                await Assert.ThrowsAsync <HttpRequestException>(async() =>
                {
                    await client.GetCurrentAPIKeyInfo();
                });
            }
        }
コード例 #4
0
    public async Task <IActionResult> InitiatePayment(PaymentMethodId paymentMethodId, string[] payoutIds)
    {
        await using var ctx = this._dbContextFactory.CreateContext();
        ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        var pmi = paymentMethodId.ToString();

        var payouts = await ctx.Payouts.Include(data => data.PullPaymentData)
                      .Where(data => payoutIds.Contains(data.Id) &&
                             pmi == data.PaymentMethodId &&
                             data.State == PayoutState.AwaitingPayment)
                      .ToListAsync();

        var           pullPaymentIds = payouts.Select(data => data.PullPaymentDataId).Distinct().Where(s => s != null).ToArray();
        var           storeId        = payouts.First().StoreDataId;
        var           network        = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(paymentMethodId.CryptoCode);
        List <string> bip21          = new List <string>();

        foreach (var payout in payouts)
        {
            if (payout.Proof != null)
            {
                continue;
            }
            var blob = payout.GetBlob(_jsonSerializerSettings);
            if (payout.GetPaymentMethodId() != paymentMethodId)
            {
                continue;
            }
            var claim = await ParseClaimDestination(paymentMethodId, blob.Destination);

            switch (claim.destination)
            {
            case UriClaimDestination uriClaimDestination:
                uriClaimDestination.BitcoinUrl.Amount = new Money(blob.CryptoAmount.Value, MoneyUnit.BTC);
                var newUri = new UriBuilder(uriClaimDestination.BitcoinUrl.Uri);
                BTCPayServerClient.AppendPayloadToQuery(newUri, new KeyValuePair <string, object>("payout", payout.Id));
                bip21.Add(newUri.Uri.ToString());
                break;

            case AddressClaimDestination addressClaimDestination:
                var bip21New = network.GenerateBIP21(addressClaimDestination.Address.ToString(), new Money(blob.CryptoAmount.Value, MoneyUnit.BTC));
                bip21New.QueryParams.Add("payout", payout.Id);
                bip21.Add(bip21New.ToString());
                break;
            }
        }
        if (bip21.Any())
        {
            return(new RedirectToActionResult("WalletSend", "UIWallets", new { walletId = new WalletId(storeId, paymentMethodId.CryptoCode).ToString(), bip21 }));
        }
        return(new RedirectToActionResult("Payouts", "UIWallets", new
        {
            walletId = new WalletId(storeId, paymentMethodId.CryptoCode).ToString(),
            pullPaymentId = pullPaymentIds.Length == 1 ? pullPaymentIds.First() : null
        }));
    }
コード例 #5
0
        private string GetRedirectToApplicationUrl(Uri redirect, APIKeyData key)
        {
            var uri         = new UriBuilder(redirect);
            var permissions = key.GetBlob().Permissions;

            BTCPayServerClient.AppendPayloadToQuery(uri,
                                                    new Dictionary <string, object>()
            {
                { "key", key.Id }, { "permissions", permissions }, { "user", key.UserId }
            });
            return(uri.Uri.AbsoluteUri);
        }
コード例 #6
0
 public BTCPayService(string endpoint, string storeId, string apiKey, ILogger <BTCPayService> logger)
 {
     if (apiKey == null || storeId == null || endpoint == null)
     {
         logger.LogWarning("BTCPay Server settings missing, cannot instantiate BTCPayService.");
     }
     else
     {
         _storeId = storeId;
         _baseUri = new Uri(endpoint);
         _client  = new BTCPayServerClient(_baseUri, apiKey);
     }
 }
コード例 #7
0
        public async Task HealthControllerTests()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

                var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri);

                var apiHealthData = await unauthClient.GetHealth();

                Assert.NotNull(apiHealthData);
                Assert.True(apiHealthData.Synchronized);
            }
        }
コード例 #8
0
        public async Task SpecificCanModifyStoreCantCreateNewStore()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

                var acc = tester.NewAccount();
                await acc.GrantAccessAsync();

                var unrestricted = await acc.CreateClient();

                var response = await unrestricted.CreateStore(new CreateStoreRequest()
                {
                    Name = "mystore"
                });

                var apiKey     = (await unrestricted.CreateAPIKey(new CreateApiKeyRequest()
                {
                    Permissions = new[] { Permission.Create("btcpay.store.canmodifystoresettings", response.Id) }
                })).ApiKey;
                var restricted = new BTCPayServerClient(unrestricted.Host, apiKey);

                // Unscoped permission should be required for create store
                await this.AssertHttpError(403, async() => await restricted.CreateStore(new CreateStoreRequest()
                {
                    Name = "store2"
                }));

                // Unrestricted should work fine
                await unrestricted.CreateStore(new CreateStoreRequest()
                {
                    Name = "store2"
                });

                // Restricted but unscoped should work fine
                apiKey     = (await unrestricted.CreateAPIKey(new CreateApiKeyRequest()
                {
                    Permissions = new[] { Permission.Create("btcpay.store.canmodifystoresettings") }
                })).ApiKey;
                restricted = new BTCPayServerClient(unrestricted.Host, apiKey);
                await restricted.CreateStore(new CreateStoreRequest()
                {
                    Name = "store2"
                });
            }
        }
コード例 #9
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, Permissions.ServerManagement,
                                                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,
                                                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,
                                                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,
                                                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
                var authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                      new[] { Permissions.StoreManagement, Permissions.ServerManagement }).ToString();
                s.Driver.Navigate().GoToUrl(authUrl);
                s.Driver.PageSource.Contains("kukksappname");
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("hidden", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("ServerManagementPermission")).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)).GetPermissions());

                authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
                                                                  new[] { Permissions.StoreManagement, Permissions.ServerManagement }, false, true).ToString();

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

                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("value").ToLowerInvariant());
                Assert.Equal("checkbox", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("type").ToLowerInvariant());
                Assert.Equal("true", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("value").ToLowerInvariant());

                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());
            }
        }
コード例 #10
0
 public TestApiKeyController(UserManager <ApplicationUser> userManager, StoreRepository storeRepository, BTCPayServerClient localBTCPayServerClient)
 {
     _userManager             = userManager;
     _storeRepository         = storeRepository;
     _localBTCPayServerClient = localBTCPayServerClient;
 }
コード例 #11
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 = CreateSeleniumTester();
            await s.StartAsync();

            var tester = s.Server;

            var user = tester.NewAccount();
            await user.GrantAccessAsync();

            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();

            TestLogs.LogInformation("Checking admin permissions");
            //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.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), true);
            s.Driver.SetCheckbox(By.Id("btcpay.store.canmodifystoresettings"), true);
            s.Driver.SetCheckbox(By.Id("btcpay.user.canviewprofile"), true);
            s.Driver.FindElement(By.Id("Generate")).Click();
            var superApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

            TestLogs.LogInformation("Checking super admin key");

            //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.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), true);
            s.Driver.FindElement(By.Id("Generate")).Click();
            var serverOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

            TestLogs.LogInformation("Checking CanModifyServerSettings permissions");

            await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
                                            Policies.CanModifyServerSettings);

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

            TestLogs.LogInformation("Checking CanModifyStoreSettings permissions");

            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 getPermissionValueIndex =
                s.Driver.FindElement(By.CssSelector("input[value='btcpay.store.canmodifystoresettings']"))
                .GetAttribute("name")
                .Replace(".Permission", ".SpecificStores[0]");
            var dropdown = s.Driver.FindElement(By.Name(getPermissionValueIndex));
            var option   = dropdown.FindElement(By.TagName("option"));
            var storeId  = option.GetAttribute("value");

            option.Click();
            s.Driver.WaitForAndClick(By.Id("Generate"));
            var selectiveStoreApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

            TestLogs.LogInformation("Checking CanModifyStoreSettings with StoreId permissions");

            await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user,
                                            Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString());

            TestLogs.LogInformation("Adding API key for no permissions");
            s.Driver.WaitForAndClick(By.Id("AddApiKey"));
            TestLogs.LogInformation("Generating API key for no permissions");
            s.Driver.WaitForAndClick(By.Id("Generate"));
            var noPermissionsApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

            TestLogs.LogInformation($"Checking no permissions: {noPermissionsApiKey}");
            await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user);

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

            TestLogs.LogInformation("Checking authorize screen");

            //let's test the authorized screen now
            //options for authorize are:
            //applicationName
            //redirect
            //permissions
            //strict
            //selectiveStores
            //redirect
            //appidentifier
            var appidentifier = "testapp";
            var callbackUrl   = s.ServerUri + "postredirect-callback-test";
            var authUrl       = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
                                                                        new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();

            TestLogs.LogInformation($"Going to auth URL {authUrl}");
            s.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);

            TestLogs.LogInformation("Going to callback URL");

            s.Driver.WaitForAndClick(By.Id("consent-yes"));
            Assert.Equal(callbackUrl, s.Driver.Url);
            TestLogs.LogInformation("On callback URL");

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

            TestLogs.LogInformation($"Access token: {accessToken}");

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

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

            TestLogs.LogInformation($"Going to auth URL 2 {authUrl}");
            s.GoToUrl(authUrl);
            TestLogs.LogInformation("On auth URL 2");
            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.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), false);
            Assert.Contains("change-store-mode", s.Driver.PageSource);

            TestLogs.LogInformation("Going to callback URL 2");
            s.Driver.WaitForAndClick(By.Id("consent-yes"));
            Assert.Equal(callbackUrl, s.Driver.Url);
            TestLogs.LogInformation("On callback URL 2");

            accessToken = GetAccessTokenFromCallbackResult(s.Driver);
            TestLogs.LogInformation($"Access token: {accessToken}");
            TestLogs.LogInformation("Checking authorized permissions");

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

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

            //if it's the same, go to the confirm page
            TestLogs.LogInformation($"Going to auth URL 3 {authUrl}");
            s.GoToUrl(authUrl);
            TestLogs.LogInformation("On auth URL 3");
            s.Driver.WaitForAndClick(By.Id("continue"));
            TestLogs.LogInformation("Going to callback URL 3");
            Assert.Equal(callbackUrl, s.Driver.Url);
            TestLogs.LogInformation("On callback URL 3");

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

            TestLogs.LogInformation($"Going to auth URL 4 {authUrl}");
            s.GoToUrl(authUrl);
            TestLogs.LogInformation("On auth URL 4");
            Assert.False(s.Driver.Url.StartsWith("https://international.com/callback"));

            // Make sure we can check all permissions when not an admin
            TestLogs.LogInformation("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);
            TestLogs.LogInformation("Go to API Keys page");
            s.GoToUrl("/account/apikeys");
            TestLogs.LogInformation("On API Keys page");
            s.Driver.WaitForAndClick(By.Id("AddApiKey"));
            int checkedPermissionCount = s.Driver.FindElements(By.ClassName("form-check-input")).Count;

            TestLogs.LogInformation($"Adding API key: {checkedPermissionCount} permissions");
            s.Driver.ExecuteJavaScript("document.querySelectorAll('#Permissions .form-check-input').forEach(i => i.click())");
            TestLogs.LogInformation($"Clicked {checkedPermissionCount}");

            TestLogs.LogInformation("Generating API key");
            s.Driver.WaitForAndClick(By.Id("Generate"));
            var allAPIKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;

            TestLogs.LogInformation($"Checking API key permissions: {allAPIKey}");
            var apikeydata = await TestApiAgainstAccessToken <ApiKeyData>(allAPIKey, "api/v1/api-keys/current", tester.PayTester.HttpClient);

            Assert.Equal(checkedPermissionCount, apikeydata.Permissions.Length);
        }
コード例 #12
0
        public async Task CanCreateUsersViaAPI()
        {
            using (var tester = ServerTester.Create(newDb: true))
            {
                tester.PayTester.DisableRegistration = true;
                await tester.StartAsync();

                var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri);
                await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()));
                await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**"
                }));

                // Pass too simple
                await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                }));

                // We have no admin, so it should work
                var user1 = await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                });

                // We have no admin, so it should work
                var user2 = await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                });

                // Duplicate email
                await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                }));

                // Let's make an admin
                var admin = await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******", IsAdministrator = true
                });

                // Creating a new user without proper creds is now impossible (unauthorized)
                // Because if registration are locked and that an admin exists, we don't accept unauthenticated connection
                await AssertHttpError(401, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                }));


                // But should be ok with subscriptions unlocked
                var settings = tester.PayTester.GetService <SettingsRepository>();
                await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings()
                {
                    LockSubscription = false
                });

                await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                });

                // But it should be forbidden to create an admin without being authenticated
                await AssertHttpError(403, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******", IsAdministrator = true
                }));

                await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings()
                {
                    LockSubscription = true
                });

                var adminAcc = tester.NewAccount();
                adminAcc.UserId  = admin.Id;
                adminAcc.IsAdmin = true;
                var adminClient = await adminAcc.CreateClient(Policies.CanModifyProfile);

                // We should be forbidden to create a new user without proper admin permissions
                await AssertHttpError(403, async() => await adminClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                }));
                await AssertHttpError(403, async() => await adminClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******", IsAdministrator = true
                }));

                // However, should be ok with the unrestricted permissions of an admin
                adminClient = await adminAcc.CreateClient(Policies.Unrestricted);

                await adminClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                });

                // Even creating new admin should be ok
                await adminClient.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******", IsAdministrator = true
                });

                var user1Acc = tester.NewAccount();
                user1Acc.UserId  = user1.Id;
                user1Acc.IsAdmin = false;
                var user1Client = await user1Acc.CreateClient(Policies.CanModifyServerSettings);

                // User1 trying to get server management would still fail to create user
                await AssertHttpError(403, async() => await user1Client.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                }));

                // User1 should be able to create user if subscription unlocked
                await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings()
                {
                    LockSubscription = false
                });

                await user1Client.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******"
                });

                // But not an admin
                await AssertHttpError(403, async() => await user1Client.CreateUser(new CreateApplicationUserRequest()
                {
                    Email = "*****@*****.**", Password = "******", IsAdministrator = true
                }));
            }
        }
コード例 #13
0
        public async Task CanUsePullPaymentViaAPI()
        {
            using (var tester = ServerTester.Create())
            {
                await tester.StartAsync();

                var acc = tester.NewAccount();
                acc.Register();
                acc.CreateStore();
                var storeId = (await acc.RegisterDerivationSchemeAsync("BTC", importKeysToNBX: true)).StoreId;
                var client  = await acc.CreateClient();

                var result = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest()
                {
                    Name           = "Test",
                    Amount         = 12.3m,
                    Currency       = "BTC",
                    PaymentMethods = new[] { "BTC" }
                });

                void VerifyResult()
                {
                    Assert.Equal("Test", result.Name);
                    Assert.Null(result.Period);
                    // If it contains ? it means that we are resolving an unknown route with the link generator
                    Assert.DoesNotContain("?", result.ViewLink);
                    Assert.False(result.Archived);
                    Assert.Equal("BTC", result.Currency);
                    Assert.Equal(12.3m, result.Amount);
                }

                VerifyResult();

                var unauthenticated = new BTCPayServerClient(tester.PayTester.ServerUri);
                result = await unauthenticated.GetPullPayment(result.Id);

                VerifyResult();
                await AssertHttpError(404, async() => await unauthenticated.GetPullPayment("lol"));

                // Can't list pull payments unauthenticated
                await AssertHttpError(401, async() => await unauthenticated.GetPullPayments(storeId));

                var pullPayments = await client.GetPullPayments(storeId);

                result = Assert.Single(pullPayments);
                VerifyResult();

                Thread.Sleep(1000);
                var test2 = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest()
                {
                    Name           = "Test 2",
                    Amount         = 12.3m,
                    Currency       = "BTC",
                    PaymentMethods = new[] { "BTC" }
                });

                Logs.Tester.LogInformation("Can't archive without knowing the walletId");
                await Assert.ThrowsAsync <HttpRequestException>(async() => await client.ArchivePullPayment("lol", result.Id));

                Logs.Tester.LogInformation("Can't archive without permission");
                await Assert.ThrowsAsync <HttpRequestException>(async() => await unauthenticated.ArchivePullPayment(storeId, result.Id));

                await client.ArchivePullPayment(storeId, result.Id);

                result = await unauthenticated.GetPullPayment(result.Id);

                Assert.True(result.Archived);
                var pps = await client.GetPullPayments(storeId);

                result = Assert.Single(pps);
                Assert.Equal("Test 2", result.Name);
                pps = await client.GetPullPayments(storeId, true);

                Assert.Equal(2, pps.Length);
                Assert.Equal("Test 2", pps[0].Name);
                Assert.Equal("Test", pps[1].Name);

                var payouts = await unauthenticated.GetPayouts(pps[0].Id);

                Assert.Empty(payouts);

                var destination = (await tester.ExplorerNode.GetNewAddressAsync()).ToString();
                await this.AssertAPIError("overdraft", async() => await unauthenticated.CreatePayout(pps[0].Id, new CreatePayoutRequest()
                {
                    Destination   = destination,
                    Amount        = 1_000_000m,
                    PaymentMethod = "BTC",
                }));
コード例 #14
0
        public async Task <ApplicationUserData> GetUserDataForApiKey(string userApiKey)
        {
            var client = new BTCPayServerClient(_baseUri, userApiKey);

            return(await client.GetCurrentUser());
        }
コード例 #15
0
ファイル: ApiKeysTests.cs プロジェクト: zaowens/btcpayserver
        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[3].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
                //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"));
            }
        }