Beispiel #1
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);
        }
Beispiel #2
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());
            }
        }
Beispiel #3
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[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"));
            }
        }