Importing hosted service that will register transactions on Shopify

This commit is contained in:
rockstardev
2020-09-13 17:14:36 -05:00
committed by Kukks
parent 8a68e1b49d
commit 0af4be3d99
2 changed files with 146 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Services.Shopify
{
public class OrderTransactionRegisterLogic
{
private readonly ShopifyApiClient _client;
public OrderTransactionRegisterLogic(ShopifyApiClient client)
{
_client = client;
}
public async Task<dynamic> Process(string orderId, string currency = null, string amountCaptured = null)
{
dynamic resp = await _client.TransactionsList(orderId);
JArray transactions = resp.transactions;
if (transactions != null && transactions.Count >= 1)
{
dynamic transaction = transactions[0];
if (currency != null && currency.Equals(transaction.currency, StringComparison.OrdinalIgnoreCase))
{
// because of parent_id present, currency will always be the one from parent transaction
// malicious attacker could potentially exploit this by creating invoice
// in different currency and paying that one, registering order on Shopify as paid
// so if currency is supplied and is different from parent transaction currency we just won't register
return null;
}
var createTransaction = new TransactionCreate
{
transaction = new TransactionCreate.DataHolder
{
parent_id = transaction.id,
currency = transaction.currency,
amount = amountCaptured ?? transaction.amount,
kind = "capture",
gateway = "BTCPayServer",
source = "external"
}
};
dynamic createResp = await _client.TransactionCreate(orderId, createTransaction);
return createResp;
}
return null;
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Logging;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Stores;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NBXplorer;
namespace BTCPayServer.Services.Shopify
{
public class ShopifyOrderMarkerHostedService : IHostedService
{
private readonly EventAggregator _eventAggregator;
private readonly StoreRepository _storeRepository;
private readonly IHttpClientFactory _httpClientFactory;
public ShopifyOrderMarkerHostedService(EventAggregator eventAggregator, StoreRepository storeRepository, IHttpClientFactory httpClientFactory)
{
_eventAggregator = eventAggregator;
_storeRepository = storeRepository;
_httpClientFactory = httpClientFactory;
}
private CancellationTokenSource _Cts;
private readonly CompositeDisposable leases = new CompositeDisposable();
public Task StartAsync(CancellationToken cancellationToken)
{
_Cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
leases.Add(_eventAggregator.Subscribe<Events.InvoiceEvent>(async b =>
{
var invoice = b.Invoice;
var shopifyOrderId = invoice.Metadata?.OrderId;
if (invoice.Status == Client.Models.InvoiceStatus.Paid && shopifyOrderId != null)
{
var storeData = await _storeRepository.FindStore(invoice.StoreId);
var storeBlob = storeData.GetStoreBlob();
if (storeBlob.Shopify?.IntegratedAt.HasValue == true)
{
var client = createShopifyApiClient(storeBlob.Shopify);
try
{
var logic = new OrderTransactionRegisterLogic(client);
await logic.Process(shopifyOrderId, invoice.Currency, invoice.Price.ToString(CultureInfo.InvariantCulture));
Logs.PayServer.LogInformation("Registered order transaction on Shopify. " +
$"Triggered by invoiceId: {invoice.Id}, Shopify orderId: {shopifyOrderId}");
}
catch (Exception ex)
{
Logs.PayServer.LogError(ex, $"Shopify error while trying to register order transaction. " +
$"Triggered by invoiceId: {invoice.Id}, Shopify orderId: {shopifyOrderId}");
}
}
}
}));
return Task.CompletedTask;
}
private ShopifyApiClient createShopifyApiClient(StoreBlob.ShopifyDataHolder shopify)
{
return new ShopifyApiClient(_httpClientFactory, null, new ShopifyApiClientCredentials
{
ShopName = shopify.ShopName,
ApiKey = shopify.ApiKey,
ApiPassword = shopify.Password,
SharedSecret = shopify.SharedSecret
});
}
public Task StopAsync(CancellationToken cancellationToken)
{
_Cts?.Cancel();
leases.Dispose();
return Task.CompletedTask;
}
}
}