Add btcpay.store.cancreateinvoice claim, and use that for the store

This commit is contained in:
nicolas.dorier 2018-09-08 14:32:26 +09:00
parent e86b4d89ca
commit fed53661b3
14 changed files with 44 additions and 43 deletions

View file

@ -2,9 +2,11 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Security;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Rates;
using Microsoft.AspNetCore.Authorization;
@ -46,7 +48,7 @@ namespace BTCPayServer.Controllers
Items = _AppsHelper.Parse(settings.Template, settings.Currency)
});
}
[HttpPost]
[Route("/apps/{appId}/pos")]
[IgnoreAntiforgeryToken]
@ -90,6 +92,7 @@ namespace BTCPayServer.Controllers
title = settings.Title;
}
var store = await _AppsHelper.GetStore(app);
store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id));
var invoice = await _InvoiceController.CreateInvoiceCore(new NBitpayClient.Invoice()
{
ItemDesc = title,

View file

@ -14,7 +14,7 @@ namespace BTCPayServer.Controllers
{
[EnableCors("BitpayAPI")]
[BitpayAPIConstraint]
[Authorize(Policies.CanUseStore.Key, AuthenticationSchemes = Policies.BitpayAuthentication)]
[Authorize(Policies.CanCreateInvoice.Key, AuthenticationSchemes = Policies.BitpayAuthentication)]
public class InvoiceControllerAPI : Controller
{
private InvoiceController _InvoiceController;

View file

@ -499,7 +499,7 @@ namespace BTCPayServer.Controllers
return View(model);
}
StatusMessage = null;
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
if (!store.HasClaim(Policies.CanCreateInvoice.Key))
{
ModelState.AddModelError(nameof(model.StoreId), "You need to be owner of this store to create an invoice");
return View(model);

View file

@ -62,6 +62,8 @@ namespace BTCPayServer.Controllers
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
{
if (!store.HasClaim(Policies.CanCreateInvoice.Key))
throw new UnauthorizedAccessException();
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting");
var entity = new InvoiceEntity

View file

@ -33,7 +33,7 @@ namespace BTCPayServer.Controllers
else
{
var storeBlob = store.GetStoreBlob();
if (!storeBlob.PayButtonEnabled)
if (!storeBlob.AnyoneCanInvoice)
ModelState.AddModelError("Store", "Store has not enabled Pay Button");
}

View file

@ -399,6 +399,7 @@ namespace BTCPayServer.Controllers
vm.StoreName = store.StoreName;
vm.StoreWebsite = store.StoreWebsite;
vm.NetworkFee = !storeBlob.NetworkFeeDisabled;
vm.AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice;
vm.SpeedPolicy = store.SpeedPolicy;
vm.CanDelete = _Repo.CanDeleteStores();
AddPaymentMethods(store, storeBlob, vm);
@ -470,6 +471,7 @@ namespace BTCPayServer.Controllers
}
var blob = StoreData.GetStoreBlob();
blob.AnyoneCanInvoice = model.AnyoneCanCreateInvoice;
blob.NetworkFeeDisabled = !model.NetworkFee;
blob.MonitoringExpiration = model.MonitoringExpiration;
blob.InvoiceExpiration = model.InvoiceExpiration;
@ -777,7 +779,7 @@ namespace BTCPayServer.Controllers
var store = StoreData;
var storeBlob = store.GetStoreBlob();
if (!storeBlob.PayButtonEnabled)
if (!storeBlob.AnyoneCanInvoice)
{
return View("PayButtonEnable", null);
}
@ -800,7 +802,7 @@ namespace BTCPayServer.Controllers
public async Task<IActionResult> PayButton(bool enableStore)
{
var blob = StoreData.GetStoreBlob();
blob.PayButtonEnabled = enableStore;
blob.AnyoneCanInvoice = enableStore;
if (StoreData.SetStoreBlob(blob))
{
await _Repo.UpdateStore(StoreData);

View file

@ -166,24 +166,25 @@ namespace BTCPayServer.Data
public Claim[] GetClaims()
{
List<Claim> claims = new List<Claim>();
claims.AddRange(AdditionalClaims);
#pragma warning disable CS0612 // Type or member is obsolete
var role = Role;
#pragma warning restore CS0612 // Type or member is obsolete
if (role == StoreRoles.Owner)
{
claims.Add(new Claim(Policies.CanModifyStoreSettings.Key, Id));
claims.Add(new Claim(Policies.CanUseStore.Key, Id));
}
if (role == StoreRoles.Guest)
if(role == StoreRoles.Owner || role == StoreRoles.Guest || GetStoreBlob().AnyoneCanInvoice)
{
claims.Add(new Claim(Policies.CanUseStore.Key, Id));
claims.Add(new Claim(Policies.CanCreateInvoice.Key, Id));
}
return claims.ToArray();
}
public bool HasClaim(string claim)
{
return GetClaims().Any(c => c.Type == claim);
return GetClaims().Any(c => c.Type == claim && c.Value == Id);
}
public byte[] StoreBlob
@ -196,6 +197,9 @@ namespace BTCPayServer.Data
public List<PairedSINData> PairedSINs { get; set; }
public IEnumerable<APIKeyData> APIKeys { get; set; }
[NotMapped]
public List<Claim> AdditionalClaims { get; set; } = new List<Claim>();
#pragma warning disable CS0618
public string GetDefaultCrypto(BTCPayNetworkProvider networkProvider = null)
{
@ -302,7 +306,7 @@ namespace BTCPayServer.Data
public string RateScript { get; set; }
public bool PayButtonEnabled { get; set; }
public bool AnyoneCanInvoice { get; set; }
string _LightningDescriptionTemplate;

View file

@ -47,6 +47,9 @@ namespace BTCPayServer.Models.StoreViewModels
set;
}
[Display(Name = "Allow anyone to create invoice")]
public bool AnyoneCanCreateInvoice { get; set; }
public List<StoreViewModel.DerivationScheme> DerivationSchemes { get; set; } = new List<StoreViewModel.DerivationScheme>();
[Display(Name = "Invoice expires if the full amount has not been paid after ... minutes")]

View file

@ -88,8 +88,9 @@ namespace BTCPayServer.Security
{
if (storeId != null)
{
claims.Add(new Claim(Policies.CanUseStore.Key, storeId));
claims.Add(new Claim(Policies.CanCreateInvoice.Key, storeId));
var store = await _StoreRepository.FindStore(storeId);
store.AdditionalClaims.AddRange(claims);
Context.Request.HttpContext.SetStoreData(store);
}
return AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity(claims, Policies.BitpayAuthentication)), Policies.BitpayAuthentication));

View file

@ -12,9 +12,9 @@ namespace BTCPayServer.Security
public const string CookieAuthentication = "Identity.Application";
public static AuthorizationOptions AddBTCPayPolicies(this AuthorizationOptions options)
{
AddClaim(options, CanUseStore.Key);
AddClaim(options, CanModifyStoreSettings.Key);
AddClaim(options, CanModifyServerSettings.Key);
AddClaim(options, CanCreateInvoice.Key);
return options;
}
@ -27,13 +27,14 @@ namespace BTCPayServer.Security
{
public const string Key = "btcpay.store.canmodifyserversettings";
}
public class CanUseStore
{
public const string Key = "btcpay.store.canusestore";
}
public class CanModifyStoreSettings
{
public const string Key = "btcpay.store.canmodifystoresettings";
}
public class CanCreateInvoice
{
public const string Key = "btcpay.store.cancreateinvoice";
}
}
}

View file

@ -148,7 +148,7 @@ namespace BTCPayServer.Services.Invoices
}
context.PendingInvoices.Add(new PendingInvoiceData() { Id = invoice.Id });
foreach(var log in creationLogs.ToList())
foreach (var log in creationLogs.ToList())
{
context.InvoiceEvents.Add(new InvoiceEventData()
{
@ -249,7 +249,7 @@ namespace BTCPayServer.Services.Invoices
{
await context.SaveChangesAsync();
}
catch(DbUpdateException) { } // Probably the invoice does not exists anymore
catch (DbUpdateException) { } // Probably the invoice does not exists anymore
}
}
@ -441,7 +441,7 @@ namespace BTCPayServer.Services.Invoices
query = query.Where(i => statusSet.Contains(i.Status));
}
if(queryObject.Unusual != null)
if (queryObject.Unusual != null)
{
var unused = queryObject.Unusual.Value;
query = query.Where(i => unused == (i.Status == "invalid" || i.ExceptionStatus != null));
@ -554,7 +554,7 @@ namespace BTCPayServer.Services.Invoices
{
await context.SaveChangesAsync().ConfigureAwait(false);
}
catch(DbUpdateException) { return null; } // Already exists
catch (DbUpdateException) { return null; } // Already exists
AddToTextSearch(invoiceId, paymentData.GetSearchTerms());
return entity;
}

View file

@ -122,25 +122,6 @@
</div>
</div>
<br /><br />
<hr />
<h3>Disable Pay Button</h3>
<div class="row">
<div class="col-md-10">
<form method="post">
<div class="form-group">
<p>
Disabling this feature will cause your currently used Pay Buttons to stop working.
Customers trying to use Pay Button to create Invoices will be displayed appropriate message.
You can always reenable Pay Buttons at later time.
</p>
@Html.Hidden("EnableStore", false)
<button name="command" type="submit" value="save" class="btn btn-primary">Disable Pay Button</button>
</div>
</form>
</div>
</div>
@section HeadScripts {
<link rel="stylesheet" href="~/vendor/highlightjs/default.min.css">

View file

@ -1,6 +1,6 @@
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePageAndTitle(StoreNavPages.PayButton, "Please confirm you want to enable Pay Button");
ViewData.SetActivePageAndTitle(StoreNavPages.PayButton, "Please confirm you want to allow anyone to create invoices in your store");
ViewBag.MainTitle = "Pay Button";
}
@ -12,10 +12,10 @@
<div class="form-group">
<p>
To start using Pay Buttons you need to explicitly turn on this feature.
Once you do so, valid POST requests from any source will allow creation of Invoices on your instance of BtcPayServer.
Once you do so, any source will be able to create an invoice on your instance store.
</p>
@Html.Hidden("EnableStore", true)
<button name="command" type="submit" value="save" class="btn btn-primary">Enable Pay Button</button>
<button name="command" type="submit" value="save" class="btn btn-primary">Allow anyone to create invoices</button>
</div>
</form>
</div>

View file

@ -46,6 +46,10 @@
<label asp-for="NetworkFee"></label>
<input asp-for="NetworkFee" type="checkbox" class="form-check" />
</div>
<div class="form-group">
<label asp-for="AnyoneCanCreateInvoice"></label>
<input asp-for="AnyoneCanCreateInvoice" type="checkbox" class="form-check" />
</div>
<div class="form-group">
<label asp-for="InvoiceExpiration"></label>
<input asp-for="InvoiceExpiration" class="form-control" />