mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-03 17:36:59 +01:00
Merge pull request #1387 from Kukks/api/users-get-current
Greenfield API: Get current User
This commit is contained in:
commit
b5664dac81
22 changed files with 490 additions and 163 deletions
11
BTCPayServer.Client/BTCPayServer.Client.csproj
Normal file
11
BTCPayServer.Client/BTCPayServer.Client.csproj
Normal file
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="4.7.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
22
BTCPayServer.Client/BTCPayServerClient.APIKeys.cs
Normal file
22
BTCPayServer.Client/BTCPayServerClient.APIKeys.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<ApiKeyData> GetCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current"), token);
|
||||
return await HandleResponse<ApiKeyData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
|
||||
HandleResponse(response);
|
||||
}
|
||||
}
|
||||
}
|
24
BTCPayServer.Client/BTCPayServerClient.Authorization.cs
Normal file
24
BTCPayServer.Client/BTCPayServerClient.Authorization.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
|
||||
public static Uri GenerateAuthorizeUri(Uri btcpayHost, string[] permissions, bool strict = true,
|
||||
bool selectiveStores = false)
|
||||
{
|
||||
var result = new UriBuilder(btcpayHost);
|
||||
result.Path = "api-keys/authorize";
|
||||
|
||||
AppendPayloadToQuery(result,
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{"strict", strict}, {"selectiveStores", selectiveStores}, {"permissions", permissions}
|
||||
});
|
||||
|
||||
return result.Uri;
|
||||
}
|
||||
}
|
||||
}
|
15
BTCPayServer.Client/BTCPayServerClient.Users.cs
Normal file
15
BTCPayServer.Client/BTCPayServerClient.Users.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<ApplicationUserData> GetCurrentUser(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users/me"), token);
|
||||
return await HandleResponse<ApplicationUserData>(response);
|
||||
}
|
||||
}
|
||||
}
|
96
BTCPayServer.Client/BTCPayServerClient.cs
Normal file
96
BTCPayServer.Client/BTCPayServerClient.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
private readonly Uri _btcpayHost;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
public BTCPayServerClient(Uri btcpayHost, string APIKey, HttpClient httpClient = null)
|
||||
{
|
||||
_apiKey = APIKey;
|
||||
_btcpayHost = btcpayHost;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
protected void HandleResponse(HttpResponseMessage message)
|
||||
{
|
||||
message.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
protected async Task<T> HandleResponse<T>(HttpResponseMessage message)
|
||||
{
|
||||
HandleResponse(message);
|
||||
return JsonSerializer.Deserialize<T>(await message.Content.ReadAsStringAsync(), _serializerOptions);
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
HttpMethod method = null)
|
||||
{
|
||||
UriBuilder uriBuilder = new UriBuilder(_btcpayHost) {Path = path};
|
||||
if (queryPayload != null && queryPayload.Any())
|
||||
{
|
||||
AppendPayloadToQuery(uriBuilder, queryPayload);
|
||||
}
|
||||
|
||||
var httpRequest = new HttpRequestMessage(method ?? HttpMethod.Get, uriBuilder.Uri);
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", _apiKey);
|
||||
|
||||
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest<T>(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
T bodyPayload = default, HttpMethod method = null)
|
||||
{
|
||||
var request = CreateHttpRequest(path, queryPayload, method);
|
||||
if (typeof(T).IsPrimitive || !EqualityComparer<T>.Default.Equals(bodyPayload, default(T)))
|
||||
{
|
||||
request.Content = new StringContent(JsonSerializer.Serialize(bodyPayload, _serializerOptions));
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private static void AppendPayloadToQuery(UriBuilder uri, Dictionary<string, object> payload)
|
||||
{
|
||||
if (uri.Query.Length > 1)
|
||||
uri.Query += "&";
|
||||
foreach (KeyValuePair<string, object> keyValuePair in payload)
|
||||
{
|
||||
UriBuilder uriBuilder = uri;
|
||||
if (keyValuePair.Value.GetType().GetInterfaces().Contains((typeof(IEnumerable))))
|
||||
{
|
||||
foreach (var item in (IEnumerable)keyValuePair.Value)
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query + Uri.EscapeDataString(keyValuePair.Key) + "=" +
|
||||
Uri.EscapeDataString(item.ToString()) + "&";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query + Uri.EscapeDataString(keyValuePair.Key) + "=" +
|
||||
Uri.EscapeDataString(keyValuePair.Value.ToString()) + "&";
|
||||
}
|
||||
}
|
||||
|
||||
uri.Query = uri.Query.Trim('&');
|
||||
}
|
||||
}
|
||||
}
|
10
BTCPayServer.Client/Models/ApiKeyData.cs
Normal file
10
BTCPayServer.Client/Models/ApiKeyData.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class ApiKeyData
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string[] Permissions { get; set; }
|
||||
}
|
||||
}
|
8
BTCPayServer.Client/Models/ApplicationUserData.cs
Normal file
8
BTCPayServer.Client/Models/ApplicationUserData.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class ApplicationUserData
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
29
BTCPayServer.Client/Permissions.cs
Normal file
29
BTCPayServer.Client/Permissions.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public static class Permissions
|
||||
{
|
||||
public const string ServerManagement = nameof(ServerManagement);
|
||||
public const string StoreManagement = nameof(StoreManagement);
|
||||
public const string ProfileManagement = nameof(ProfileManagement);
|
||||
|
||||
public static string[] GetAllPermissionKeys()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
ServerManagement,
|
||||
StoreManagement,
|
||||
ProfileManagement
|
||||
};
|
||||
}
|
||||
public static string GetStorePermission(string storeId) => $"{nameof(StoreManagement)}:{storeId}";
|
||||
|
||||
public static IEnumerable<string> ExtractStorePermissionsIds(IEnumerable<string> permissions) => permissions
|
||||
.Where(s => s.StartsWith($"{nameof(StoreManagement)}:", StringComparison.InvariantCulture))
|
||||
.Select(s => s.Split(":")[1]);
|
||||
}
|
||||
}
|
|
@ -4,11 +4,11 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Security.APIKeys;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using BTCPayServer.Views.Manage;
|
||||
using ExchangeSharp;
|
||||
using Newtonsoft.Json;
|
||||
using OpenQA.Selenium;
|
||||
using Xunit;
|
||||
|
@ -67,8 +67,8 @@ namespace BTCPayServer.Tests
|
|||
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);
|
||||
await TestApiAgainstAccessToken(superApiKey, tester, user, Permissions.ServerManagement,
|
||||
Permissions.StoreManagement);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
|
@ -76,7 +76,7 @@ namespace BTCPayServer.Tests
|
|||
s.Driver.FindElement(By.Id("Generate")).Click();
|
||||
var serverOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
|
||||
await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user,
|
||||
APIKeyConstants.Permissions.ServerManagement);
|
||||
Permissions.ServerManagement);
|
||||
|
||||
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
|
@ -84,7 +84,7 @@ namespace BTCPayServer.Tests
|
|||
s.Driver.FindElement(By.Id("Generate")).Click();
|
||||
var allStoreOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text;
|
||||
await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user,
|
||||
APIKeyConstants.Permissions.StoreManagement);
|
||||
Permissions.StoreManagement);
|
||||
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
s.Driver.FindElement(By.CssSelector("button[value=change-store-mode]")).Click();
|
||||
|
@ -96,7 +96,7 @@ namespace BTCPayServer.Tests
|
|||
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));
|
||||
Permissions.GetStorePermission(storeId));
|
||||
|
||||
s.Driver.FindElement(By.Id("AddApiKey")).Click();
|
||||
s.Driver.FindElement(By.Id("Generate")).Click();
|
||||
|
@ -117,37 +117,14 @@ namespace BTCPayServer.Tests
|
|||
//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}")));
|
||||
var authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri,
|
||||
new[] {Permissions.StoreManagement, Permissions.ServerManagement}).ToString();
|
||||
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.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;
|
||||
|
@ -159,35 +136,16 @@ namespace BTCPayServer.Tests
|
|||
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}")));
|
||||
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.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);
|
||||
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);
|
||||
|
@ -214,8 +172,8 @@ namespace BTCPayServer.Tests
|
|||
var secondUser = tester.NewAccount();
|
||||
secondUser.GrantAccess();
|
||||
|
||||
var selectiveStorePermissions = APIKeyConstants.Permissions.ExtractStorePermissionsIds(permissions);
|
||||
if (permissions.Contains(APIKeyConstants.Permissions.StoreManagement) || selectiveStorePermissions.Any())
|
||||
var selectiveStorePermissions = Permissions.ExtractStorePermissionsIds(permissions);
|
||||
if (permissions.Contains(Permissions.StoreManagement) || selectiveStorePermissions.Any())
|
||||
{
|
||||
var resultStores =
|
||||
await TestApiAgainstAccessToken<StoreData[]>(accessToken, $"{TestApiPath}/me/stores",
|
||||
|
@ -231,7 +189,7 @@ namespace BTCPayServer.Tests
|
|||
data => data.Id.Equals(selectiveStorePermission, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
if (permissions.Contains(APIKeyConstants.Permissions.StoreManagement))
|
||||
if (permissions.Contains(Permissions.StoreManagement))
|
||||
{
|
||||
Assert.True(await TestApiAgainstAccessToken<bool>(accessToken,
|
||||
$"{TestApiPath}/me/stores/actions",
|
||||
|
@ -272,7 +230,7 @@ namespace BTCPayServer.Tests
|
|||
tester.PayTester.HttpClient);
|
||||
});
|
||||
|
||||
if (permissions.Contains(APIKeyConstants.Permissions.ServerManagement))
|
||||
if (permissions.Contains(Permissions.ServerManagement))
|
||||
{
|
||||
Assert.True(await TestApiAgainstAccessToken<bool>(accessToken,
|
||||
$"{TestApiPath}/me/is-admin",
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Controllers.RestApi.ApiKeys;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Security.APIKeys;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.AspNet.SignalR.Client;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -26,7 +23,7 @@ namespace BTCPayServer.Tests
|
|||
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task ApiKeysControllerTests()
|
||||
{
|
||||
|
@ -36,29 +33,59 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.MakeAdmin();
|
||||
string apiKey = await GenerateAPIKey(tester, user);
|
||||
|
||||
string apiKey = await GenerateAPIKey(tester, user, Permissions.ServerManagement, Permissions.StoreManagement);
|
||||
var client = new BTCPayServerClient(tester.PayTester.ServerUri, apiKey);
|
||||
//Get current api key
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "api/v1/api-keys/current");
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", apiKey);
|
||||
var result = await tester.PayTester.HttpClient.SendAsync(request);
|
||||
Assert.True(result.IsSuccessStatusCode);
|
||||
var apiKeyData = JObject.Parse(await result.Content.ReadAsStringAsync()).ToObject<ApiKeyData>();
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> GenerateAPIKey(ServerTester tester, TestAccount user)
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> GenerateAPIKey(ServerTester tester, TestAccount user, params string[] permissions)
|
||||
{
|
||||
var manageController = tester.PayTester.GetController<ManageController>(user.UserId, user.StoreId, user.IsAdmin);
|
||||
var x = Assert.IsType<RedirectToActionResult>(await manageController.AddApiKey(
|
||||
new ManageController.AddApiKeyViewModel()
|
||||
{
|
||||
ServerManagementPermission = true,
|
||||
StoreManagementPermission = true,
|
||||
PermissionValues = permissions.Select(s => new ManageController.AddApiKeyViewModel.PermissionValueItem()
|
||||
{
|
||||
Permission = s,
|
||||
Value = true
|
||||
}).ToList(),
|
||||
StoreMode = ManageController.AddApiKeyViewModel.ApiKeyStoreMode.AllStores
|
||||
}));
|
||||
var statusMessage = manageController.TempData.GetStatusMessageModel();
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
|
||||
<ProjectReference Include="..\BTCPayServer.Data\BTCPayServer.Data.csproj" />
|
||||
<ProjectReference Include="..\BTCPayServer.Rating\BTCPayServer.Rating.csproj" />
|
||||
<ProjectReference Include="..\BTCPayServer.Common\BTCPayServer.Common.csproj" />
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Hosting.OpenApi;
|
||||
using BTCPayServer.Models;
|
||||
|
@ -13,6 +14,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NSwag.Annotations;
|
||||
using YamlDotNet.Core.Tokens;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
|
@ -30,8 +32,6 @@ namespace BTCPayServer.Controllers
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet("api-keys/{id}/delete")]
|
||||
public async Task<IActionResult> RemoveAPIKey(string id)
|
||||
{
|
||||
|
@ -109,9 +109,13 @@ namespace BTCPayServer.Controllers
|
|||
var vm = await SetViewModelValues(new AuthorizeApiKeysViewModel()
|
||||
{
|
||||
Label = applicationName,
|
||||
ServerManagementPermission = permissions.Contains(APIKeyConstants.Permissions.ServerManagement),
|
||||
StoreManagementPermission = permissions.Contains(APIKeyConstants.Permissions.StoreManagement),
|
||||
ServerManagementPermission = permissions.Contains(Permissions.ServerManagement),
|
||||
StoreManagementPermission = permissions.Contains(Permissions.StoreManagement),
|
||||
PermissionsFormatted = permissions,
|
||||
PermissionValues = permissions.Where(s =>
|
||||
!s.Contains(Permissions.StoreManagement, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
s != Permissions.ServerManagement)
|
||||
.Select(s => new AddApiKeyViewModel.PermissionValueItem() {Permission = s, Value = true}).ToList(),
|
||||
ApplicationName = applicationName,
|
||||
SelectiveStores = selectiveStores,
|
||||
Strict = strict,
|
||||
|
@ -133,7 +137,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
|
||||
if (viewModel.PermissionsFormatted.Contains(APIKeyConstants.Permissions.ServerManagement))
|
||||
if (viewModel.PermissionsFormatted.Contains(Permissions.ServerManagement))
|
||||
{
|
||||
if (!viewModel.IsServerAdmin && viewModel.ServerManagementPermission)
|
||||
{
|
||||
|
@ -147,7 +151,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
if (viewModel.PermissionsFormatted.Contains(APIKeyConstants.Permissions.StoreManagement))
|
||||
if (viewModel.PermissionsFormatted.Contains(Permissions.StoreManagement))
|
||||
{
|
||||
if (!viewModel.SelectiveStores &&
|
||||
viewModel.StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific)
|
||||
|
@ -261,29 +265,34 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
private IEnumerable<string> GetPermissionsFromViewModel(AddApiKeyViewModel viewModel)
|
||||
{
|
||||
var permissions = new List<string>();
|
||||
var permissions = viewModel.PermissionValues.Where(tuple => tuple.Value).Select(tuple => tuple.Permission).ToList();
|
||||
|
||||
if (viewModel.StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific)
|
||||
{
|
||||
permissions.AddRange(viewModel.SpecificStores.Select(APIKeyConstants.Permissions.GetStorePermission));
|
||||
permissions.AddRange(viewModel.SpecificStores.Select(Permissions.GetStorePermission));
|
||||
}
|
||||
else if (viewModel.StoreManagementPermission)
|
||||
{
|
||||
permissions.Add(APIKeyConstants.Permissions.StoreManagement);
|
||||
permissions.Add(Permissions.StoreManagement);
|
||||
}
|
||||
|
||||
if (viewModel.IsServerAdmin && viewModel.ServerManagementPermission)
|
||||
{
|
||||
permissions.Add(APIKeyConstants.Permissions.ServerManagement);
|
||||
permissions.Add(Permissions.ServerManagement);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
return permissions.Distinct();
|
||||
}
|
||||
|
||||
private async Task<T> SetViewModelValues<T>(T viewModel) where T : AddApiKeyViewModel
|
||||
{
|
||||
viewModel.Stores = await _StoreRepository.GetStoresByUserId(_userManager.GetUserId(User));
|
||||
viewModel.IsServerAdmin = (await _authorizationService.AuthorizeAsync(User, Policies.CanModifyServerSettings.Key)).Succeeded;
|
||||
viewModel.IsServerAdmin =
|
||||
(await _authorizationService.AuthorizeAsync(User, Policies.CanModifyServerSettings.Key)).Succeeded;
|
||||
viewModel.PermissionValues ??= Permissions.GetAllPermissionKeys().Where(s =>
|
||||
!s.Contains(Permissions.StoreManagement, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
s != Permissions.ServerManagement)
|
||||
.Select(s => new AddApiKeyViewModel.PermissionValueItem() {Permission = s, Value = true}).ToList();
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
|
@ -297,12 +306,19 @@ namespace BTCPayServer.Controllers
|
|||
public bool ServerManagementPermission { get; set; }
|
||||
public bool StoreManagementPermission { get; set; }
|
||||
public string Command { get; set; }
|
||||
public List<PermissionValueItem> PermissionValues { get; set; }
|
||||
|
||||
public enum ApiKeyStoreMode
|
||||
{
|
||||
AllStores,
|
||||
Specific
|
||||
}
|
||||
|
||||
public class PermissionValueItem
|
||||
{
|
||||
public string Permission { get; set; }
|
||||
public bool Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthorizeApiKeysViewModel : AddApiKeyViewModel
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
using BTCPayServer.Data;
|
||||
|
||||
namespace BTCPayServer.Controllers.RestApi.ApiKeys
|
||||
{
|
||||
public class ApiKeyData
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string[] Permissions { get; set; }
|
||||
|
||||
public static ApiKeyData FromModel(APIKeyData data)
|
||||
{
|
||||
return new ApiKeyData()
|
||||
{
|
||||
Permissions = data.GetPermissions(),
|
||||
ApiKey = data.Id,
|
||||
UserId = data.UserId,
|
||||
Label = data.Label
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Hosting.OpenApi;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.APIKeys;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NSwag.Annotations;
|
||||
|
||||
|
@ -16,10 +19,12 @@ namespace BTCPayServer.Controllers.RestApi.ApiKeys
|
|||
public class ApiKeysController : ControllerBase
|
||||
{
|
||||
private readonly APIKeyRepository _apiKeyRepository;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public ApiKeysController(APIKeyRepository apiKeyRepository)
|
||||
public ApiKeysController(APIKeyRepository apiKeyRepository, UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_apiKeyRepository = apiKeyRepository;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
[OpenApiOperation("Get current API Key information", "View information about the current API key")]
|
||||
|
@ -31,7 +36,30 @@ namespace BTCPayServer.Controllers.RestApi.ApiKeys
|
|||
{
|
||||
ControllerContext.HttpContext.GetAPIKey(out var apiKey);
|
||||
var data = await _apiKeyRepository.GetKey(apiKey);
|
||||
return Ok(ApiKeyData.FromModel(data));
|
||||
return Ok(FromModel(data));
|
||||
}
|
||||
|
||||
[OpenApiOperation("Revoke the current API Key", "Revoke the current API key so that it cannot be used anymore")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApiKeyData),
|
||||
Description = "The key was revoked and is no longer usable")]
|
||||
[HttpDelete("~/api/v1/api-keys/current")]
|
||||
[HttpDelete("~/api/v1/users/me/api-keys/current")]
|
||||
public async Task<ActionResult<ApiKeyData>> RevokeKey()
|
||||
{
|
||||
ControllerContext.HttpContext.GetAPIKey(out var apiKey);
|
||||
await _apiKeyRepository.Remove(apiKey, _userManager.GetUserId(User));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private static ApiKeyData FromModel(APIKeyData data)
|
||||
{
|
||||
return new ApiKeyData()
|
||||
{
|
||||
Permissions = data.GetPermissions(),
|
||||
ApiKey = data.Id,
|
||||
UserId = data.UserId,
|
||||
Label = data.Label
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
47
BTCPayServer/Controllers/RestApi/Users/UsersController.cs
Normal file
47
BTCPayServer/Controllers/RestApi/Users/UsersController.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Hosting.OpenApi;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NSwag.Annotations;
|
||||
|
||||
namespace BTCPayServer.Controllers.RestApi.Users
|
||||
{
|
||||
[ApiController]
|
||||
[IncludeInOpenApiDocs]
|
||||
[OpenApiTags("Users")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public UsersController(UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
[OpenApiOperation("Get current user information", "View information about the current user")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, typeof(ApiKeyData),
|
||||
Description = "Information about the current user")]
|
||||
[Authorize(Policy = Policies.CanModifyProfile.Key, AuthenticationSchemes = AuthenticationSchemes.ApiKey)]
|
||||
[HttpGet("~/api/v1/users/me")]
|
||||
public async Task<ActionResult<ApplicationUserData>> GetCurrentUser()
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
return FromModel(user);
|
||||
}
|
||||
|
||||
private static ApplicationUserData FromModel(ApplicationUser data)
|
||||
{
|
||||
return new ApplicationUserData()
|
||||
{
|
||||
Id = data.Id,
|
||||
Email = data.Email
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -33,16 +34,19 @@ namespace BTCPayServer.Security.APIKeys
|
|||
bool success = false;
|
||||
switch (requirement.Policy)
|
||||
{
|
||||
case Policies.CanModifyProfile.Key:
|
||||
success = context.HasPermissions(Permissions.ProfileManagement);
|
||||
break;
|
||||
case Policies.CanListStoreSettings.Key:
|
||||
var selectiveStorePermissions =
|
||||
APIKeyConstants.Permissions.ExtractStorePermissionsIds(context.GetPermissions());
|
||||
success = context.HasPermissions(APIKeyConstants.Permissions.StoreManagement) ||
|
||||
Permissions.ExtractStorePermissionsIds(context.GetPermissions());
|
||||
success = context.HasPermissions(Permissions.StoreManagement) ||
|
||||
selectiveStorePermissions.Any();
|
||||
break;
|
||||
case Policies.CanModifyStoreSettings.Key:
|
||||
string storeId = _HttpContext.GetImplicitStoreId();
|
||||
if (!context.HasPermissions(APIKeyConstants.Permissions.StoreManagement) &&
|
||||
!context.HasPermissions(APIKeyConstants.Permissions.GetStorePermission(storeId)))
|
||||
if (!context.HasPermissions(Permissions.StoreManagement) &&
|
||||
!context.HasPermissions(Permissions.GetStorePermission(storeId)))
|
||||
break;
|
||||
|
||||
if (storeId == null)
|
||||
|
@ -63,7 +67,7 @@ namespace BTCPayServer.Security.APIKeys
|
|||
|
||||
break;
|
||||
case Policies.CanModifyServerSettings.Key:
|
||||
if (!context.HasPermissions(APIKeyConstants.Permissions.ServerManagement))
|
||||
if (!context.HasPermissions(Permissions.ServerManagement))
|
||||
break;
|
||||
// For this authorization, we stil check in database because it is super sensitive.
|
||||
var user = await _userManager.GetUserAsync(context.User);
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Security.APIKeys
|
||||
{
|
||||
|
@ -16,21 +13,14 @@ namespace BTCPayServer.Security.APIKeys
|
|||
|
||||
public static class Permissions
|
||||
{
|
||||
public const string ServerManagement = nameof(ServerManagement);
|
||||
public const string StoreManagement = nameof(StoreManagement);
|
||||
|
||||
public static readonly Dictionary<string, (string Title, string Description)> PermissionDescriptions = new Dictionary<string, (string Title, string Description)>()
|
||||
{
|
||||
{StoreManagement, ("Manage your stores", "The app will be able to create, modify and delete all your stores.")},
|
||||
{$"{nameof(StoreManagement)}:", ("Manage selected stores", "The app will be able to modify and delete selected stores.")},
|
||||
{ServerManagement, ("Manage your server", "The app will have total control on your server")},
|
||||
{Client.Permissions.StoreManagement, ("Manage your stores", "The app will be able to create, modify and delete all your stores.")},
|
||||
{$"{nameof(Client.Permissions.StoreManagement)}:", ("Manage selected stores", "The app will be able to modify and delete selected stores.")},
|
||||
{Client.Permissions.ServerManagement, ("Manage your server", "The app will have total control on your server")},
|
||||
{Client.Permissions.ProfileManagement, ("Manage your profile", "The app will be able to view and modify your user profile.")},
|
||||
};
|
||||
|
||||
public static string GetStorePermission(string storeId) => $"{nameof(StoreManagement)}:{storeId}";
|
||||
|
||||
public static IEnumerable<string> ExtractStorePermissionsIds(IEnumerable<string> permissions) => permissions
|
||||
.Where(s => s.StartsWith($"{nameof(StoreManagement)}:", StringComparison.InvariantCulture))
|
||||
.Select(s => s.Split(":")[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
using BTCPayServer.Services.Stores;
|
||||
|
@ -35,12 +36,12 @@ namespace BTCPayServer.Security.APIKeys
|
|||
claimsPrincipal.Claims.Where(claim => claim.Type == APIKeyConstants.ClaimTypes.Permissions)
|
||||
.Select(claim => claim.Value).ToList();
|
||||
|
||||
if (permissions.Contains(APIKeyConstants.Permissions.StoreManagement))
|
||||
if (permissions.Contains(Permissions.StoreManagement))
|
||||
{
|
||||
return storeRepository.GetStoresByUserId(userManager.GetUserId(claimsPrincipal));
|
||||
}
|
||||
|
||||
var storeIds = APIKeyConstants.Permissions.ExtractStorePermissionsIds(permissions);
|
||||
var storeIds = Permissions.ExtractStorePermissionsIds(permissions);
|
||||
return storeRepository.GetStoresByUserId(userManager.GetUserId(claimsPrincipal), storeIds);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
{
|
||||
|
@ -15,6 +11,8 @@ namespace BTCPayServer.Security
|
|||
options.AddPolicy(CanCreateInvoice.Key);
|
||||
options.AddPolicy(CanGetRates.Key);
|
||||
options.AddPolicy(CanModifyServerSettings.Key);
|
||||
options.AddPolicy(CanModifyServerSettings.Key);
|
||||
options.AddPolicy(CanModifyProfile.Key);
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -27,6 +25,10 @@ namespace BTCPayServer.Security
|
|||
{
|
||||
public const string Key = "btcpay.store.canmodifyserversettings";
|
||||
}
|
||||
public class CanModifyProfile
|
||||
{
|
||||
public const string Key = "btcpay.store.canmodifyprofile";
|
||||
}
|
||||
public class CanModifyStoreSettings
|
||||
{
|
||||
public const string Key = "btcpay.store.canmodifystoresettings";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Controllers
|
||||
@using BTCPayServer.Security.APIKeys
|
||||
@model BTCPayServer.Controllers.ManageController.AddApiKeyViewModel
|
||||
@model ManageController.AddApiKeyViewModel
|
||||
|
||||
@{
|
||||
ViewData.SetActivePageAndTitle(ManageNavPages.APIKeys, "Add API Key");
|
||||
|
@ -39,9 +40,20 @@
|
|||
{
|
||||
<div class="list-group-item form-group">
|
||||
<input asp-for="ServerManagementPermission" class="form-check-inline"/>
|
||||
<label asp-for="ServerManagementPermission" class="h5">@GetTitle(APIKeyConstants.Permissions.ServerManagement)</label>
|
||||
<label asp-for="ServerManagementPermission" class="h5">@GetTitle(Permissions.ServerManagement)</label>
|
||||
<span asp-validation-for="ServerManagementPermission" class="text-danger"></span>
|
||||
<p>@GetDescription(APIKeyConstants.Permissions.ServerManagement).</p>
|
||||
<p>@GetDescription(Permissions.ServerManagement).</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@for (int i = 0; i < Model.PermissionValues.Count; i++)
|
||||
{
|
||||
<div class="list-group-item form-group">
|
||||
<input type="hidden" asp-for="PermissionValues[i].Permission">
|
||||
<input type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-inline"/>
|
||||
<label asp-for="PermissionValues[i].Value" class="h5">@GetTitle(Model.PermissionValues[i].Permission)</label>
|
||||
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
|
||||
<p>@GetDescription(Model.PermissionValues[i].Permission).</p>
|
||||
</div>
|
||||
}
|
||||
@if (Model.StoreMode == ManageController.AddApiKeyViewModel.ApiKeyStoreMode.AllStores)
|
||||
|
@ -49,9 +61,9 @@
|
|||
<div class="list-group-item form-group">
|
||||
@Html.CheckBoxFor(model => model.StoreManagementPermission, new Dictionary<string, string>() {{"class", "form-check-inline"}})
|
||||
|
||||
<label asp-for="StoreManagementPermission" class="h5">@GetTitle(APIKeyConstants.Permissions.StoreManagement)</label>
|
||||
<label asp-for="StoreManagementPermission" class="h5">@GetTitle(Permissions.StoreManagement)</label>
|
||||
<span asp-validation-for="StoreManagementPermission" class="text-danger"></span>
|
||||
<p class="mb-0">@GetDescription(APIKeyConstants.Permissions.StoreManagement).</p>
|
||||
<p class="mb-0">@GetDescription(Permissions.StoreManagement).</p>
|
||||
<button type="submit" class="btn btn-link" name="command" value="change-store-mode">Give permission to specific stores instead</button>
|
||||
</div>
|
||||
}
|
||||
|
@ -59,8 +71,8 @@
|
|||
{
|
||||
<div class="list-group-item p-0 border-0 mb-2">
|
||||
<li class="list-group-item ">
|
||||
<h5 class="mb-1">@GetTitle(APIKeyConstants.Permissions.StoreManagement + ":")</h5>
|
||||
<p class="mb-0">@GetDescription(APIKeyConstants.Permissions.StoreManagement + ":").</p>
|
||||
<h5 class="mb-1">@GetTitle(Permissions.StoreManagement + ":")</h5>
|
||||
<p class="mb-0">@GetDescription(Permissions.StoreManagement + ":").</p>
|
||||
<button type="submit" class="btn btn-link" name="command" value="change-store-mode">Give permission to all stores instead</button>
|
||||
</li>
|
||||
@if (!Model.Stores.Any())
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Controllers
|
||||
@using BTCPayServer.Security.APIKeys
|
||||
@model BTCPayServer.Controllers.ManageController.AuthorizeApiKeysViewModel
|
||||
|
@ -48,11 +49,20 @@
|
|||
<p >There are no associated permissions to the API key being requested here. The application cannot do anything with your BTCPay account other than validating your account exists.</p>
|
||||
</div>
|
||||
}
|
||||
@if (Model.PermissionsFormatted.Contains(APIKeyConstants.Permissions.ServerManagement) && (Model.IsServerAdmin || Model.Strict))
|
||||
@if (Model.PermissionsFormatted.Contains(Permissions.ServerManagement) && (Model.IsServerAdmin || Model.Strict))
|
||||
{
|
||||
<div class="list-group-item form-group">
|
||||
<input asp-for="ServerManagementPermission" class="form-check-inline" readonly="@(Model.Strict || !Model.IsServerAdmin)"/>
|
||||
<label asp-for="ServerManagementPermission" class="h5">@GetTitle(APIKeyConstants.Permissions.ServerManagement)</label>
|
||||
@if (Model.Strict || !Model.IsServerAdmin)
|
||||
{
|
||||
<input type="hidden" asp-for="ServerManagementPermission"/>
|
||||
<input type="checkbox" class="form-check-inline" checked="@Model.ServerManagementPermission" disabled/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" asp-for="ServerManagementPermission" class="form-check-inline"/>
|
||||
}
|
||||
|
||||
<label asp-for="ServerManagementPermission" class="h5">@GetTitle(Permissions.ServerManagement)</label>
|
||||
@if (!Model.IsServerAdmin)
|
||||
{
|
||||
<span class="text-danger">
|
||||
|
@ -61,19 +71,44 @@
|
|||
}
|
||||
|
||||
<span asp-validation-for="ServerManagementPermission" class="text-danger"></span>
|
||||
<p>@GetDescription(APIKeyConstants.Permissions.ServerManagement).</p>
|
||||
<p>@GetDescription(Permissions.ServerManagement).</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (Model.PermissionsFormatted.Contains(APIKeyConstants.Permissions.StoreManagement))
|
||||
@for (int i = 0; i < Model.PermissionValues.Count; i++)
|
||||
{
|
||||
<div class="list-group-item form-group">
|
||||
<input type="hidden" asp-for="PermissionValues[i].Permission">
|
||||
@if (Model.Strict || !Model.IsServerAdmin)
|
||||
{
|
||||
<input type="hidden" asp-for="PermissionValues[i].Value"/>
|
||||
<input type="checkbox" class="form-check-inline" checked="@Model.PermissionValues[i].Value" disabled/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-inline"/>
|
||||
}
|
||||
<label asp-for="PermissionValues[i].Value" class="h5">@GetTitle(Model.PermissionValues[i].Permission)</label>
|
||||
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
|
||||
<p>@GetDescription(Model.PermissionValues[i].Permission).</p>
|
||||
</div>
|
||||
}
|
||||
@if (Model.PermissionsFormatted.Contains(Permissions.StoreManagement))
|
||||
{
|
||||
@if (Model.StoreMode == ManageController.AddApiKeyViewModel.ApiKeyStoreMode.AllStores)
|
||||
{
|
||||
<div class="list-group-item form-group">
|
||||
<input type="checkbox" asp-for="StoreManagementPermission" class="form-check-inline" readonly="@Model.Strict"/>
|
||||
<label asp-for="StoreManagementPermission" class="h5">@GetTitle(APIKeyConstants.Permissions.StoreManagement)</label>
|
||||
@if (Model.Strict)
|
||||
{
|
||||
<input type="hidden" asp-for="StoreManagementPermission"/>
|
||||
<input type="checkbox" class="form-check-inline" checked="@Model.StoreManagementPermission" disabled/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" asp-for="StoreManagementPermission" class="form-check-inline"/>
|
||||
}
|
||||
<label asp-for="StoreManagementPermission" class="h5">@GetTitle(Permissions.StoreManagement)</label>
|
||||
<span asp-validation-for="StoreManagementPermission" class="text-danger"></span>
|
||||
<p class="mb-0">@GetDescription(APIKeyConstants.Permissions.StoreManagement).</p>
|
||||
<p class="mb-0">@GetDescription(Permissions.StoreManagement).</p>
|
||||
@if (Model.SelectiveStores)
|
||||
{
|
||||
<button type="submit" class="btn btn-link" name="command" value="change-store-mode">Give permission to specific stores instead</button>
|
||||
|
@ -84,8 +119,8 @@
|
|||
{
|
||||
<div class="list-group-item p-0 border-0 mb-2">
|
||||
<li class="list-group-item">
|
||||
<h5 class="mb-1">@GetTitle(APIKeyConstants.Permissions.StoreManagement + ":")</h5>
|
||||
<p class="mb-0">@GetDescription(APIKeyConstants.Permissions.StoreManagement + ":").</p>
|
||||
<h5 class="mb-1">@GetTitle(Permissions.StoreManagement + ":")</h5>
|
||||
<p class="mb-0">@GetDescription(Permissions.StoreManagement + ":").</p>
|
||||
<button type="submit" class="btn btn-link" name="command" value="change-store-mode">Give permission to all stores instead</button>
|
||||
</li>
|
||||
@if (!Model.Stores.Any())
|
||||
|
|
|
@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BTCPayServer.Common", "BTCP
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BTCPayServer.Data", "BTCPayServer.Data\BTCPayServer.Data.csproj", "{4D7A865D-3945-4C70-9CC8-B09A274A697E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Client", "BTCPayServer.Client\BTCPayServer.Client.csproj", "{21A13304-7168-49A0-86C2-0A1A9453E9C7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -95,6 +97,18 @@ Global
|
|||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Loading…
Add table
Reference in a new issue