mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Move to a Claim based security
This commit is contained in:
@@ -4,6 +4,7 @@ using BTCPayServer.Payments;
|
|||||||
using BTCPayServer.Payments.Lightning;
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
using BTCPayServer.Tests.Logging;
|
using BTCPayServer.Tests.Logging;
|
||||||
using BTCPayServer.Tests.Mocks;
|
using BTCPayServer.Tests.Mocks;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
@@ -142,7 +143,7 @@ namespace BTCPayServer.Tests
|
|||||||
return _Host.Services.GetRequiredService<T>();
|
return _Host.Services.GetRequiredService<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetController<T>(string userId = null) where T : Controller
|
public T GetController<T>(string userId = null, string storeId = null) where T : Controller
|
||||||
{
|
{
|
||||||
var context = new DefaultHttpContext();
|
var context = new DefaultHttpContext();
|
||||||
context.Request.Host = new HostString("127.0.0.1");
|
context.Request.Host = new HostString("127.0.0.1");
|
||||||
@@ -152,6 +153,10 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) }));
|
context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId) }));
|
||||||
}
|
}
|
||||||
|
if(storeId != null)
|
||||||
|
{
|
||||||
|
context.SetStoreData(GetService<StoreRepository>().FindStore(storeId, userId).GetAwaiter().GetResult());
|
||||||
|
}
|
||||||
var scope = (IServiceScopeFactory)_Host.Services.GetService(typeof(IServiceScopeFactory));
|
var scope = (IServiceScopeFactory)_Host.Services.GetService(typeof(IServiceScopeFactory));
|
||||||
var provider = scope.CreateScope().ServiceProvider;
|
var provider = scope.CreateScope().ServiceProvider;
|
||||||
context.RequestServices = provider;
|
context.RequestServices = provider;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
public T GetController<T>() where T : Controller
|
public T GetController<T>() where T : Controller
|
||||||
{
|
{
|
||||||
return parent.PayTester.GetController<T>(UserId);
|
return parent.PayTester.GetController<T>(UserId, StoreId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<StoresController> CreateStoreAsync()
|
public async Task<StoresController> CreateStoreAsync()
|
||||||
@@ -78,10 +78,10 @@ namespace BTCPayServer.Tests
|
|||||||
public async Task RegisterDerivationSchemeAsync(string cryptoCode)
|
public async Task RegisterDerivationSchemeAsync(string cryptoCode)
|
||||||
{
|
{
|
||||||
SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode);
|
SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode);
|
||||||
var store = parent.PayTester.GetController<StoresController>(UserId);
|
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId);
|
||||||
ExtKey = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
|
ExtKey = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
|
||||||
DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
|
DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
|
||||||
var vm = (StoreViewModel)((ViewResult)await store.UpdateStore(StoreId)).Model;
|
var vm = (StoreViewModel)((ViewResult)store.UpdateStore(StoreId)).Model;
|
||||||
vm.SpeedPolicy = SpeedPolicy.MediumSpeed;
|
vm.SpeedPolicy = SpeedPolicy.MediumSpeed;
|
||||||
await store.UpdateStore(StoreId, vm);
|
await store.UpdateStore(StoreId, vm);
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
public async Task RegisterLightningNodeAsync(string cryptoCode, LightningConnectionType connectionType)
|
public async Task RegisterLightningNodeAsync(string cryptoCode, LightningConnectionType connectionType)
|
||||||
{
|
{
|
||||||
var storeController = parent.PayTester.GetController<StoresController>(UserId);
|
var storeController = this.GetController<StoresController>();
|
||||||
await storeController.AddLightningNode(StoreId, new LightningNodeViewModel()
|
await storeController.AddLightningNode(StoreId, new LightningNodeViewModel()
|
||||||
{
|
{
|
||||||
Url = connectionType == LightningConnectionType.Charge ? parent.MerchantCharge.Client.Uri.AbsoluteUri :
|
Url = connectionType == LightningConnectionType.Charge ? parent.MerchantCharge.Client.Uri.AbsoluteUri :
|
||||||
|
|||||||
@@ -306,9 +306,9 @@ namespace BTCPayServer.Tests
|
|||||||
tester.Start();
|
tester.Start();
|
||||||
var user = tester.NewAccount();
|
var user = tester.NewAccount();
|
||||||
user.GrantAccess();
|
user.GrantAccess();
|
||||||
var storeController = tester.PayTester.GetController<StoresController>(user.UserId);
|
var storeController = user.GetController<StoresController>();
|
||||||
Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId).GetAwaiter().GetResult());
|
Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId));
|
||||||
Assert.IsType<ViewResult>(storeController.AddLightningNode(user.StoreId, "BTC").GetAwaiter().GetResult());
|
Assert.IsType<ViewResult>(storeController.AddLightningNode(user.StoreId, "BTC"));
|
||||||
|
|
||||||
var testResult = storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel()
|
var testResult = storeController.AddLightningNode(user.StoreId, new LightningNodeViewModel()
|
||||||
{
|
{
|
||||||
@@ -322,7 +322,7 @@ namespace BTCPayServer.Tests
|
|||||||
Url = tester.MerchantCharge.Client.Uri.AbsoluteUri
|
Url = tester.MerchantCharge.Client.Uri.AbsoluteUri
|
||||||
}, "save", "BTC").GetAwaiter().GetResult());
|
}, "save", "BTC").GetAwaiter().GetResult());
|
||||||
|
|
||||||
var storeVm = Assert.IsType<Models.StoreViewModels.StoreViewModel>(Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId).GetAwaiter().GetResult()).Model);
|
var storeVm = Assert.IsType<Models.StoreViewModels.StoreViewModel>(Assert.IsType<ViewResult>(storeController.UpdateStore(user.StoreId)).Model);
|
||||||
Assert.Single(storeVm.LightningNodes.Where(l => !string.IsNullOrEmpty(l.Address)));
|
Assert.Single(storeVm.LightningNodes.Where(l => !string.IsNullOrEmpty(l.Address)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,7 +468,7 @@ namespace BTCPayServer.Tests
|
|||||||
acc.Register();
|
acc.Register();
|
||||||
acc.CreateStore();
|
acc.CreateStore();
|
||||||
|
|
||||||
var controller = tester.PayTester.GetController<StoresController>(acc.UserId);
|
var controller = acc.GetController<StoresController>();
|
||||||
var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel()
|
var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel()
|
||||||
{
|
{
|
||||||
Facade = Facade.Merchant.ToString(),
|
Facade = Facade.Merchant.ToString(),
|
||||||
@@ -685,8 +685,8 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
private static decimal CreateInvoice(ServerTester tester, TestAccount user, string exchange)
|
private static decimal CreateInvoice(ServerTester tester, TestAccount user, string exchange)
|
||||||
{
|
{
|
||||||
var storeController = tester.PayTester.GetController<StoresController>(user.UserId);
|
var storeController = user.GetController<StoresController>();
|
||||||
var vm = (StoreViewModel)((ViewResult)storeController.UpdateStore(user.StoreId).Result).Model;
|
var vm = (StoreViewModel)((ViewResult)storeController.UpdateStore(user.StoreId)).Model;
|
||||||
vm.PreferredExchange = exchange;
|
vm.PreferredExchange = exchange;
|
||||||
storeController.UpdateStore(user.StoreId, vm).Wait();
|
storeController.UpdateStore(user.StoreId, vm).Wait();
|
||||||
var invoice2 = user.BitPay.CreateInvoice(new Invoice()
|
var invoice2 = user.BitPay.CreateInvoice(new Invoice()
|
||||||
@@ -724,8 +724,8 @@ namespace BTCPayServer.Tests
|
|||||||
}, Facade.Merchant);
|
}, Facade.Merchant);
|
||||||
|
|
||||||
|
|
||||||
var storeController = tester.PayTester.GetController<StoresController>(user.UserId);
|
var storeController = user.GetController<StoresController>();
|
||||||
var vm = (StoreViewModel)((ViewResult)storeController.UpdateStore(user.StoreId).Result).Model;
|
var vm = (StoreViewModel)((ViewResult)storeController.UpdateStore(user.StoreId)).Model;
|
||||||
Assert.Equal(1.0, vm.RateMultiplier);
|
Assert.Equal(1.0, vm.RateMultiplier);
|
||||||
vm.RateMultiplier = 0.5;
|
vm.RateMultiplier = 0.5;
|
||||||
storeController.UpdateStore(user.StoreId, vm).Wait();
|
storeController.UpdateStore(user.StoreId, vm).Wait();
|
||||||
@@ -963,7 +963,7 @@ namespace BTCPayServer.Tests
|
|||||||
user.GrantAccess();
|
user.GrantAccess();
|
||||||
user.RegisterDerivationScheme("BTC");
|
user.RegisterDerivationScheme("BTC");
|
||||||
user.RegisterLightningNode("BTC", LightningConnectionType.Charge);
|
user.RegisterLightningNode("BTC", LightningConnectionType.Charge);
|
||||||
var vm = Assert.IsType<CheckoutExperienceViewModel>(Assert.IsType<ViewResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId).Result).Model);
|
var vm = Assert.IsType<CheckoutExperienceViewModel>(Assert.IsType<ViewResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId)).Model);
|
||||||
vm.LightningMaxValue = "2 USD";
|
vm.LightningMaxValue = "2 USD";
|
||||||
vm.OnChainMinValue = "5 USD";
|
vm.OnChainMinValue = "5 USD";
|
||||||
Assert.IsType<RedirectToActionResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId, vm).Result);
|
Assert.IsType<RedirectToActionResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId, vm).Result);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ using BTCPayServer.Logging;
|
|||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[Authorize]
|
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
||||||
[Route("[controller]/[action]")]
|
[Route("[controller]/[action]")]
|
||||||
public class AccountController : Controller
|
public class AccountController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -140,6 +140,8 @@ namespace BTCPayServer.Controllers
|
|||||||
.Where(us => us.ApplicationUserId == userId && us.Role == StoreRoles.Owner)
|
.Where(us => us.ApplicationUserId == userId && us.Role == StoreRoles.Owner)
|
||||||
.SelectMany(us => us.StoreData.Apps.Where(a => a.Id == appId))
|
.SelectMany(us => us.StoreData.Apps.Where(a => a.Id == appId))
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
if (app == null)
|
||||||
|
return null;
|
||||||
if (type != null && type.Value.ToString() != app.AppType)
|
if (type != null && type.Value.ToString() != app.AppType)
|
||||||
return null;
|
return null;
|
||||||
return app;
|
return app;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using BTCPayServer.Events;
|
|||||||
using NBXplorer;
|
using NBXplorer;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Lightning;
|
using BTCPayServer.Payments.Lightning;
|
||||||
|
using BTCPayServer.Security;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
@@ -394,7 +395,7 @@ namespace BTCPayServer.Controllers
|
|||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
public async Task<IActionResult> CreateInvoice()
|
public async Task<IActionResult> CreateInvoice()
|
||||||
{
|
{
|
||||||
var stores = await GetStores(GetUserId());
|
var stores = new SelectList(await _StoreRepository.GetStoresByUserId(GetUserId()), nameof(StoreData.Id), nameof(StoreData.StoreName), null);
|
||||||
if (stores.Count() == 0)
|
if (stores.Count() == 0)
|
||||||
{
|
{
|
||||||
StatusMessage = "Error: You need to create at least one store before creating a transaction";
|
StatusMessage = "Error: You need to create at least one store before creating a transaction";
|
||||||
@@ -409,14 +410,19 @@ namespace BTCPayServer.Controllers
|
|||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
public async Task<IActionResult> CreateInvoice(CreateInvoiceModel model)
|
public async Task<IActionResult> CreateInvoice(CreateInvoiceModel model)
|
||||||
{
|
{
|
||||||
model.Stores = await GetStores(GetUserId(), model.StoreId);
|
var stores = await _StoreRepository.GetStoresByUserId(GetUserId());
|
||||||
|
model.Stores = new SelectList(stores, nameof(StoreData.Id), nameof(StoreData.StoreName), model.StoreId);
|
||||||
|
var store = stores.FirstOrDefault(s => s.Id == model.StoreId);
|
||||||
|
if(store == null)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(model.StoreId), "Store not found");
|
||||||
|
}
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
var store = await _StoreRepository.FindStore(model.StoreId, GetUserId());
|
|
||||||
StatusMessage = null;
|
StatusMessage = null;
|
||||||
if (store.Role != StoreRoles.Owner)
|
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.StoreId), "You need to be owner of this store to create an invoice");
|
ModelState.AddModelError(nameof(model.StoreId), "You need to be owner of this store to create an invoice");
|
||||||
return View(model);
|
return View(model);
|
||||||
@@ -461,11 +467,6 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SelectList> GetStores(string userId, string storeId = null)
|
|
||||||
{
|
|
||||||
return new SelectList(await _StoreRepository.GetStoresByUserId(userId), nameof(StoreData.Id), nameof(StoreData.StoreName), storeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
||||||
[BitpayAPIConstraint(false)]
|
[BitpayAPIConstraint(false)]
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[Authorize]
|
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
||||||
[Route("[controller]/[action]")]
|
[Route("[controller]/[action]")]
|
||||||
public class ManageController : Controller
|
public class ManageController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
[Authorize(Roles = Roles.ServerAdmin)]
|
[Authorize(Policy = BTCPayServer.Security.Policies.CanModifyServerSettings.Key)]
|
||||||
public class ServerController : Controller
|
public class ServerController : Controller
|
||||||
{
|
{
|
||||||
private UserManager<ApplicationUser> _UserManager;
|
private UserManager<ApplicationUser> _UserManager;
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/derivations/{cryptoCode}")]
|
[Route("{storeId}/derivations/{cryptoCode}")]
|
||||||
public async Task<IActionResult> AddDerivationScheme(string storeId, string cryptoCode)
|
public IActionResult AddDerivationScheme(string storeId, string cryptoCode)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode);
|
var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode);
|
||||||
@@ -60,7 +60,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
vm.ServerUrl = GetStoreUrl(storeId);
|
vm.ServerUrl = GetStoreUrl(storeId);
|
||||||
vm.CryptoCode = cryptoCode;
|
vm.CryptoCode = cryptoCode;
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
if (!HttpContext.WebSockets.IsWebSocketRequest)
|
if (!HttpContext.WebSockets.IsWebSocketRequest)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/lightning/{cryptoCode}")]
|
[Route("{storeId}/lightning/{cryptoCode}")]
|
||||||
public async Task<IActionResult> AddLightningNode(string storeId, string cryptoCode)
|
public IActionResult AddLightningNode(string storeId, string cryptoCode)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
LightningNodeViewModel vm = new LightningNodeViewModel();
|
LightningNodeViewModel vm = new LightningNodeViewModel();
|
||||||
@@ -59,7 +59,7 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
|
public async Task<IActionResult> AddLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
|
||||||
{
|
{
|
||||||
vm.CryptoCode = cryptoCode;
|
vm.CryptoCode = cryptoCode;
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);
|
var network = vm.CryptoCode == null ? null : _ExplorerProvider.GetNetwork(vm.CryptoCode);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using BTCPayServer.Data;
|
|||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.StoreViewModels;
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
@@ -28,7 +29,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
[Route("stores")]
|
[Route("stores")]
|
||||||
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
[Authorize(AuthenticationSchemes = "Identity.Application")]
|
||||||
[Authorize(Policy = StorePolicies.OwnStore)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings.Key)]
|
||||||
[AutoValidateAntiforgeryToken]
|
[AutoValidateAntiforgeryToken]
|
||||||
public partial class StoresController : Controller
|
public partial class StoresController : Controller
|
||||||
{
|
{
|
||||||
@@ -93,9 +94,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/wallet/{cryptoCode}")]
|
[Route("{storeId}/wallet/{cryptoCode}")]
|
||||||
public async Task<IActionResult> Wallet(string storeId, string cryptoCode)
|
public IActionResult Wallet(string storeId, string cryptoCode)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
WalletModel model = new WalletModel();
|
WalletModel model = new WalletModel();
|
||||||
@@ -164,7 +165,7 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> DeleteStoreUser(string storeId, string userId)
|
public async Task<IActionResult> DeleteStoreUser(string storeId, string userId)
|
||||||
{
|
{
|
||||||
StoreUsersViewModel vm = new StoreUsersViewModel();
|
StoreUsersViewModel vm = new StoreUsersViewModel();
|
||||||
var store = await _Repo.FindStore(storeId, userId);
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var user = await _UserManager.FindByIdAsync(userId);
|
var user = await _UserManager.FindByIdAsync(userId);
|
||||||
@@ -173,7 +174,7 @@ namespace BTCPayServer.Controllers
|
|||||||
return View("Confirm", new ConfirmModel()
|
return View("Confirm", new ConfirmModel()
|
||||||
{
|
{
|
||||||
Title = $"Remove store user",
|
Title = $"Remove store user",
|
||||||
Description = $"Are you sure to remove access to remove {store.Role} access to {user.Email}?",
|
Description = $"Are you sure to remove access to remove access to {user.Email}?",
|
||||||
Action = "Delete"
|
Action = "Delete"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -189,9 +190,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/checkout")]
|
[Route("{storeId}/checkout")]
|
||||||
public async Task<IActionResult> CheckoutExperience(string storeId)
|
public IActionResult CheckoutExperience(string storeId)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
@@ -229,7 +230,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
bool needUpdate = false;
|
bool needUpdate = false;
|
||||||
@@ -271,9 +272,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}")]
|
[Route("{storeId}")]
|
||||||
public async Task<IActionResult> UpdateStore(string storeId)
|
public IActionResult UpdateStore(string storeId)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
@@ -338,7 +339,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
if (model.PreferredExchange != null)
|
if (model.PreferredExchange != null)
|
||||||
model.PreferredExchange = model.PreferredExchange.Trim().ToLowerInvariant();
|
model.PreferredExchange = model.PreferredExchange.Trim().ToLowerInvariant();
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
AddPaymentMethods(store, model);
|
AddPaymentMethods(store, model);
|
||||||
@@ -450,10 +451,10 @@ namespace BTCPayServer.Controllers
|
|||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
if (userId == null)
|
if (userId == null)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
var store = await _Repo.FindStore(storeId, userId);
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
if (store.Role != StoreRoles.Owner)
|
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
|
||||||
{
|
{
|
||||||
StatusMessage = "Error: You need to be owner of this store to request pairing codes";
|
StatusMessage = "Error: You need to be owner of this store to request pairing codes";
|
||||||
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
|
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
|
||||||
@@ -535,7 +536,7 @@ namespace BTCPayServer.Controllers
|
|||||||
[Route("{storeId}/tokens/apikey")]
|
[Route("{storeId}/tokens/apikey")]
|
||||||
public async Task<IActionResult> GenerateAPIKey(string storeId)
|
public async Task<IActionResult> GenerateAPIKey(string storeId)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
await _TokenRepository.GenerateLegacyAPIKey(storeId);
|
await _TokenRepository.GenerateLegacyAPIKey(storeId);
|
||||||
@@ -585,7 +586,7 @@ namespace BTCPayServer.Controllers
|
|||||||
if (store == null || pairing == null)
|
if (store == null || pairing == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
if (store.Role != StoreRoles.Owner)
|
if (!store.HasClaim(Policies.CanModifyStoreSettings.Key))
|
||||||
{
|
{
|
||||||
StatusMessage = "Error: You can't approve a pairing without being owner of the store";
|
StatusMessage = "Error: You can't approve a pairing without being owner of the store";
|
||||||
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
|
return RedirectToAction(nameof(UserStoresController.ListStores), "UserStores");
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.StoreViewModels;
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
using BTCPayServer.Services.Wallets;
|
using BTCPayServer.Services.Wallets;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -37,9 +38,9 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/delete")]
|
[Route("{storeId}/delete")]
|
||||||
public async Task<IActionResult> DeleteStore(string storeId)
|
public IActionResult DeleteStore(string storeId)
|
||||||
{
|
{
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return View("Confirm", new ConfirmModel()
|
return View("Confirm", new ConfirmModel()
|
||||||
@@ -67,7 +68,7 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> DeleteStorePost(string storeId)
|
public async Task<IActionResult> DeleteStorePost(string storeId)
|
||||||
{
|
{
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
await _Repo.RemoveStore(storeId, userId);
|
await _Repo.RemoveStore(storeId, userId);
|
||||||
@@ -102,8 +103,8 @@ namespace BTCPayServer.Controllers
|
|||||||
Id = store.Id,
|
Id = store.Id,
|
||||||
Name = store.StoreName,
|
Name = store.StoreName,
|
||||||
WebSite = store.StoreWebsite,
|
WebSite = store.StoreWebsite,
|
||||||
IsOwner = store.Role == StoreRoles.Owner,
|
IsOwner = store.HasClaim(Policies.CanModifyStoreSettings.Key),
|
||||||
Balances = store.Role == StoreRoles.Owner ? balances[i].Select(t => t.Result).ToArray() : Array.Empty<string>()
|
Balances = store.HasClaim(Policies.CanModifyStoreSettings.Key) ? balances[i].Select(t => t.Result).ToArray() : Array.Empty<string>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return View(result);
|
return View(result);
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ using BTCPayServer.Services.Rates;
|
|||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.JsonConverters;
|
using BTCPayServer.JsonConverters;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using BTCPayServer.Services;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using BTCPayServer.Security;
|
||||||
|
|
||||||
namespace BTCPayServer.Data
|
namespace BTCPayServer.Data
|
||||||
{
|
{
|
||||||
@@ -152,10 +155,35 @@ namespace BTCPayServer.Data
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
|
[Obsolete]
|
||||||
public string Role
|
public string Role
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Claim[] GetClaims()
|
||||||
|
{
|
||||||
|
List<Claim> claims = new List<Claim>();
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
claims.Add(new Claim(Policies.CanUseStore.Key, Id));
|
||||||
|
}
|
||||||
|
return claims.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasClaim(string claim)
|
||||||
|
{
|
||||||
|
return GetClaims().Any(c => c.Type == claim);
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] StoreBlob
|
public byte[] StoreBlob
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
|
|||||||
@@ -38,55 +38,13 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using BTCPayServer.Logging;
|
using BTCPayServer.Logging;
|
||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
using Meziantou.AspNetCore.BundleTagHelpers;
|
using Meziantou.AspNetCore.BundleTagHelpers;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using BTCPayServer.Security;
|
||||||
|
|
||||||
namespace BTCPayServer.Hosting
|
namespace BTCPayServer.Hosting
|
||||||
{
|
{
|
||||||
public static class BTCPayServerServices
|
public static class BTCPayServerServices
|
||||||
{
|
{
|
||||||
public class OwnStoreAuthorizationRequirement : IAuthorizationRequirement
|
|
||||||
{
|
|
||||||
public OwnStoreAuthorizationRequirement()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnStoreAuthorizationRequirement(string role)
|
|
||||||
{
|
|
||||||
Role = role;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Role
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OwnStoreHandler : AuthorizationHandler<OwnStoreAuthorizationRequirement>
|
|
||||||
{
|
|
||||||
StoreRepository _StoreRepository;
|
|
||||||
UserManager<ApplicationUser> _UserManager;
|
|
||||||
public OwnStoreHandler(StoreRepository storeRepository, UserManager<ApplicationUser> userManager)
|
|
||||||
{
|
|
||||||
_StoreRepository = storeRepository;
|
|
||||||
_UserManager = userManager;
|
|
||||||
}
|
|
||||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OwnStoreAuthorizationRequirement requirement)
|
|
||||||
{
|
|
||||||
object storeId = null;
|
|
||||||
if (!((Microsoft.AspNetCore.Mvc.ActionContext)context.Resource).RouteData.Values.TryGetValue("storeId", out storeId))
|
|
||||||
context.Succeed(requirement);
|
|
||||||
else if (storeId != null)
|
|
||||||
{
|
|
||||||
var user = _UserManager.GetUserId(((Microsoft.AspNetCore.Mvc.ActionContext)context.Resource).HttpContext.User);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
var store = await _StoreRepository.FindStore((string)storeId, user);
|
|
||||||
if (store != null)
|
|
||||||
if (requirement.Role == null || requirement.Role == store.Role)
|
|
||||||
context.Succeed(requirement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static IServiceCollection AddBTCPayServer(this IServiceCollection services)
|
public static IServiceCollection AddBTCPayServer(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddDbContext<ApplicationDbContext>((provider, o) =>
|
services.AddDbContext<ApplicationDbContext>((provider, o) =>
|
||||||
@@ -160,6 +118,7 @@ namespace BTCPayServer.Hosting
|
|||||||
services.AddSingleton<IHostedService, InvoiceNotificationManager>();
|
services.AddSingleton<IHostedService, InvoiceNotificationManager>();
|
||||||
services.AddSingleton<IHostedService, InvoiceWatcher>();
|
services.AddSingleton<IHostedService, InvoiceWatcher>();
|
||||||
services.AddSingleton<IHostedService, RatesHostedService>();
|
services.AddSingleton<IHostedService, RatesHostedService>();
|
||||||
|
services.AddTransient<IConfigureOptions<MvcOptions>, BTCPayClaimsFilter>();
|
||||||
|
|
||||||
services.TryAddSingleton<ExplorerClientProvider>();
|
services.TryAddSingleton<ExplorerClientProvider>();
|
||||||
services.TryAddSingleton<Bitpay>(o =>
|
services.TryAddSingleton<Bitpay>(o =>
|
||||||
@@ -172,27 +131,14 @@ namespace BTCPayServer.Hosting
|
|||||||
services.TryAddSingleton<IRateProviderFactory, BTCPayRateProviderFactory>();
|
services.TryAddSingleton<IRateProviderFactory, BTCPayRateProviderFactory>();
|
||||||
|
|
||||||
services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
|
services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.TryAddSingleton<IAuthorizationHandler, OwnStoreHandler>();
|
|
||||||
services.AddTransient<AccessTokenController>();
|
services.AddTransient<AccessTokenController>();
|
||||||
services.AddTransient<InvoiceController>();
|
services.AddTransient<InvoiceController>();
|
||||||
// Add application services.
|
// Add application services.
|
||||||
services.AddTransient<IEmailSender, EmailSender>();
|
services.AddTransient<IEmailSender, EmailSender>();
|
||||||
|
|
||||||
services.AddAuthorization(o =>
|
|
||||||
{
|
|
||||||
o.AddPolicy(StorePolicies.CanAccessStores, builder =>
|
|
||||||
{
|
|
||||||
builder.AddRequirements(new OwnStoreAuthorizationRequirement());
|
|
||||||
});
|
|
||||||
|
|
||||||
o.AddPolicy(StorePolicies.OwnStore, builder =>
|
|
||||||
{
|
|
||||||
builder.AddRequirements(new OwnStoreAuthorizationRequirement(StoreRoles.Owner));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// bundling
|
// bundling
|
||||||
|
|
||||||
|
services.AddAuthorization(o => Policies.AddBTCPayPolicies(o));
|
||||||
|
|
||||||
services.AddBundles();
|
services.AddBundles();
|
||||||
services.AddTransient<BundleOptions>(provider =>
|
services.AddTransient<BundleOptions>(provider =>
|
||||||
{
|
{
|
||||||
|
|||||||
97
BTCPayServer/Security/BTCPayClaimsPrincipalFactory.cs
Normal file
97
BTCPayServer/Security/BTCPayClaimsPrincipalFactory.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Models;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Security
|
||||||
|
{
|
||||||
|
|
||||||
|
public class BTCPayClaimsFilter : IAsyncAuthorizationFilter, IConfigureOptions<MvcOptions>
|
||||||
|
{
|
||||||
|
UserManager<ApplicationUser> _UserManager;
|
||||||
|
StoreRepository _StoreRepository;
|
||||||
|
public BTCPayClaimsFilter(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
StoreRepository storeRepository)
|
||||||
|
{
|
||||||
|
_UserManager = userManager;
|
||||||
|
_StoreRepository = storeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IConfigureOptions<MvcOptions>.Configure(MvcOptions options)
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(BTCPayClaimsFilter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||||
|
{
|
||||||
|
var principal = context.HttpContext.User;
|
||||||
|
if (!context.HttpContext.GetIsBitpayAPI())
|
||||||
|
{
|
||||||
|
var identity = ((ClaimsIdentity)principal.Identity);
|
||||||
|
if (principal.IsInRole(Roles.ServerAdmin))
|
||||||
|
{
|
||||||
|
identity.AddClaim(new Claim(Policies.CanModifyServerSettings.Key, "true"));
|
||||||
|
}
|
||||||
|
if (context.RouteData.Values.TryGetValue("storeId", out var storeId))
|
||||||
|
{
|
||||||
|
var claim = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
|
||||||
|
if (claim != null)
|
||||||
|
{
|
||||||
|
var store = await _StoreRepository.FindStore((string)storeId, claim.Value);
|
||||||
|
context.HttpContext.SetStoreData(store);
|
||||||
|
if (store != null)
|
||||||
|
{
|
||||||
|
identity.AddClaims(store.GetClaims());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class BTCPayClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
|
||||||
|
{
|
||||||
|
IHttpContextAccessor httpContext;
|
||||||
|
StoreRepository _StoreRepository;
|
||||||
|
public BTCPayClaimsPrincipalFactory(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
IHttpContextAccessor httpContext,
|
||||||
|
StoreRepository storeRepository,
|
||||||
|
IOptions<IdentityOptions> options) : base(userManager, options)
|
||||||
|
{
|
||||||
|
this.httpContext = httpContext;
|
||||||
|
_StoreRepository = storeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
|
||||||
|
{
|
||||||
|
var ctx = (IActionContextAccessor)httpContext.HttpContext.RequestServices.GetService(typeof(IActionContextAccessor));
|
||||||
|
var principal = await base.CreateAsync(user);
|
||||||
|
if (ctx.ActionContext.HttpContext.GetIsBitpayAPI())
|
||||||
|
return principal;
|
||||||
|
var identity = ((ClaimsIdentity)principal.Identity);
|
||||||
|
if (principal.IsInRole(Roles.ServerAdmin))
|
||||||
|
{
|
||||||
|
identity.AddClaim(new Claim(Policies.CanModifyServerSettings.Key, "true"));
|
||||||
|
}
|
||||||
|
if (ctx.ActionContext.RouteData.Values.TryGetValue("storeId", out var storeId))
|
||||||
|
{
|
||||||
|
var store = await _StoreRepository.FindStore((string)storeId, await UserManager.GetUserIdAsync(user));
|
||||||
|
if (store != null)
|
||||||
|
{
|
||||||
|
identity.AddClaims(store.GetClaims());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
BTCPayServer/Security/Policies.cs
Normal file
37
BTCPayServer/Security/Policies.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Security
|
||||||
|
{
|
||||||
|
public static class Policies
|
||||||
|
{
|
||||||
|
public static AuthorizationOptions AddBTCPayPolicies(this AuthorizationOptions options)
|
||||||
|
{
|
||||||
|
AddClaim(options, CanUseStore.Key);
|
||||||
|
AddClaim(options, CanModifyStoreSettings.Key);
|
||||||
|
AddClaim(options, CanModifyServerSettings.Key);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddClaim(AuthorizationOptions options, string key)
|
||||||
|
{
|
||||||
|
options.AddPolicy(key, o => o.RequireClaim(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CanModifyServerSettings
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,9 @@ namespace BTCPayServer.Services.Stores
|
|||||||
}).ToArrayAsync())
|
}).ToArrayAsync())
|
||||||
.Select(us =>
|
.Select(us =>
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CS0612 // Type or member is obsolete
|
||||||
us.Store.Role = us.Role;
|
us.Store.Role = us.Role;
|
||||||
|
#pragma warning restore CS0612 // Type or member is obsolete
|
||||||
return us.Store;
|
return us.Store;
|
||||||
}).FirstOrDefault();
|
}).FirstOrDefault();
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,9 @@ namespace BTCPayServer.Services.Stores
|
|||||||
.ToArrayAsync())
|
.ToArrayAsync())
|
||||||
.Select(u =>
|
.Select(u =>
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CS0612 // Type or member is obsolete
|
||||||
u.StoreData.Role = u.Role;
|
u.StoreData.Role = u.Role;
|
||||||
|
#pragma warning restore CS0612 // Type or member is obsolete
|
||||||
return u.StoreData;
|
return u.StoreData;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace BTCPayServer
|
namespace BTCPayServer
|
||||||
{
|
{
|
||||||
public class StorePolicies
|
|
||||||
{
|
|
||||||
public const string CanAccessStores = "CanAccessStore";
|
|
||||||
public const string OwnStore = "OwnStore";
|
|
||||||
}
|
|
||||||
public class StoreRoles
|
public class StoreRoles
|
||||||
{
|
{
|
||||||
public const string Owner = "Owner";
|
public const string Owner = "Owner";
|
||||||
|
|||||||
Reference in New Issue
Block a user