diff --git a/BTCPayServer.Client/BTCPayServer.Client.csproj b/BTCPayServer.Client/BTCPayServer.Client.csproj index 7522bd9e2..4acef7f94 100644 --- a/BTCPayServer.Client/BTCPayServer.Client.csproj +++ b/BTCPayServer.Client/BTCPayServer.Client.csproj @@ -5,7 +5,8 @@ - + + diff --git a/BTCPayServer.Client/BTCPayServerClient.cs b/BTCPayServer.Client/BTCPayServerClient.cs index 60c81c400..d3780411c 100644 --- a/BTCPayServer.Client/BTCPayServerClient.cs +++ b/BTCPayServer.Client/BTCPayServerClient.cs @@ -5,23 +5,25 @@ using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; -using System.Text.Json; using System.Threading.Tasks; +using Newtonsoft.Json; namespace BTCPayServer.Client { public partial class BTCPayServerClient { + static BTCPayServerClient() + { + _GlobalSerializer = new JsonSerializerSettings(); + Serializer.RegisterConverters(_GlobalSerializer); + } private readonly string _apiKey; private readonly Uri _btcpayHost; private readonly HttpClient _httpClient; public string APIKey => _apiKey; - private readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; + private static readonly JsonSerializerSettings _GlobalSerializer = new JsonSerializerSettings(); public BTCPayServerClient(Uri btcpayHost, HttpClient httpClient = null) { @@ -45,7 +47,7 @@ namespace BTCPayServer.Client protected async Task HandleResponse(HttpResponseMessage message) { HandleResponse(message); - return JsonSerializer.Deserialize(await message.Content.ReadAsStringAsync(), _serializerOptions); + return JsonConvert.DeserializeObject(await message.Content.ReadAsStringAsync(), _GlobalSerializer); } protected virtual HttpRequestMessage CreateHttpRequest(string path, @@ -73,7 +75,7 @@ namespace BTCPayServer.Client var request = CreateHttpRequest(path, queryPayload, method); if (typeof(T).IsPrimitive || !EqualityComparer.Default.Equals(bodyPayload, default(T))) { - request.Content = new StringContent(JsonSerializer.Serialize(bodyPayload, _serializerOptions), Encoding.UTF8, "application/json"); + request.Content = new StringContent(JsonConvert.SerializeObject(bodyPayload, _GlobalSerializer), Encoding.UTF8, "application/json"); } return request; diff --git a/BTCPayServer.Client/JsonConverters/PermissionJsonConverter.cs b/BTCPayServer.Client/JsonConverters/PermissionJsonConverter.cs new file mode 100644 index 000000000..26bf1eace --- /dev/null +++ b/BTCPayServer.Client/JsonConverters/PermissionJsonConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; +using NBitcoin.JsonConverters; + +namespace BTCPayServer.Client.JsonConverters +{ + public class PermissionJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(Permission).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + if (reader.TokenType != JsonToken.String) + throw new JsonObjectException("Type 'Permission' is expected to be a 'String'", reader); + if (reader.ReadAsString() is String s && Permission.TryParse(s, out var permission)) + return permission; + throw new JsonObjectException("Invalid 'Permission' String", reader); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is Permission v) + writer.WriteValue(v.ToString()); + } + } +} diff --git a/BTCPayServer.Client/Models/ApiKeyData.cs b/BTCPayServer.Client/Models/ApiKeyData.cs index 58872cb11..244859f60 100644 --- a/BTCPayServer.Client/Models/ApiKeyData.cs +++ b/BTCPayServer.Client/Models/ApiKeyData.cs @@ -5,6 +5,6 @@ namespace BTCPayServer.Client.Models public string ApiKey { get; set; } public string Label { get; set; } public string UserId { get; set; } - public string[] Permissions { get; set; } + public Permission[] Permissions { get; set; } } } diff --git a/BTCPayServer.Client/Permissions.cs b/BTCPayServer.Client/Permissions.cs index 1dfa845c0..88adc5389 100644 --- a/BTCPayServer.Client/Permissions.cs +++ b/BTCPayServer.Client/Permissions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.Json.Serialization; namespace BTCPayServer.Client { diff --git a/BTCPayServer.Client/Serializer.cs b/BTCPayServer.Client/Serializer.cs new file mode 100644 index 000000000..7ab7b43b4 --- /dev/null +++ b/BTCPayServer.Client/Serializer.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BTCPayServer.Client.JsonConverters; +using Newtonsoft.Json; + +namespace BTCPayServer.Client +{ + public class Serializer + { + public static void RegisterConverters(JsonSerializerSettings settings) + { + if (settings == null) + throw new ArgumentNullException(nameof(settings)); + settings.Converters.Add(new PermissionJsonConverter()); + } + } +} diff --git a/BTCPayServer.Tests/ApiKeysTests.cs b/BTCPayServer.Tests/ApiKeysTests.cs index ee7c64f4d..fde2e5433 100644 --- a/BTCPayServer.Tests/ApiKeysTests.cs +++ b/BTCPayServer.Tests/ApiKeysTests.cs @@ -165,7 +165,7 @@ namespace BTCPayServer.Tests var expectedPermissions = Permission.ToPermissions(expectedPermissionsString).ToArray(); expectedPermissions ??= new Permission[0]; var apikeydata = await TestApiAgainstAccessToken(accessToken, $"api/v1/api-keys/current", tester.PayTester.HttpClient); - var permissions = Permission.ToPermissions(apikeydata.Permissions).ToArray(); + var permissions = apikeydata.Permissions; Assert.Equal(expectedPermissions.Length, permissions.Length); foreach (var expectPermission in expectedPermissions) { diff --git a/BTCPayServer/Controllers/ManageController.APIKeys.cs b/BTCPayServer/Controllers/ManageController.APIKeys.cs index 8a2429ed6..169a8b48e 100644 --- a/BTCPayServer/Controllers/ManageController.APIKeys.cs +++ b/BTCPayServer/Controllers/ManageController.APIKeys.cs @@ -331,7 +331,6 @@ namespace BTCPayServer.Controllers } public string Label { get; set; } public StoreData[] Stores { get; set; } - ApiKeyStoreMode _StoreMode; public ApiKeyStoreMode StoreMode { get; set; } public List SpecificStores { get; set; } = new List(); public PermissionValueItem StoreManagementPermission { get; set; } diff --git a/BTCPayServer/Controllers/RestApi/ApiKeys/ApiKeysController.cs b/BTCPayServer/Controllers/RestApi/ApiKeys/ApiKeysController.cs index cc7b7e7de..ea2dc4ff2 100644 --- a/BTCPayServer/Controllers/RestApi/ApiKeys/ApiKeysController.cs +++ b/BTCPayServer/Controllers/RestApi/ApiKeys/ApiKeysController.cs @@ -45,7 +45,7 @@ namespace BTCPayServer.Controllers.RestApi.ApiKeys { return new ApiKeyData() { - Permissions = Permission.ToPermissions(data.Permissions).Select(c => c.ToString()).ToArray(), + Permissions = Permission.ToPermissions(data.Permissions).ToArray(), ApiKey = data.Id, UserId = data.UserId, Label = data.Label diff --git a/BTCPayServer/Controllers/StoresController.BTCLike.cs b/BTCPayServer/Controllers/StoresController.BTCLike.cs index eebebf054..44d7d7370 100644 --- a/BTCPayServer/Controllers/StoresController.BTCLike.cs +++ b/BTCPayServer/Controllers/StoresController.BTCLike.cs @@ -387,7 +387,7 @@ namespace BTCPayServer.Controllers private async Task CanUseHotWallet() { - var isAdmin = (await _authorizationService.AuthorizeAsync(User, Permission.CanModifyServerSettings)).Succeeded; + var isAdmin = (await _authorizationService.AuthorizeAsync(User, Policies.CanModifyServerSettings)).Succeeded; if (isAdmin) return true; var policies = await _settingsRepository.GetSettingAsync(); diff --git a/BTCPayServer/Controllers/VaultController.cs b/BTCPayServer/Controllers/VaultController.cs index edb4211a3..c07c59794 100644 --- a/BTCPayServer/Controllers/VaultController.cs +++ b/BTCPayServer/Controllers/VaultController.cs @@ -128,7 +128,7 @@ namespace BTCPayServer.Controllers } await websocketHelper.Send("{ \"info\": \"ready\"}", cancellationToken); o = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken)); - var authorization = await _authorizationService.AuthorizeAsync(User, Permission.CanModifyStoreSettings); + var authorization = await _authorizationService.AuthorizeAsync(User, Policies.CanModifyStoreSettings); if (!authorization.Succeeded) { await websocketHelper.Send("{ \"error\": \"not-authorized\"}", cancellationToken); diff --git a/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs b/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs index 0c06c5760..a4306ff37 100644 --- a/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs +++ b/BTCPayServer/Security/APIKeys/APIKeyAuthorizationHandler.cs @@ -36,13 +36,13 @@ namespace BTCPayServer.Security.APIKeys bool success = false; switch (requirement.Policy) { - case Permission.CanModifyProfile: - case Permission.CanViewProfile: + case Policies.CanModifyProfile: + case Policies.CanViewProfile: success = context.HasPermission(Permission.Create(requirement.Policy)); break; - case Permission.CanViewStoreSettings: - case Permission.CanModifyStoreSettings: + case Policies.CanViewStoreSettings: + case Policies.CanModifyStoreSettings: var storeId = _HttpContext.GetImplicitStoreId(); var userid = _userManager.GetUserId(context.User); // Specific store action @@ -72,8 +72,8 @@ namespace BTCPayServer.Security.APIKeys success = true; } break; - case Permission.CanCreateUser: - case Permission.CanModifyServerSettings: + case Policies.CanCreateUser: + case Policies.CanModifyServerSettings: if (context.HasPermission(Permission.Create(requirement.Policy))) { var user = await _userManager.GetUserAsync(context.User); diff --git a/BTCPayServer/Security/Bitpay/BitpayAuthorizationHandler.cs b/BTCPayServer/Security/Bitpay/BitpayAuthorizationHandler.cs index 30b100e14..6183eeeab 100644 --- a/BTCPayServer/Security/Bitpay/BitpayAuthorizationHandler.cs +++ b/BTCPayServer/Security/Bitpay/BitpayAuthorizationHandler.cs @@ -55,7 +55,7 @@ namespace BTCPayServer.Security.Bitpay var anyoneCanInvoice = store.GetStoreBlob().AnyoneCanInvoice; switch (requirement.Policy) { - case Permission.CanCreateInvoice: + case Policies.CanCreateInvoice: if (!isAnonymous || (isAnonymous && anyoneCanInvoice)) { context.Succeed(requirement); @@ -63,7 +63,7 @@ namespace BTCPayServer.Security.Bitpay return; } break; - case Policies.CanGetRates.Key: + case ServerPolicies.CanGetRates.Key: context.Succeed(requirement); _HttpContext.SetStoreData(store); return; diff --git a/BTCPayServer/Security/CookieAuthorizationHandler.cs b/BTCPayServer/Security/CookieAuthorizationHandler.cs index 9f5c5e603..d2546dc22 100644 --- a/BTCPayServer/Security/CookieAuthorizationHandler.cs +++ b/BTCPayServer/Security/CookieAuthorizationHandler.cs @@ -36,7 +36,7 @@ namespace BTCPayServer.Security var isAdmin = context.User.IsInRole(Roles.ServerAdmin); switch (requirement.Policy) { - case Permission.CanModifyServerSettings: + case Policies.CanModifyServerSettings: if (isAdmin) context.Succeed(requirement); return; @@ -57,11 +57,11 @@ namespace BTCPayServer.Security bool success = false; switch (requirement.Policy) { - case Permission.CanModifyStoreSettings: + case Policies.CanModifyStoreSettings: if (store.Role == StoreRoles.Owner || isAdmin) success = true; break; - case Permission.CanCreateInvoice: + case Policies.CanCreateInvoice: if (store.Role == StoreRoles.Owner || store.Role == StoreRoles.Guest || isAdmin ||