Fix selective stores case

This commit is contained in:
Dennis Reimann
2022-06-28 16:58:03 +02:00
committed by Andrew Camilleri
parent 1bb35bf545
commit eef7539c2d
3 changed files with 46 additions and 18 deletions

View File

@@ -128,11 +128,17 @@ namespace BTCPayServer.Tests
// No upfront store selection with only server settings // No upfront store selection with only server settings
s.GoToUrl(authUrl); s.GoToUrl(authUrl);
Assert.Contains(appidentifier, s.Driver.PageSource); Assert.Contains(appidentifier, s.Driver.PageSource);
Assert.False(s.Driver.FindElement(By.Id("StoreId")).Displayed); Assert.True(s.Driver.ElementDoesNotExist(By.CssSelector("select#StoreId")));
// No upfront store selection with selectiveStores being false
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, selectiveStores: false, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
s.GoToUrl(authUrl);
Assert.True(s.Driver.ElementDoesNotExist(By.CssSelector("select#StoreId")));
// Now with store settings // Now with store settings
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString(); new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, selectiveStores: true, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
s.GoToUrl(authUrl); s.GoToUrl(authUrl);
Assert.Contains(appidentifier, s.Driver.PageSource); Assert.Contains(appidentifier, s.Driver.PageSource);
@@ -156,7 +162,7 @@ namespace BTCPayServer.Tests
(await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions); (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions);
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, applicationDetails: (null, new Uri(callbackUrl))).ToString(); new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (null, new Uri(callbackUrl))).ToString();
s.GoToUrl(authUrl); s.GoToUrl(authUrl);
Assert.DoesNotContain("kukksappname", s.Driver.PageSource); Assert.DoesNotContain("kukksappname", s.Driver.PageSource);
@@ -186,6 +192,12 @@ namespace BTCPayServer.Tests
//if it's the same, go to the confirm page //if it's the same, go to the confirm page
s.GoToUrl(authUrl); s.GoToUrl(authUrl);
// Select the same store
select = new SelectElement(s.Driver.FindElement(By.Id("StoreId")));
select.SelectByIndex(0);
s.Driver.FindElement(By.Id("continue")).Click();
Assert.Contains("previously generated the API Key", s.Driver.PageSource); Assert.Contains("previously generated the API Key", s.Driver.PageSource);
s.Driver.WaitForAndClick(By.Id("continue")); s.Driver.WaitForAndClick(By.Id("continue"));
Assert.Equal(callbackUrl, s.Driver.Url); Assert.Equal(callbackUrl, s.Driver.Url);
@@ -195,6 +207,12 @@ namespace BTCPayServer.Tests
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString(); new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString();
s.GoToUrl(authUrl); s.GoToUrl(authUrl);
// Select the same store
select = new SelectElement(s.Driver.FindElement(By.Id("StoreId")));
select.SelectByIndex(0);
s.Driver.FindElement(By.Id("continue")).Click();
Assert.DoesNotContain("previously generated the API Key", s.Driver.PageSource); Assert.DoesNotContain("previously generated the API Key", s.Driver.PageSource);
Assert.False(s.Driver.Url.StartsWith("https://international.com/callback")); Assert.False(s.Driver.Url.StartsWith("https://international.com/callback"));

View File

@@ -174,6 +174,16 @@ retry:
driver.WaitUntilAvailable(selector); driver.WaitUntilAvailable(selector);
driver.FindElement(selector).Click(); driver.FindElement(selector).Click();
} }
public static bool ElementDoesNotExist(this IWebDriver driver, By selector)
{
Assert.Throws<NoSuchElementException>(() =>
{
driver.FindElement(selector);
});
return true;
}
public static void SetCheckbox(this IWebDriver driver, By selector, bool value) public static void SetCheckbox(this IWebDriver driver, By selector, bool value)
{ {

View File

@@ -115,7 +115,7 @@ namespace BTCPayServer.Controllers
ApplicationIdentifier = applicationIdentifier ApplicationIdentifier = applicationIdentifier
}; };
var existingApiKey = await CheckForMatchingApiKey(applicationIdentifier, redirect, requestPermissions, strict); var existingApiKey = await CheckForMatchingApiKey(requestPermissions, vm);
if (existingApiKey != null) if (existingApiKey != null)
{ {
vm.ApiKey = existingApiKey.Id; vm.ApiKey = existingApiKey.Id;
@@ -204,7 +204,7 @@ namespace BTCPayServer.Controllers
default: default:
var requestPermissions = Permission.ToPermissions(viewModel.Permissions?.Split(';').ToArray()).ToList(); var requestPermissions = Permission.ToPermissions(viewModel.Permissions?.Split(';').ToArray()).ToList();
var existingApiKey = await CheckForMatchingApiKey(viewModel.ApplicationIdentifier, viewModel.RedirectUrl, requestPermissions, viewModel.Strict); var existingApiKey = await CheckForMatchingApiKey(requestPermissions, viewModel);
if (existingApiKey != null) if (existingApiKey != null)
{ {
viewModel.ApiKey = existingApiKey.Id; viewModel.ApiKey = existingApiKey.Id;
@@ -241,10 +241,9 @@ namespace BTCPayServer.Controllers
return RedirectToAction("APIKeys"); return RedirectToAction("APIKeys");
} }
private async Task<APIKeyData> CheckForMatchingApiKey(string applicationIdentifier, Uri redirect, private async Task<APIKeyData> CheckForMatchingApiKey(IEnumerable<Permission> requestedPermissions, AuthorizeApiKeysViewModel vm)
IEnumerable<Permission> requestPermissions, bool strict)
{ {
if (string.IsNullOrEmpty(applicationIdentifier) || redirect == null) if (string.IsNullOrEmpty(vm.ApplicationIdentifier) || vm.RedirectUrl == null)
{ {
return null; return null;
} }
@@ -257,28 +256,29 @@ namespace BTCPayServer.Controllers
foreach (var key in keys) foreach (var key in keys)
{ {
var blob = key.GetBlob(); var blob = key.GetBlob();
if (blob.ApplicationIdentifier != applicationIdentifier || blob.ApplicationAuthority != redirect.AbsoluteUri) if (blob.ApplicationIdentifier != vm.ApplicationIdentifier || blob.ApplicationAuthority != vm.RedirectUrl.AbsoluteUri)
{ {
continue; continue;
} }
var requestedGrouped = requestedPermissions.GroupBy(permission => permission.Policy);
var existingGrouped = Permission.ToPermissions(blob.Permissions).GroupBy(permission => permission.Policy);
//matched the identifier and authority, but we need to check if what the app is requesting in terms of permissions is enough //matched the identifier and authority, but we need to check if what the app is requesting in terms of permissions is enough
var alreadyPresentPermissions = Permission.ToPermissions(blob.Permissions)
.GroupBy(permission => permission.Policy);
var fail = false; var fail = false;
foreach (var permission in requestPermissions.GroupBy(permission => permission.Policy)) foreach (var requested in requestedGrouped)
{ {
var presentPermission = var existing = existingGrouped.SingleOrDefault(grouping => requested.Key == grouping.Key);
alreadyPresentPermissions.SingleOrDefault(grouping => permission.Key == grouping.Key); if (vm.Strict && existing == null)
if (strict && presentPermission == null)
{ {
fail = true; fail = true;
break; break;
} }
if (Policies.IsStorePolicy(permission.Key)) if (Policies.IsStorePolicy(requested.Key))
{ {
if (presentPermission.Any(permission1 => !string.IsNullOrEmpty(permission1.Scope))) if ((vm.SelectiveStores && !existing.Any(p => p.Scope == vm.StoreId)) ||
(!vm.SelectiveStores && existing.Any(p => !string.IsNullOrEmpty(p.Scope))) )
{ {
fail = true; fail = true;
break; break;
@@ -303,7 +303,7 @@ namespace BTCPayServer.Controllers
var permissions = vm.Permissions?.Split(';') ?? Array.Empty<string>(); var permissions = vm.Permissions?.Split(';') ?? Array.Empty<string>();
var permissionsWithStoreIDs = new List<string>(); var permissionsWithStoreIDs = new List<string>();
vm.NeedsStorePermission = permissions.Any(Policies.IsStorePolicy) || !vm.Strict; vm.NeedsStorePermission = vm.SelectiveStores && (permissions.Any(Policies.IsStorePolicy) || !vm.Strict);
// Go over each permission and associated store IDs and join them // Go over each permission and associated store IDs and join them
// so that permission for a specific store is parsed correctly // so that permission for a specific store is parsed correctly