Local Greenfield Client for Plugins (#2410)

* wip

* Local GreenField Client for Plugins

* support notification handlers being missing

* Initial support for scoped btcpay client

* test out scoped local client

* wip

* small fix

* Throw exception if using local greenfield client and it has not been implemented yet

* adapt based on new changes in BTCPay

* update

* fix tests

* Allow Local client to bypass authorization handler

* Add Misc endpoints to Local API Client

* Add new endpoints

* Apply code review changes
This commit is contained in:
Andrew Camilleri 2021-07-27 14:11:47 +02:00 committed by GitHub
parent 14e4d2d675
commit ba165ddd4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1065 additions and 106 deletions

View File

@ -36,4 +36,7 @@
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using BTCPayServer.Client;
namespace BTCPayServer.Abstractions.Contracts
{
public interface IBTCPayServerClientFactory
{
Task<BTCPayServerClient> Create(string userId, params string[] storeIds);
}
}

View File

@ -11,7 +11,8 @@ namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string orderId = null, InvoiceStatus[] status = null,
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string[] orderId = null,
InvoiceStatus[] status = null,
DateTimeOffset? startDate = null,
DateTimeOffset? endDate = null,
string textSearch = null,

View File

@ -9,7 +9,7 @@ namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public async Task<LightningNodeInformationData> GetLightningNodeInfo(string cryptoCode,
public virtual async Task<LightningNodeInformationData> GetLightningNodeInfo(string cryptoCode,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
@ -18,7 +18,7 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningNodeInformationData>(response);
}
public async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
public virtual async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
CancellationToken token = default)
{
if (request == null)
@ -29,7 +29,7 @@ namespace BTCPayServer.Client
await HandleResponse(response);
}
public async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string cryptoCode,
public virtual async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string cryptoCode,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
@ -38,16 +38,16 @@ namespace BTCPayServer.Client
return await HandleResponse<IEnumerable<LightningChannelData>>(response);
}
public async Task<string> OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request,
public virtual async Task OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/channels", bodyPayload: request,
method: HttpMethod.Post), token);
return await HandleResponse<string>(response);
await HandleResponse(response);
}
public async Task<string> GetLightningDepositAddress(string cryptoCode, CancellationToken token = default)
public virtual async Task<string> GetLightningDepositAddress(string cryptoCode, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/address", method: HttpMethod.Post), token);
@ -55,7 +55,7 @@ namespace BTCPayServer.Client
}
public async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
public virtual async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
CancellationToken token = default)
{
if (request == null)
@ -66,7 +66,7 @@ namespace BTCPayServer.Client
await HandleResponse(response);
}
public async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
string invoiceId, CancellationToken token = default)
{
if (invoiceId == null)
@ -77,7 +77,7 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningInvoiceData>(response);
}
public async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request,
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request,
CancellationToken token = default)
{
if (request == null)

View File

@ -9,7 +9,7 @@ namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public async Task<LightningNodeInformationData> GetLightningNodeInfo(string storeId, string cryptoCode,
public virtual async Task<LightningNodeInformationData> GetLightningNodeInfo(string storeId, string cryptoCode,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
@ -18,7 +18,7 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningNodeInformationData>(response);
}
public async Task ConnectToLightningNode(string storeId, string cryptoCode, ConnectToNodeRequest request,
public virtual async Task ConnectToLightningNode(string storeId, string cryptoCode, ConnectToNodeRequest request,
CancellationToken token = default)
{
if (request == null)
@ -29,7 +29,7 @@ namespace BTCPayServer.Client
await HandleResponse(response);
}
public async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string storeId, string cryptoCode,
public virtual async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string storeId, string cryptoCode,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
@ -38,16 +38,16 @@ namespace BTCPayServer.Client
return await HandleResponse<IEnumerable<LightningChannelData>>(response);
}
public async Task<string> OpenLightningChannel(string storeId, string cryptoCode, OpenLightningChannelRequest request,
public virtual async Task OpenLightningChannel(string storeId, string cryptoCode, OpenLightningChannelRequest request,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/channels", bodyPayload: request,
method: HttpMethod.Post), token);
return await HandleResponse<string>(response);
await HandleResponse(response);
}
public async Task<string> GetLightningDepositAddress(string storeId, string cryptoCode,
public virtual async Task<string> GetLightningDepositAddress(string storeId, string cryptoCode,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
@ -56,7 +56,7 @@ namespace BTCPayServer.Client
return await HandleResponse<string>(response);
}
public async Task PayLightningInvoice(string storeId, string cryptoCode, PayLightningInvoiceRequest request,
public virtual async Task PayLightningInvoice(string storeId, string cryptoCode, PayLightningInvoiceRequest request,
CancellationToken token = default)
{
if (request == null)
@ -67,7 +67,7 @@ namespace BTCPayServer.Client
await HandleResponse(response);
}
public async Task<LightningInvoiceData> GetLightningInvoice(string storeId, string cryptoCode,
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string storeId, string cryptoCode,
string invoiceId, CancellationToken token = default)
{
if (invoiceId == null)
@ -78,7 +78,7 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningInvoiceData>(response);
}
public async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
CreateLightningInvoiceRequest request, CancellationToken token = default)
{
if (request == null)

View File

@ -9,18 +9,18 @@ namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public async Task<PullPaymentData> CreatePullPayment(string storeId, CreatePullPaymentRequest request, CancellationToken cancellationToken = default)
public virtual async Task<PullPaymentData> CreatePullPayment(string storeId, CreatePullPaymentRequest request, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments", bodyPayload: request, method: HttpMethod.Post), cancellationToken);
return await HandleResponse<PullPaymentData>(response);
}
public async Task<PullPaymentData> GetPullPayment(string pullPaymentId, CancellationToken cancellationToken = default)
public virtual async Task<PullPaymentData> GetPullPayment(string pullPaymentId, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", method: HttpMethod.Get), cancellationToken);
return await HandleResponse<PullPaymentData>(response);
}
public async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false, CancellationToken cancellationToken = default)
public virtual async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false, CancellationToken cancellationToken = default)
{
Dictionary<string, object> query = new Dictionary<string, object>();
query.Add("includeArchived", includeArchived);
@ -28,31 +28,31 @@ namespace BTCPayServer.Client
return await HandleResponse<PullPaymentData[]>(response);
}
public async Task ArchivePullPayment(string storeId, string pullPaymentId, CancellationToken cancellationToken = default)
public virtual async Task ArchivePullPayment(string storeId, string pullPaymentId, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", method: HttpMethod.Delete), cancellationToken);
await HandleResponse(response);
}
public async Task<PayoutData[]> GetPayouts(string pullPaymentId, bool includeCancelled = false, CancellationToken cancellationToken = default)
public virtual async Task<PayoutData[]> GetPayouts(string pullPaymentId, bool includeCancelled = false, CancellationToken cancellationToken = default)
{
Dictionary<string, object> query = new Dictionary<string, object>();
query.Add("includeCancelled", includeCancelled);
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", queryPayload: query, method: HttpMethod.Get), cancellationToken);
return await HandleResponse<PayoutData[]>(response);
}
public async Task<PayoutData> CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest, CancellationToken cancellationToken = default)
public virtual async Task<PayoutData> CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", bodyPayload: payoutRequest, method: HttpMethod.Post), cancellationToken);
return await HandleResponse<PayoutData>(response);
}
public async Task CancelPayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
public virtual async Task CancelPayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", method: HttpMethod.Delete), cancellationToken);
await HandleResponse(response);
}
public async Task<PayoutData> ApprovePayout(string storeId, string payoutId, ApprovePayoutRequest request, CancellationToken cancellationToken = default)
public virtual async Task<PayoutData> ApprovePayout(string storeId, string payoutId, ApprovePayoutRequest request, CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", bodyPayload: request, method: HttpMethod.Post), cancellationToken);
return await HandleResponse<PayoutData>(response);

View File

@ -1,60 +1,56 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public async Task<StoreWebhookData> CreateWebhook(string storeId, Client.Models.CreateStoreWebhookRequest create, CancellationToken token = default)
public virtual async Task<StoreWebhookData> CreateWebhook(string storeId, Client.Models.CreateStoreWebhookRequest create, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks", bodyPayload: create, method: HttpMethod.Post), token);
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<StoreWebhookData> GetWebhook(string storeId, string webhookId, CancellationToken token = default)
public virtual async Task<StoreWebhookData> GetWebhook(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}"), token);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
return null;
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<StoreWebhookData> UpdateWebhook(string storeId, string webhookId, Models.UpdateStoreWebhookRequest update, CancellationToken token = default)
public virtual async Task<StoreWebhookData> UpdateWebhook(string storeId, string webhookId, Models.UpdateStoreWebhookRequest update, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}", bodyPayload: update, method: HttpMethod.Put), token);
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<bool> DeleteWebhook(string storeId, string webhookId, CancellationToken token = default)
public virtual async Task<bool> DeleteWebhook(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}", method: HttpMethod.Delete), token);
return response.IsSuccessStatusCode;
}
public async Task<StoreWebhookData[]> GetWebhooks(string storeId, CancellationToken token = default)
public virtual async Task<StoreWebhookData[]> GetWebhooks(string storeId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks"), token);
return await HandleResponse<StoreWebhookData[]>(response);
}
public async Task<WebhookDeliveryData[]> GetWebhookDeliveries(string storeId, string webhookId, CancellationToken token = default)
public virtual async Task<WebhookDeliveryData[]> GetWebhookDeliveries(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries"), token);
return await HandleResponse<WebhookDeliveryData[]>(response);
}
public async Task<WebhookDeliveryData> GetWebhookDelivery(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
public virtual async Task<WebhookDeliveryData> GetWebhookDelivery(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}"), token);
return await HandleResponse<WebhookDeliveryData>(response);
}
public async Task<string> RedeliverWebhook(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
public virtual async Task<string> RedeliverWebhook(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver", null, HttpMethod.Post), token);
return await HandleResponse<string>(response);
}
public async Task<WebhookEvent> GetWebhookDeliveryRequest(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
public virtual async Task<WebhookEvent> GetWebhookDeliveryRequest(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request"), token);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Controllers;
@ -20,8 +21,6 @@ using BTCPayServer.Tests.Logging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NBitcoin;
using NBitcoin.OpenAsset;
using NBitcoin.Payment;
using NBitpayClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -41,6 +40,23 @@ namespace BTCPayServer.Tests
Logs.LogProvider = new XUnitLogProvider(helper);
}
[Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")]
public async Task LocalClientTests()
{
using var tester = ServerTester.Create();
await tester.StartAsync();
var user = tester.NewAccount();
await user.GrantAccessAsync();
await user.MakeAdmin();
var factory = tester.PayTester.GetService<IBTCPayServerClientFactory>();
Assert.NotNull(factory);
var client = await factory.Create(user.UserId);
var u = await client.GetCurrentUser();
var s = await client.GetStores();
}
[Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")]
public async Task ApiKeysControllerTests()
@ -1066,26 +1082,31 @@ namespace BTCPayServer.Tests
Assert.Empty(invoices);
//list Filtered
var invoicesFiltered = await viewOnly.GetInvoices(user.StoreId,
orderId: null, status: null, DateTimeOffset.Now.AddHours(-1),
DateTimeOffset.Now.AddHours(1));
var invoicesFiltered = await viewOnly.GetInvoices(user.StoreId,
orderId: null, status: null, startDate: DateTimeOffset.Now.AddHours(-1),
endDate: DateTimeOffset.Now.AddHours(1));
Assert.NotNull(invoicesFiltered);
Assert.Single(invoicesFiltered);
Assert.Equal(newInvoice.Id, invoicesFiltered.First().Id);
Assert.NotNull(invoicesFiltered);
Assert.Single(invoicesFiltered);
Assert.Equal(newInvoice.Id, invoicesFiltered.First().Id);
//list Yesterday
var invoicesYesterday = await viewOnly.GetInvoices(user.StoreId,
orderId: null, status: null, DateTimeOffset.Now.AddDays(-2),
DateTimeOffset.Now.AddDays(-1));
Assert.NotNull(invoicesYesterday);
Assert.Empty(invoicesYesterday);
//list Yesterday
var invoicesYesterday = await viewOnly.GetInvoices(user.StoreId,
orderId: null, status: null, startDate: DateTimeOffset.Now.AddDays(-2),
endDate: DateTimeOffset.Now.AddDays(-1));
Assert.NotNull(invoicesYesterday);
Assert.Empty(invoicesYesterday);
// Error, startDate and endDate inverted
await AssertValidationError(new[] { "startDate", "endDate" },
() => viewOnly.GetInvoices(user.StoreId,
orderId: null, status: null, DateTimeOffset.Now.AddDays(-1),
DateTimeOffset.Now.AddDays(-2)));
orderId: null, status: null, startDate: DateTimeOffset.Now.AddDays(-1),
endDate: DateTimeOffset.Now.AddDays(-2)));
await AssertValidationError(new[] { "startDate" },
() => viewOnly.SendHttpRequest<Client.Models.InvoiceData[]>($"api/v1/stores/{user.StoreId}/invoices", new Dictionary<string, object>()
@ -1096,31 +1117,31 @@ namespace BTCPayServer.Tests
//list Existing OrderId
var invoicesExistingOrderId =
await viewOnly.GetInvoices(user.StoreId, orderId: newInvoice.Metadata["orderId"].ToString());
Assert.NotNull(invoicesExistingOrderId);
Assert.Single(invoicesFiltered);
Assert.Equal(newInvoice.Id, invoicesFiltered.First().Id);
await viewOnly.GetInvoices(user.StoreId, orderId: new []{newInvoice.Metadata["orderId"].ToString()});
Assert.NotNull(invoicesExistingOrderId);
Assert.Single(invoicesFiltered);
Assert.Equal(newInvoice.Id, invoicesFiltered.First().Id);
//list NonExisting OrderId
var invoicesNonExistingOrderId =
await viewOnly.GetInvoices(user.StoreId, orderId: "NonExistingOrderId");
Assert.NotNull(invoicesNonExistingOrderId);
Assert.Empty(invoicesNonExistingOrderId);
//list Existing Status
var invoicesExistingStatus =
await viewOnly.GetInvoices(user.StoreId, status: new[] { newInvoice.Status });
Assert.NotNull(invoicesExistingStatus);
Assert.Single(invoicesExistingStatus);
Assert.Equal(newInvoice.Id, invoicesExistingStatus.First().Id);
//list NonExisting Status
var invoicesNonExistingStatus = await viewOnly.GetInvoices(user.StoreId,
status: new[] { BTCPayServer.Client.Models.InvoiceStatus.Invalid });
Assert.NotNull(invoicesNonExistingStatus);
Assert.Empty(invoicesNonExistingStatus);
//list NonExisting OrderId
var invoicesNonExistingOrderId =
await viewOnly.GetInvoices(user.StoreId, orderId: new []{"NonExistingOrderId"});
Assert.NotNull(invoicesNonExistingOrderId);
Assert.Empty(invoicesNonExistingOrderId);
//list Existing Status
var invoicesExistingStatus =
await viewOnly.GetInvoices(user.StoreId, status: new []{newInvoice.Status});
Assert.NotNull(invoicesExistingStatus);
Assert.Single(invoicesExistingStatus);
Assert.Equal(newInvoice.Id, invoicesExistingStatus.First().Id);
//list NonExisting Status
var invoicesNonExistingStatus = await viewOnly.GetInvoices(user.StoreId,
status: new []{BTCPayServer.Client.Models.InvoiceStatus.Invalid});
Assert.NotNull(invoicesNonExistingStatus);
Assert.Empty(invoicesNonExistingStatus);
//get
var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
Assert.Equal(newInvoice.Metadata, invoice.Metadata);

View File

@ -10,13 +10,19 @@ namespace BTCPayServer.Controllers.GreenField
[EnableCors(CorsPolicies.All)]
public class HealthController : ControllerBase
{
private readonly NBXplorerDashboard _dashBoard;
public HealthController(NBXplorerDashboard dashBoard )
{
_dashBoard = dashBoard;
}
[AllowAnonymous]
[HttpGet("~/api/v1/health")]
public ActionResult GetHealth(NBXplorerDashboard dashBoard)
public ActionResult GetHealth()
{
ApiHealthData model = new ApiHealthData()
{
Synchronized = dashBoard.IsFullySynched()
Synchronized = _dashBoard.IsFullySynched()
};
return Ok(model);
}

View File

@ -0,0 +1,887 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Security.GreenField;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NBitcoin;
using YamlDotNet.Core.Tokens;
using InvoiceData = BTCPayServer.Client.Models.InvoiceData;
using Language = BTCPayServer.Client.Models.Language;
using NotificationData = BTCPayServer.Client.Models.NotificationData;
using PaymentRequestData = BTCPayServer.Client.Models.PaymentRequestData;
using PayoutData = BTCPayServer.Client.Models.PayoutData;
using PullPaymentData = BTCPayServer.Client.Models.PullPaymentData;
using StoreData = BTCPayServer.Client.Models.StoreData;
using StoreWebhookData = BTCPayServer.Client.Models.StoreWebhookData;
using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData;
namespace BTCPayServer.Controllers.GreenField
{
public class BTCPayServerClientFactory : IBTCPayServerClientFactory
{
private readonly StoreRepository _storeRepository;
private readonly IOptionsMonitor<IdentityOptions> _identityOptions;
private readonly StoreOnChainPaymentMethodsController _chainPaymentMethodsController;
private readonly StoreOnChainWalletsController _storeOnChainWalletsController;
private readonly StoreLightningNetworkPaymentMethodsController _storeLightningNetworkPaymentMethodsController;
private readonly HealthController _healthController;
private readonly GreenFieldPaymentRequestsController _paymentRequestController;
private readonly ApiKeysController _apiKeysController;
private readonly NotificationsController _notificationsController;
private readonly UsersController _usersController;
private readonly GreenFieldStoresController _storesController;
private readonly InternalLightningNodeApiController _internalLightningNodeApiController;
private readonly StoreLightningNodeApiController _storeLightningNodeApiController;
private readonly GreenFieldInvoiceController _greenFieldInvoiceController;
private readonly UserManager<ApplicationUser> _userManager;
private readonly GreenFieldServerInfoController _greenFieldServerInfoController;
private readonly StoreWebhooksController _storeWebhooksController;
private readonly GreenfieldPullPaymentController _greenfieldPullPaymentController;
private readonly HomeController _homeController;
private readonly StorePaymentMethodsController _storePaymentMethodsController;
public BTCPayServerClientFactory(StoreRepository storeRepository,
IOptionsMonitor<IdentityOptions> identityOptions,
StoreOnChainPaymentMethodsController chainPaymentMethodsController,
StoreOnChainWalletsController storeOnChainWalletsController,
StoreLightningNetworkPaymentMethodsController storeLightningNetworkPaymentMethodsController,
HealthController healthController,
GreenFieldPaymentRequestsController paymentRequestController,
ApiKeysController apiKeysController,
NotificationsController notificationsController,
UsersController usersController,
GreenFieldStoresController storesController,
InternalLightningNodeApiController internalLightningNodeApiController,
StoreLightningNodeApiController storeLightningNodeApiController,
GreenFieldInvoiceController greenFieldInvoiceController,
UserManager<ApplicationUser> userManager,
GreenFieldServerInfoController greenFieldServerInfoController,
StoreWebhooksController storeWebhooksController,
GreenfieldPullPaymentController greenfieldPullPaymentController,
HomeController homeController,
StorePaymentMethodsController storePaymentMethodsController)
{
_storeRepository = storeRepository;
_identityOptions = identityOptions;
_chainPaymentMethodsController = chainPaymentMethodsController;
_storeOnChainWalletsController = storeOnChainWalletsController;
_storeLightningNetworkPaymentMethodsController = storeLightningNetworkPaymentMethodsController;
_healthController = healthController;
_paymentRequestController = paymentRequestController;
_apiKeysController = apiKeysController;
_notificationsController = notificationsController;
_usersController = usersController;
_storesController = storesController;
_internalLightningNodeApiController = internalLightningNodeApiController;
_storeLightningNodeApiController = storeLightningNodeApiController;
_greenFieldInvoiceController = greenFieldInvoiceController;
_userManager = userManager;
_greenFieldServerInfoController = greenFieldServerInfoController;
_storeWebhooksController = storeWebhooksController;
_greenfieldPullPaymentController = greenfieldPullPaymentController;
_homeController = homeController;
_storePaymentMethodsController = storePaymentMethodsController;
}
public async Task<BTCPayServerClient> Create(string userId, params string[] storeIds)
{
var context = new DefaultHttpContext();
if (!string.IsNullOrEmpty(userId))
{
var user = await _userManager.FindByIdAsync(userId);
List<Claim> claims = new List<Claim>
{
new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, userId),
new Claim(GreenFieldConstants.ClaimTypes.Permission,
Permission.Create(Policies.Unrestricted).ToString())
};
claims.AddRange((await _userManager.GetRolesAsync(user)).Select(s =>
new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s)));
context.User =
new ClaimsPrincipal(new ClaimsIdentity(claims, GreenFieldConstants.AuthenticationType));
}
else
{
context.User =
new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>(), $"Local{GreenFieldConstants.AuthenticationType}"));
}
if (storeIds?.Any() is true)
{
context.SetStoreData(await _storeRepository.FindStore(storeIds.First()));
context.SetStoresData(await _storeRepository.GetStoresByUserId(userId, storeIds));
}
else
{
context.SetStoresData(await _storeRepository.GetStoresByUserId(userId));
}
return new LocalBTCPayServerClient(
_chainPaymentMethodsController,
_storeOnChainWalletsController,
_healthController,
_paymentRequestController,
_apiKeysController,
_notificationsController,
_usersController,
_storesController,
_storeLightningNodeApiController,
_internalLightningNodeApiController,
_storeLightningNetworkPaymentMethodsController,
_greenFieldInvoiceController,
_greenFieldServerInfoController,
_storeWebhooksController,
_greenfieldPullPaymentController,
_homeController,
_storePaymentMethodsController,
new HttpContextAccessor() {HttpContext = context}
);
}
}
public class LocalBTCPayServerClient : BTCPayServerClient
{
private readonly StoreOnChainPaymentMethodsController _chainPaymentMethodsController;
private readonly StoreOnChainWalletsController _storeOnChainWalletsController;
private readonly HealthController _healthController;
private readonly GreenFieldPaymentRequestsController _paymentRequestController;
private readonly ApiKeysController _apiKeysController;
private readonly NotificationsController _notificationsController;
private readonly UsersController _usersController;
private readonly GreenFieldStoresController _storesController;
private readonly StoreLightningNodeApiController _storeLightningNodeApiController;
private readonly InternalLightningNodeApiController _lightningNodeApiController;
private readonly StoreLightningNetworkPaymentMethodsController _storeLightningNetworkPaymentMethodsController;
private readonly GreenFieldInvoiceController _greenFieldInvoiceController;
private readonly GreenFieldServerInfoController _greenFieldServerInfoController;
private readonly StoreWebhooksController _storeWebhooksController;
private readonly GreenfieldPullPaymentController _greenfieldPullPaymentController;
private readonly HomeController _homeController;
private readonly StorePaymentMethodsController _storePaymentMethodsController;
public LocalBTCPayServerClient(StoreOnChainPaymentMethodsController chainPaymentMethodsController,
StoreOnChainWalletsController storeOnChainWalletsController,
HealthController healthController,
GreenFieldPaymentRequestsController paymentRequestController,
ApiKeysController apiKeysController,
NotificationsController notificationsController,
UsersController usersController,
GreenFieldStoresController storesController,
StoreLightningNodeApiController storeLightningNodeApiController,
InternalLightningNodeApiController lightningNodeApiController,
StoreLightningNetworkPaymentMethodsController storeLightningNetworkPaymentMethodsController,
GreenFieldInvoiceController greenFieldInvoiceController,
GreenFieldServerInfoController greenFieldServerInfoController,
StoreWebhooksController storeWebhooksController,
GreenfieldPullPaymentController greenfieldPullPaymentController,
HomeController homeController,
StorePaymentMethodsController storePaymentMethodsController,
IHttpContextAccessor httpContextAccessor) : base(new Uri("https://dummy.local"), "", "")
{
_chainPaymentMethodsController = chainPaymentMethodsController;
_storeOnChainWalletsController = storeOnChainWalletsController;
_healthController = healthController;
_paymentRequestController = paymentRequestController;
_apiKeysController = apiKeysController;
_notificationsController = notificationsController;
_usersController = usersController;
_storesController = storesController;
_storeLightningNodeApiController = storeLightningNodeApiController;
_lightningNodeApiController = lightningNodeApiController;
_storeLightningNetworkPaymentMethodsController = storeLightningNetworkPaymentMethodsController;
_greenFieldInvoiceController = greenFieldInvoiceController;
_greenFieldServerInfoController = greenFieldServerInfoController;
_storeWebhooksController = storeWebhooksController;
_greenfieldPullPaymentController = greenfieldPullPaymentController;
_homeController = homeController;
_storePaymentMethodsController = storePaymentMethodsController;
var controllers = new[]
{
chainPaymentMethodsController, storeOnChainWalletsController, healthController,
paymentRequestController, apiKeysController, notificationsController, usersController,
storeLightningNetworkPaymentMethodsController, greenFieldInvoiceController, storeWebhooksController,
greenFieldServerInfoController, greenfieldPullPaymentController, storesController, homeController,
lightningNodeApiController, storeLightningNodeApiController as ControllerBase, storePaymentMethodsController
};
foreach (var controller in controllers)
{
controller.ControllerContext.HttpContext = httpContextAccessor.HttpContext;
}
}
protected override HttpRequestMessage CreateHttpRequest(string path,
Dictionary<string, object> queryPayload = null, HttpMethod method = null)
{
throw new NotSupportedException("This method is not supported by the LocalBTCPayServerClient.");
}
public override async Task<StoreWebhookData> CreateWebhook(string storeId, CreateStoreWebhookRequest create,
CancellationToken token = default)
{
return GetFromActionResult<StoreWebhookData>(
await _storeWebhooksController.CreateWebhook(storeId, create));
}
public override async Task<StoreWebhookData> GetWebhook(string storeId, string webhookId,
CancellationToken token = default)
{
return GetFromActionResult<StoreWebhookData>(
await _storeWebhooksController.ListWebhooks(storeId, webhookId));
}
public override async Task<StoreWebhookData> UpdateWebhook(string storeId, string webhookId,
UpdateStoreWebhookRequest update,
CancellationToken token = default)
{
return GetFromActionResult<StoreWebhookData>(
await _storeWebhooksController.UpdateWebhook(storeId, webhookId, update));
}
public override async Task<bool> DeleteWebhook(string storeId, string webhookId,
CancellationToken token = default)
{
HandleActionResult(await _storeWebhooksController.DeleteWebhook(storeId, webhookId));
return true;
}
public override async Task<StoreWebhookData[]> GetWebhooks(string storeId, CancellationToken token = default)
{
return GetFromActionResult<StoreWebhookData[]>(
await _storeWebhooksController.ListWebhooks(storeId, null));
}
public override async Task<WebhookDeliveryData[]> GetWebhookDeliveries(string storeId, string webhookId,
CancellationToken token = default)
{
return GetFromActionResult<WebhookDeliveryData[]>(
await _storeWebhooksController.ListDeliveries(storeId, webhookId, null));
}
public override async Task<WebhookDeliveryData> GetWebhookDelivery(string storeId, string webhookId,
string deliveryId, CancellationToken token = default)
{
return GetFromActionResult<WebhookDeliveryData>(
await _storeWebhooksController.ListDeliveries(storeId, webhookId, deliveryId));
}
public override async Task<string> RedeliverWebhook(string storeId, string webhookId, string deliveryId,
CancellationToken token = default)
{
return GetFromActionResult<string>(
await _storeWebhooksController.RedeliverWebhook(storeId, webhookId, deliveryId));
}
public override async Task<WebhookEvent> GetWebhookDeliveryRequest(string storeId, string webhookId,
string deliveryId, CancellationToken token = default)
{
return GetFromActionResult<WebhookEvent>(
await _storeWebhooksController.GetDeliveryRequest(storeId, webhookId, deliveryId));
}
public override async Task<PullPaymentData> CreatePullPayment(string storeId, CreatePullPaymentRequest request,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PullPaymentData>(
await _greenfieldPullPaymentController.CreatePullPayment(storeId, request));
}
public override async Task<PullPaymentData> GetPullPayment(string pullPaymentId,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PullPaymentData>(
await _greenfieldPullPaymentController.GetPullPayment(pullPaymentId));
}
public override async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PullPaymentData[]>(
await _greenfieldPullPaymentController.GetPullPayments(storeId, includeArchived));
}
public override async Task ArchivePullPayment(string storeId, string pullPaymentId,
CancellationToken cancellationToken = default)
{
HandleActionResult(await _greenfieldPullPaymentController.ArchivePullPayment(storeId, pullPaymentId));
}
public override async Task<PayoutData[]> GetPayouts(string pullPaymentId, bool includeCancelled = false,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PayoutData[]>(
await _greenfieldPullPaymentController.GetPayouts(pullPaymentId, includeCancelled));
}
public override async Task<PayoutData> CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PayoutData>(
await _greenfieldPullPaymentController.CreatePayout(pullPaymentId, payoutRequest));
}
public override async Task CancelPayout(string storeId, string payoutId,
CancellationToken cancellationToken = default)
{
HandleActionResult(await _greenfieldPullPaymentController.CancelPayout(storeId, payoutId));
}
public override async Task<PayoutData> ApprovePayout(string storeId, string payoutId,
ApprovePayoutRequest request,
CancellationToken cancellationToken = default)
{
return GetFromActionResult<PayoutData>(
await _greenfieldPullPaymentController.ApprovePayout(storeId, payoutId, request, cancellationToken));
}
public override async Task<LightningNodeInformationData> GetLightningNodeInfo(string storeId, string cryptoCode,
CancellationToken token = default)
{
return GetFromActionResult<LightningNodeInformationData>(
await _storeLightningNodeApiController.GetInfo(cryptoCode));
}
public override async Task ConnectToLightningNode(string storeId, string cryptoCode,
ConnectToNodeRequest request,
CancellationToken token = default)
{
HandleActionResult(await _storeLightningNodeApiController.ConnectToNode(cryptoCode, request));
}
public override async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string storeId,
string cryptoCode, CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<LightningChannelData>>(
await _storeLightningNodeApiController.GetChannels(cryptoCode));
}
public override async Task OpenLightningChannel(string storeId, string cryptoCode,
OpenLightningChannelRequest request,
CancellationToken token = default)
{
HandleActionResult(await _storeLightningNodeApiController.OpenChannel(cryptoCode, request));
}
public override async Task<string> GetLightningDepositAddress(string storeId, string cryptoCode,
CancellationToken token = default)
{
return GetFromActionResult<string>(
await _storeLightningNodeApiController.GetDepositAddress(cryptoCode));
}
public override async Task PayLightningInvoice(string storeId, string cryptoCode,
PayLightningInvoiceRequest request,
CancellationToken token = default)
{
HandleActionResult(await _storeLightningNodeApiController.PayInvoice(cryptoCode, request));
}
public override async Task<LightningInvoiceData> GetLightningInvoice(string storeId, string cryptoCode,
string invoiceId, CancellationToken token = default)
{
return GetFromActionResult<LightningInvoiceData>(
await _storeLightningNodeApiController.GetInvoice(cryptoCode, invoiceId));
}
public override async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
CreateLightningInvoiceRequest request,
CancellationToken token = default)
{
return GetFromActionResult<LightningInvoiceData>(
await _storeLightningNodeApiController.CreateInvoice(cryptoCode, request));
}
public override async Task<LightningNodeInformationData> GetLightningNodeInfo(string cryptoCode,
CancellationToken token = default)
{
return GetFromActionResult<LightningNodeInformationData>(
await _lightningNodeApiController.GetInfo(cryptoCode));
}
public override async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
CancellationToken token = default)
{
HandleActionResult(await _lightningNodeApiController.ConnectToNode(cryptoCode, request));
}
public override async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string cryptoCode,
CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<LightningChannelData>>(
await _lightningNodeApiController.GetChannels(cryptoCode));
}
public override async Task OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request,
CancellationToken token = default)
{
HandleActionResult(await _lightningNodeApiController.OpenChannel(cryptoCode, request));
}
public override async Task<string> GetLightningDepositAddress(string cryptoCode,
CancellationToken token = default)
{
return GetFromActionResult<string>(
await _lightningNodeApiController.GetDepositAddress(cryptoCode));
}
public override async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
CancellationToken token = default)
{
HandleActionResult(await _lightningNodeApiController.PayInvoice(cryptoCode, request));
}
public override async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode, string invoiceId,
CancellationToken token = default)
{
return GetFromActionResult<LightningInvoiceData>(
await _lightningNodeApiController.GetInvoice(cryptoCode, invoiceId));
}
public override async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode,
CreateLightningInvoiceRequest request,
CancellationToken token = default)
{
return GetFromActionResult<LightningInvoiceData>(
await _lightningNodeApiController.CreateInvoice(cryptoCode, request));
}
private T GetFromActionResult<T>(IActionResult result)
{
HandleActionResult(result);
switch (result)
{
case JsonResult jsonResult:
return (T) jsonResult.Value;
case OkObjectResult {Value: T res}:
return res;
default:
return default;
}
}
private void HandleActionResult(IActionResult result)
{
switch (result)
{
case UnprocessableEntityObjectResult {Value: List<GreenfieldValidationError> validationErrors}:
throw new GreenFieldValidationException(validationErrors.ToArray());
case BadRequestObjectResult {Value: GreenfieldAPIError error}:
throw new GreenFieldAPIException(error);
case NotFoundResult _:
throw new GreenFieldAPIException(new GreenfieldAPIError("not-found", ""));
default:
return;
}
}
private T GetFromActionResult<T>(ActionResult result)
{
return GetFromActionResult<T>((IActionResult)result);
}
private T GetFromActionResult<T>(ActionResult<T> result)
{
return result.Value ?? GetFromActionResult<T>(result.Result);
}
public override Task<IEnumerable<OnChainPaymentMethodData>> GetStoreOnChainPaymentMethods(string storeId,
bool? enabled, CancellationToken token)
{
return Task.FromResult(GetFromActionResult(_chainPaymentMethodsController.GetOnChainPaymentMethods(storeId, enabled)));
}
public override async Task<OnChainPaymentMethodData> GetStoreOnChainPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
return GetFromActionResult(
await _chainPaymentMethodsController.GetOnChainPaymentMethod(storeId, cryptoCode));
}
public override async Task RemoveStoreOnChainPaymentMethod(string storeId, string cryptoCode,
CancellationToken token = default)
{
HandleActionResult(await _chainPaymentMethodsController.RemoveOnChainPaymentMethod(storeId, cryptoCode));
}
public override async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId,
string cryptoCode, OnChainPaymentMethodData paymentMethod,
CancellationToken token = default)
{
return GetFromActionResult<OnChainPaymentMethodData>(
await _chainPaymentMethodsController.UpdateOnChainPaymentMethod(storeId, cryptoCode, paymentMethod));
}
public override Task<OnChainPaymentMethodPreviewResultData> PreviewProposedStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode,
OnChainPaymentMethodData paymentMethod, int offset = 0, int amount = 10, CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult<OnChainPaymentMethodPreviewResultData>(
_chainPaymentMethodsController.GetProposedOnChainPaymentMethodPreview(storeId, cryptoCode,
paymentMethod, offset, amount)));
}
public override async Task<OnChainPaymentMethodPreviewResultData> PreviewStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, int offset = 0, int amount = 10,
CancellationToken token = default)
{
return GetFromActionResult<OnChainPaymentMethodPreviewResultData>(
await _chainPaymentMethodsController.GetOnChainPaymentMethodPreview(storeId, cryptoCode, offset,
amount));
}
public override Task<ApiHealthData> GetHealth(CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult<ApiHealthData>(_healthController.GetHealth()));
}
public override async Task<IEnumerable<PaymentRequestData>> GetPaymentRequests(string storeId,
bool includeArchived = false, CancellationToken token = default)
{
return GetFromActionResult(await _paymentRequestController.GetPaymentRequests(storeId, includeArchived));
}
public override async Task<PaymentRequestData> GetPaymentRequest(string storeId, string paymentRequestId,
CancellationToken token = default)
{
return GetFromActionResult(await _paymentRequestController.GetPaymentRequest(storeId, paymentRequestId));
}
public override async Task ArchivePaymentRequest(string storeId, string paymentRequestId,
CancellationToken token = default)
{
HandleActionResult(await _paymentRequestController.ArchivePaymentRequest(storeId, paymentRequestId));
}
public override async Task<PaymentRequestData> CreatePaymentRequest(string storeId,
CreatePaymentRequestRequest request, CancellationToken token = default)
{
return GetFromActionResult<PaymentRequestData>(
await _paymentRequestController.CreatePaymentRequest(storeId, request));
}
public override async Task<PaymentRequestData> UpdatePaymentRequest(string storeId, string paymentRequestId,
UpdatePaymentRequestRequest request,
CancellationToken token = default)
{
return GetFromActionResult<PaymentRequestData>(
await _paymentRequestController.UpdatePaymentRequest(storeId, paymentRequestId, request));
}
public override async Task<ApiKeyData> GetCurrentAPIKeyInfo(CancellationToken token = default)
{
return GetFromActionResult(await _apiKeysController.GetKey());
}
public override async Task<ApiKeyData> CreateAPIKey(CreateApiKeyRequest request,
CancellationToken token = default)
{
return GetFromActionResult<ApiKeyData>(await _apiKeysController.CreateKey(request));
}
public override async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
{
HandleActionResult(await _apiKeysController.RevokeCurrentKey());
}
public override async Task RevokeAPIKey(string apikey, CancellationToken token = default)
{
HandleActionResult(await _apiKeysController.RevokeKey(apikey));
}
public override async Task<IEnumerable<NotificationData>> GetNotifications(bool? seen = null,
CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<NotificationData>>(
await _notificationsController.GetNotifications(seen));
}
public override async Task<NotificationData> GetNotification(string notificationId,
CancellationToken token = default)
{
return GetFromActionResult<NotificationData>(
await _notificationsController.GetNotification(notificationId));
}
public override async Task<NotificationData> UpdateNotification(string notificationId, bool? seen,
CancellationToken token = default)
{
return GetFromActionResult<NotificationData>(
await _notificationsController.UpdateNotification(notificationId,
new UpdateNotification() {Seen = seen}));
}
public override async Task RemoveNotification(string notificationId, CancellationToken token = default)
{
HandleActionResult(await _notificationsController.DeleteNotification(notificationId));
}
public override async Task<ApplicationUserData> GetCurrentUser(CancellationToken token = default)
{
return GetFromActionResult(await _usersController.GetCurrentUser());
}
public override async Task<ApplicationUserData> CreateUser(CreateApplicationUserRequest request,
CancellationToken token = default)
{
return GetFromActionResult<ApplicationUserData>(await _usersController.CreateUser(request, token));
}
public override async Task<OnChainWalletOverviewData> ShowOnChainWalletOverview(string storeId,
string cryptoCode, CancellationToken token = default)
{
return GetFromActionResult<OnChainWalletOverviewData>(
await _storeOnChainWalletsController.ShowOnChainWalletOverview(storeId, cryptoCode));
}
public override async Task<OnChainWalletAddressData> GetOnChainWalletReceiveAddress(string storeId,
string cryptoCode, bool forceGenerate = false,
CancellationToken token = default)
{
return GetFromActionResult<OnChainWalletAddressData>(
await _storeOnChainWalletsController.GetOnChainWalletReceiveAddress(storeId, cryptoCode,
forceGenerate));
}
public override async Task UnReserveOnChainWalletReceiveAddress(string storeId, string cryptoCode,
CancellationToken token = default)
{
HandleActionResult(
await _storeOnChainWalletsController.UnReserveOnChainWalletReceiveAddress(storeId, cryptoCode));
}
public override async Task<IEnumerable<OnChainWalletTransactionData>> ShowOnChainWalletTransactions(
string storeId, string cryptoCode, TransactionStatus[] statusFilter = null,
CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<OnChainWalletTransactionData>>(
await _storeOnChainWalletsController.ShowOnChainWalletTransactions(storeId, cryptoCode, statusFilter));
}
public override async Task<OnChainWalletTransactionData> GetOnChainWalletTransaction(string storeId,
string cryptoCode, string transactionId,
CancellationToken token = default)
{
return GetFromActionResult<OnChainWalletTransactionData>(
await _storeOnChainWalletsController.GetOnChainWalletTransaction(storeId, cryptoCode, transactionId));
}
public override async Task<IEnumerable<OnChainWalletUTXOData>> GetOnChainWalletUTXOs(string storeId,
string cryptoCode, CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<OnChainWalletUTXOData>>(
await _storeOnChainWalletsController.GetOnChainWalletUTXOs(storeId, cryptoCode));
}
public override async Task<OnChainWalletTransactionData> CreateOnChainTransaction(string storeId,
string cryptoCode, CreateOnChainTransactionRequest request,
CancellationToken token = default)
{
if (!request.ProceedWithBroadcast)
{
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
"Please use CreateOnChainTransactionButDoNotBroadcast when wanting to only create the transaction");
}
return GetFromActionResult<OnChainWalletTransactionData>(
await _storeOnChainWalletsController.CreateOnChainTransaction(storeId, cryptoCode, request));
}
public override async Task<Transaction> CreateOnChainTransactionButDoNotBroadcast(string storeId,
string cryptoCode,
CreateOnChainTransactionRequest request, Network network, CancellationToken token = default)
{
if (request.ProceedWithBroadcast)
{
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
"Please use CreateOnChainTransaction when wanting to also broadcast the transaction");
}
return Transaction.Parse(
GetFromActionResult<string>(
await _storeOnChainWalletsController.CreateOnChainTransaction(storeId, cryptoCode, request)),
network);
}
public override async Task<IEnumerable<StoreData>> GetStores(CancellationToken token = default)
{
return GetFromActionResult(await _storesController.GetStores());
}
public override async Task<StoreData> GetStore(string storeId, CancellationToken token = default)
{
return GetFromActionResult(await _storesController.GetStore(storeId));
}
public override async Task RemoveStore(string storeId, CancellationToken token = default)
{
HandleActionResult(await _storesController.RemoveStore(storeId));
}
public override async Task<StoreData> CreateStore(CreateStoreRequest request, CancellationToken token = default)
{
return GetFromActionResult<StoreData>(await _storesController.CreateStore(request));
}
public override async Task<StoreData> UpdateStore(string storeId, UpdateStoreRequest request,
CancellationToken token = default)
{
return GetFromActionResult<StoreData>(await _storesController.UpdateStore(storeId, request));
}
public override Task<IEnumerable<LightningNetworkPaymentMethodData>>
GetStoreLightningNetworkPaymentMethods(string storeId, bool? enabled,
CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult(
_storeLightningNetworkPaymentMethodsController.GetLightningPaymentMethods(storeId, enabled)));
}
public override Task<LightningNetworkPaymentMethodData> GetStoreLightningNetworkPaymentMethod(
string storeId, string cryptoCode, CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult(
_storeLightningNetworkPaymentMethodsController.GetLightningNetworkPaymentMethod(storeId, cryptoCode)));
}
public override async Task RemoveStoreLightningNetworkPaymentMethod(string storeId, string cryptoCode,
CancellationToken token = default)
{
HandleActionResult(
await _storeLightningNetworkPaymentMethodsController.RemoveLightningNetworkPaymentMethod(storeId,
cryptoCode));
}
public override async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod(
string storeId, string cryptoCode,
LightningNetworkPaymentMethodData paymentMethod, CancellationToken token = default)
{
return GetFromActionResult<LightningNetworkPaymentMethodData>(await
_storeLightningNetworkPaymentMethodsController.UpdateLightningNetworkPaymentMethod(storeId, cryptoCode,
paymentMethod));
}
public override async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string[] orderId = null,
InvoiceStatus[] status = null,
DateTimeOffset? startDate = null,
DateTimeOffset? endDate = null,
string textSearch = null,
bool includeArchived = false,
CancellationToken token = default)
{
return GetFromActionResult<IEnumerable<InvoiceData>>(
await _greenFieldInvoiceController.GetInvoices(storeId, orderId,
status?.Select(invoiceStatus => invoiceStatus.ToString())?.ToArray(), startDate,
endDate, textSearch, includeArchived));
}
public override async Task<InvoiceData> GetInvoice(string storeId, string invoiceId,
CancellationToken token = default)
{
return GetFromActionResult<InvoiceData>(await _greenFieldInvoiceController.GetInvoice(storeId, invoiceId));
}
public override async Task<InvoicePaymentMethodDataModel[]> GetInvoicePaymentMethods(string storeId,
string invoiceId, CancellationToken token = default)
{
return GetFromActionResult<InvoicePaymentMethodDataModel[]>(
await _greenFieldInvoiceController.GetInvoicePaymentMethods(storeId, invoiceId));
}
public override async Task ArchiveInvoice(string storeId, string invoiceId, CancellationToken token = default)
{
HandleActionResult(await _greenFieldInvoiceController.ArchiveInvoice(storeId, invoiceId));
}
public override async Task<InvoiceData> CreateInvoice(string storeId, CreateInvoiceRequest request,
CancellationToken token = default)
{
return GetFromActionResult<InvoiceData>(await _greenFieldInvoiceController.CreateInvoice(storeId, request));
}
public override async Task<InvoiceData> UpdateInvoice(string storeId, string invoiceId,
UpdateInvoiceRequest request, CancellationToken token = default)
{
return GetFromActionResult<InvoiceData>(
await _greenFieldInvoiceController.UpdateInvoice(storeId, invoiceId, request));
}
public override async Task<InvoiceData> MarkInvoiceStatus(string storeId, string invoiceId,
MarkInvoiceStatusRequest request,
CancellationToken token = default)
{
return GetFromActionResult<InvoiceData>(
await _greenFieldInvoiceController.MarkInvoiceStatus(storeId, invoiceId, request));
}
public override async Task<InvoiceData> UnarchiveInvoice(string storeId, string invoiceId,
CancellationToken token = default)
{
return GetFromActionResult<InvoiceData>(
await _greenFieldInvoiceController.UnarchiveInvoice(storeId, invoiceId));
}
public override Task<ServerInfoData> GetServerInfo(CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult<ServerInfoData>(_greenFieldServerInfoController.ServerInfo()));
}
public override async Task ActivateInvoicePaymentMethod(string storeId, string invoiceId, string paymentMethod,
CancellationToken token = default)
{
HandleActionResult(
await _greenFieldInvoiceController.ActivateInvoicePaymentMethod(storeId, invoiceId, paymentMethod));
}
public override async Task<OnChainWalletFeeRateData> GetOnChainFeeRate(string storeId, string cryptoCode,
int? blockTarget = null, CancellationToken token = default)
{
return GetFromActionResult<OnChainWalletFeeRateData>(
await _storeOnChainWalletsController.GetOnChainFeeRate(storeId, cryptoCode, blockTarget));
}
public override async Task DeleteCurrentUser(CancellationToken token = default)
{
HandleActionResult(await _usersController.DeleteCurrentUser());
}
public override async Task DeleteUser(string userId, CancellationToken token = default)
{
HandleActionResult(await _usersController.DeleteUser(userId));
}
public override Task<Language[]> GetAvailableLanguages(CancellationToken token = default)
{
return Task.FromResult(_homeController.LanguageService.GetLanguages().Select(language => new Language(language.Code, language.DisplayName)).ToArray());
}
public override Task<PermissionMetadata[]> GetPermissionMetadata(CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult<PermissionMetadata[]>(_homeController.Permissions()));
}
public override async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId, string cryptoCode,
CancellationToken token = default)
{
//nothing to change, just local client sugar
return await base.UpdateStoreLightningNetworkPaymentMethodToInternalNode(storeId, cryptoCode, token);
}
public override Task<Dictionary<string, GenericPaymentMethodData>> GetStorePaymentMethods(string storeId, bool? enabled = null, CancellationToken token = default)
{
return Task.FromResult(GetFromActionResult(_storePaymentMethodsController.GetStorePaymentMethods(storeId, enabled)));
}
}
}

View File

@ -33,7 +33,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewPaymentRequests, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-requests")]
public async Task<ActionResult<IEnumerable<PaymentRequestData>>> GetPaymentRequests(string storeId, bool includeArchived = false)
public async Task<ActionResult<IEnumerable<Client.Models.PaymentRequestData>>> GetPaymentRequests(string storeId, bool includeArchived = false)
{
var prs = await _paymentRequestRepository.FindPaymentRequests(
new PaymentRequestQuery() { StoreId = storeId, IncludeArchived = includeArchived });
@ -42,7 +42,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewPaymentRequests, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-requests/{paymentRequestId}")]
public async Task<ActionResult<PaymentRequestData>> GetPaymentRequest(string storeId, string paymentRequestId)
public async Task<ActionResult<Client.Models.PaymentRequestData>> GetPaymentRequest(string storeId, string paymentRequestId)
{
var pr = await _paymentRequestRepository.FindPaymentRequests(
new PaymentRequestQuery() { StoreId = storeId, Ids = new[] { paymentRequestId } });

View File

@ -67,6 +67,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork")]
public ActionResult<IEnumerable<LightningNetworkPaymentMethodData>> GetLightningPaymentMethods(
string storeId,
[FromQuery] bool? enabled)
{
return Ok(GetLightningPaymentMethods(Store, _btcPayNetworkProvider, enabled));
@ -74,7 +75,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
public ActionResult<LightningNetworkPaymentMethodData> GetLightningNetworkPaymentMethod(string cryptoCode)
public ActionResult<LightningNetworkPaymentMethodData> GetLightningNetworkPaymentMethod(string storeId, string cryptoCode)
{
if (!GetNetwork(cryptoCode, out BTCPayNetwork _))
{
@ -93,6 +94,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
public async Task<IActionResult> RemoveLightningNetworkPaymentMethod(
string storeId,
string cryptoCode,
int offset = 0, int amount = 10)
{
@ -110,7 +112,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPut("~/api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}")]
public async Task<IActionResult> UpdateLightningNetworkPaymentMethod(string cryptoCode,
public async Task<IActionResult> UpdateLightningNetworkPaymentMethod(string storeId, string cryptoCode,
[FromBody] LightningNetworkPaymentMethodData paymentMethodData)
{
var paymentMethodId = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike);

View File

@ -54,6 +54,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/onchain")]
public ActionResult<IEnumerable<OnChainPaymentMethodData>> GetOnChainPaymentMethods(
string storeId,
[FromQuery] bool? enabled)
{
return Ok(GetOnChainPaymentMethods(Store, _btcPayNetworkProvider, enabled));
@ -61,7 +62,9 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}")]
public ActionResult<OnChainPaymentMethodData> GetOnChainPaymentMethod(string cryptoCode)
public async Task<ActionResult<OnChainPaymentMethodData>> GetOnChainPaymentMethod(
string storeId,
string cryptoCode)
{
if (!GetCryptoCodeWallet(cryptoCode, out BTCPayNetwork _, out BTCPayWallet _))
{
@ -79,7 +82,8 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/preview")]
public IActionResult GetOnChainPaymentMethodPreview(
public async Task<IActionResult> GetOnChainPaymentMethodPreview(
string storeId,
string cryptoCode,
int offset = 0, int amount = 10)
{
@ -126,7 +130,9 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPost("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/preview")]
public IActionResult GetProposedOnChainPaymentMethodPreview(string cryptoCode,
public IActionResult GetProposedOnChainPaymentMethodPreview(
string storeId,
string cryptoCode,
[FromBody] OnChainPaymentMethodData paymentMethodData,
int offset = 0, int amount = 10)
{
@ -179,6 +185,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}")]
public async Task<IActionResult> RemoveOnChainPaymentMethod(
string storeId,
string cryptoCode,
int offset = 0, int amount = 10)
{
@ -196,7 +203,9 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPut("~/api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}")]
public async Task<IActionResult> UpdateOnChainPaymentMethod(string cryptoCode,
public async Task<IActionResult> UpdateOnChainPaymentMethod(
string storeId,
string cryptoCode,
[FromBody] OnChainPaymentMethodData paymentMethodData)
{
var id = new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike);

View File

@ -26,6 +26,7 @@ namespace BTCPayServer.Controllers.GreenField
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}/payment-methods")]
public ActionResult<Dictionary<string, GenericPaymentMethodData>> GetStorePaymentMethods(
string storeId,
[FromQuery] bool? enabled)
{
var storeBlob = Store.GetStoreBlob();

View File

@ -36,7 +36,7 @@ namespace BTCPayServer.Controllers.GreenField
public WebhookNotificationManager WebhookNotificationManager { get; }
[HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId?}")]
public async Task<IActionResult> ListWebhooks(string webhookId)
public async Task<IActionResult> ListWebhooks(string storeId, string webhookId)
{
if (webhookId is null)
{
@ -62,7 +62,7 @@ namespace BTCPayServer.Controllers.GreenField
}
[HttpPost("~/api/v1/stores/{storeId}/webhooks")]
public async Task<IActionResult> CreateWebhook(Client.Models.CreateStoreWebhookRequest create)
public async Task<IActionResult> CreateWebhook(string storeId, Client.Models.CreateStoreWebhookRequest create)
{
ValidateWebhookRequest(create);
if (!ModelState.IsValid)
@ -90,10 +90,10 @@ namespace BTCPayServer.Controllers.GreenField
if (w is null)
return WebhookNotFound();
await StoreRepository.UpdateWebhook(storeId, webhookId, ToModel(update));
return await ListWebhooks(webhookId);
return await ListWebhooks(storeId, webhookId);
}
[HttpDelete("~/api/v1/stores/{storeId}/webhooks/{webhookId}")]
public async Task<IActionResult> DeleteWebhook(string webhookId)
public async Task<IActionResult> DeleteWebhook(string storeId, string webhookId)
{
var w = await StoreRepository.GetWebhook(CurrentStoreId, webhookId);
if (w is null)
@ -130,7 +130,7 @@ namespace BTCPayServer.Controllers.GreenField
[HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId?}")]
public async Task<IActionResult> ListDeliveries(string webhookId, string deliveryId, int? count = null)
public async Task<IActionResult> ListDeliveries(string storeId, string webhookId, string deliveryId, int? count = null)
{
if (deliveryId is null)
{
@ -147,7 +147,7 @@ namespace BTCPayServer.Controllers.GreenField
}
}
[HttpPost("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver")]
public async Task<IActionResult> RedeliverWebhook(string webhookId, string deliveryId)
public async Task<IActionResult> RedeliverWebhook(string storeId, string webhookId, string deliveryId)
{
var delivery = await StoreRepository.GetWebhookDelivery(CurrentStoreId, webhookId, deliveryId);
if (delivery is null)
@ -156,7 +156,7 @@ namespace BTCPayServer.Controllers.GreenField
}
[HttpGet("~/api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request")]
public async Task<IActionResult> GetDeliveryRequest(string webhookId, string deliveryId)
public async Task<IActionResult> GetDeliveryRequest(string storeId, string webhookId, string deliveryId)
{
var delivery = await StoreRepository.GetWebhookDelivery(CurrentStoreId, webhookId, deliveryId);
if (delivery is null)

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers.GreenField
{
@ -33,22 +34,22 @@ namespace BTCPayServer.Controllers.GreenField
}
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores")]
public ActionResult<IEnumerable<Client.Models.StoreData>> GetStores()
public Task<ActionResult<IEnumerable<Client.Models.StoreData>>> GetStores()
{
var stores = HttpContext.GetStoresData();
return Ok(stores.Select(FromModel));
return Task.FromResult<ActionResult<IEnumerable<Client.Models.StoreData>>>(Ok(stores.Select(FromModel)));
}
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}")]
public ActionResult<Client.Models.StoreData> GetStore(string storeId)
public Task<ActionResult<Client.Models.StoreData>> GetStore(string storeId)
{
var store = HttpContext.GetStoreData();
if (store == null)
{
return NotFound();
return Task.FromResult<ActionResult<Client.Models.StoreData>>(NotFound());
}
return Ok(FromModel(store));
return Task.FromResult<ActionResult<Client.Models.StoreData>>(Ok(FromModel(store)));
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]

View File

@ -20,11 +20,13 @@ namespace BTCPayServer.Controllers.GreenField
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly StoreRepository _storeRepository;
private readonly BTCPayServerClient _localBTCPayServerClient;
public TestApiKeyController(UserManager<ApplicationUser> userManager, StoreRepository storeRepository)
public TestApiKeyController(UserManager<ApplicationUser> userManager, StoreRepository storeRepository, BTCPayServerClient localBTCPayServerClient)
{
_userManager = userManager;
_storeRepository = storeRepository;
_localBTCPayServerClient = localBTCPayServerClient;
}
[HttpGet("me/id")]

View File

@ -6,8 +6,10 @@ using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Common;
using BTCPayServer.Client;
using BTCPayServer.Configuration;
using BTCPayServer.Controllers;
using BTCPayServer.Controllers.GreenField;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Lightning;
@ -378,6 +380,11 @@ namespace BTCPayServer.Hosting
services.AddTransient<PaymentRequestController>();
// Add application services.
services.AddSingleton<EmailSenderFactory>();
//create a simple client which hooks up to the http scope
services.AddScoped<BTCPayServerClient, LocalBTCPayServerClient>();
//also provide a factory that can impersonate user/store id
services.AddSingleton<IBTCPayServerClientFactory, BTCPayServerClientFactory>();
services.AddAPIKeyAuthentication();
services.AddBtcPayServerAuthenticationSchemes();

View File

@ -37,6 +37,7 @@ namespace BTCPayServer.Security.GreenField
{
serviceCollection.AddSingleton<APIKeyRepository>();
serviceCollection.AddScoped<IAuthorizationHandler, GreenFieldAuthorizationHandler>();
serviceCollection.AddScoped<IAuthorizationHandler, LocalGreenFieldAuthorizationHandler>();
return serviceCollection;
}

View File

@ -16,7 +16,6 @@ namespace BTCPayServer.Security.GreenField
{
private readonly APIKeyRepository _apiKeyRepository;
private readonly IOptionsMonitor<IdentityOptions> _identityOptions;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
public APIKeysAuthenticationHandler(
@ -26,12 +25,10 @@ namespace BTCPayServer.Security.GreenField
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager) : base(options, logger, encoder, clock)
{
_apiKeyRepository = apiKeyRepository;
_identityOptions = identityOptions;
_signInManager = signInManager;
_userManager = userManager;
}

View File

@ -9,6 +9,20 @@ using Microsoft.AspNetCore.Identity;
namespace BTCPayServer.Security.GreenField
{
public class LocalGreenFieldAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
{
var succeed = context.User.Identity.AuthenticationType == $"Local{GreenFieldConstants.AuthenticationType}";
if (succeed)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class GreenFieldAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{

View File

@ -71,7 +71,7 @@ namespace BTCPayServer.Services.Notifications
var queryables = GetNotificationsQueryable(dbContext, query);
return (Items: (await queryables.withPaging.ToListAsync()).Select(ToViewModel).ToList(),
return (Items: (await queryables.withPaging.ToListAsync()).Select(ToViewModel).Where(model => model != null).ToList(),
Count: await queryables.withoutPaging.CountAsync());
}
@ -125,7 +125,7 @@ namespace BTCPayServer.Services.Notifications
await dbContext.SaveChangesAsync();
InvalidateNotificationCache(userIds.ToArray());
return items.Select(ToViewModel).ToList();
return items.Select(ToViewModel).Where(model => model != null).ToList();
}
public async Task Remove(NotificationsQuery notificationsQuery)
@ -144,6 +144,8 @@ namespace BTCPayServer.Services.Notifications
private NotificationViewModel ToViewModel(NotificationData data)
{
var handler = GetHandler(data.NotificationType);
if (handler is null)
return null;
var notification = JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), handler.NotificationBlobType);
var obj = new NotificationViewModel {Id = data.Id, Created = data.Created, Seen = data.Seen};
handler.FillViewModel(notification, obj);
@ -152,9 +154,8 @@ namespace BTCPayServer.Services.Notifications
public INotificationHandler GetHandler(string notificationId)
{
if (_handlersByNotificationType.TryGetValue(notificationId, out var h))
return h;
throw new InvalidOperationException($"No INotificationHandler found for {notificationId}");
_handlersByNotificationType.TryGetValue(notificationId, out var h);
return h;
}
}