mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-19 15:04:19 +01:00
Authorize granular permissions (#1057)
* granular scope permissions for api * final fixes and styling * prettify code * fix missing policy
This commit is contained in:
committed by
Nicolas Dorier
parent
c7e3241a85
commit
3366c86b16
@@ -11,6 +11,7 @@ using Xunit;
|
|||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using BTCPayServer.Authentication;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
@@ -108,7 +109,8 @@ namespace BTCPayServer.Tests
|
|||||||
ClientId = id,
|
ClientId = id,
|
||||||
DisplayName = id,
|
DisplayName = id,
|
||||||
Permissions = {OpenIddictConstants.Permissions.GrantTypes.Implicit},
|
Permissions = {OpenIddictConstants.Permissions.GrantTypes.Implicit},
|
||||||
RedirectUris = {redirecturi}
|
RedirectUris = {redirecturi},
|
||||||
|
|
||||||
});
|
});
|
||||||
var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
|
var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
|
||||||
$"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}");
|
$"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}");
|
||||||
@@ -127,7 +129,7 @@ namespace BTCPayServer.Tests
|
|||||||
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
||||||
|
|
||||||
LogoutFlow(tester, id, s);
|
LogoutFlow(tester, id, s);
|
||||||
|
//we dont ask for consent after acquiring it the first time for the same scopes.
|
||||||
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
|
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
|
||||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||||
|
|
||||||
@@ -135,6 +137,42 @@ namespace BTCPayServer.Tests
|
|||||||
results = url.Split("#").Last().Split("&")
|
results = url.Split("#").Last().Split("&")
|
||||||
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||||
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
||||||
|
|
||||||
|
//let's test out scopes!
|
||||||
|
implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
|
||||||
|
$"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid {RestAPIPolicies.BTCPayScopes.AppManagement} {RestAPIPolicies.BTCPayScopes.ViewStores} &nonce={Guid.NewGuid().ToString()}");
|
||||||
|
|
||||||
|
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
|
||||||
|
//authorize form should show now that we have asked for more scopes
|
||||||
|
s.Driver.FindElement(By.Id("consent-yes")).Click();
|
||||||
|
url = s.Driver.Url;
|
||||||
|
results = url.Split("#").Last().Split("&")
|
||||||
|
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.True(await TestApiAgainstAccessToken<bool>(results["access_token"],
|
||||||
|
$"api/test/ScopeCanViewApps",
|
||||||
|
tester.PayTester.HttpClient));
|
||||||
|
|
||||||
|
Assert.True(await TestApiAgainstAccessToken<bool>(results["access_token"],
|
||||||
|
$"api/test/ScopeCanManageApps",
|
||||||
|
tester.PayTester.HttpClient));
|
||||||
|
|
||||||
|
Assert.True(await TestApiAgainstAccessToken<bool>(results["access_token"],
|
||||||
|
$"api/test/ScopeCanViewStores",
|
||||||
|
tester.PayTester.HttpClient));
|
||||||
|
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
|
||||||
|
{
|
||||||
|
await TestApiAgainstAccessToken<bool>(results["access_token"],
|
||||||
|
$"api/test/ScopeCanManageStores",
|
||||||
|
tester.PayTester.HttpClient);
|
||||||
|
});
|
||||||
|
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
|
||||||
|
{
|
||||||
|
await TestApiAgainstAccessToken<bool>(results["access_token"],
|
||||||
|
$"api/test/ScopeCanViewProfile",
|
||||||
|
tester.PayTester.HttpClient);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +391,6 @@ namespace BTCPayServer.Tests
|
|||||||
$"api/test/me/stores/{testAccount.StoreId}/can-edit",
|
$"api/test/me/stores/{testAccount.StoreId}/can-edit",
|
||||||
tester.PayTester.HttpClient));
|
tester.PayTester.HttpClient));
|
||||||
|
|
||||||
|
|
||||||
Assert.Equal(testAccount.RegisterDetails.IsAdmin, await TestApiAgainstAccessToken<bool>(accessToken,
|
Assert.Equal(testAccount.RegisterDetails.IsAdmin, await TestApiAgainstAccessToken<bool>(accessToken,
|
||||||
$"api/test/me/is-admin",
|
$"api/test/me/is-admin",
|
||||||
tester.PayTester.HttpClient));
|
tester.PayTester.HttpClient));
|
||||||
|
|||||||
105
BTCPayServer/Authentication/BTCPayScopes.cs
Normal file
105
BTCPayServer/Authentication/BTCPayScopes.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using OpenIddict.Abstractions;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Authentication
|
||||||
|
{
|
||||||
|
public static class RestAPIPolicies
|
||||||
|
{
|
||||||
|
public static class BTCPayScopes
|
||||||
|
{
|
||||||
|
public const string ViewStores = "view_stores";
|
||||||
|
|
||||||
|
//Create and manage stores
|
||||||
|
public const string StoreManagement = "store_management";
|
||||||
|
|
||||||
|
//create and manage invoices
|
||||||
|
public const string ViewInvoices = "view_invoices";
|
||||||
|
|
||||||
|
//create and manage invoices
|
||||||
|
public const string CreateInvoices = "create_invoice";
|
||||||
|
|
||||||
|
public const string InvoiceManagement = "manage_invoices";
|
||||||
|
|
||||||
|
//view apps
|
||||||
|
public const string ViewApps = "view_apps";
|
||||||
|
|
||||||
|
//create and manage apps
|
||||||
|
public const string AppManagement = "app_management";
|
||||||
|
public const string WalletManagement = "wallet_management";
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string CanViewStores = nameof(CanViewStores);
|
||||||
|
public const string CanManageStores = nameof(CanManageStores);
|
||||||
|
public const string CanViewInvoices = nameof(CanViewInvoices);
|
||||||
|
public const string CanCreateInvoices = nameof(CanCreateInvoices);
|
||||||
|
public const string CanManageInvoices = nameof(CanManageInvoices);
|
||||||
|
public const string CanManageApps = nameof(CanManageApps);
|
||||||
|
public const string CanViewApps = nameof(CanViewApps);
|
||||||
|
public const string CanManageWallet = nameof(CanManageWallet);
|
||||||
|
public const string CanViewProfile = nameof(CanViewProfile);
|
||||||
|
|
||||||
|
public static AuthorizationOptions AddBTCPayRESTApiPolicies(this AuthorizationOptions options)
|
||||||
|
{
|
||||||
|
AddScopePolicy(options, CanViewStores,
|
||||||
|
context => context.HasScopes(BTCPayScopes.StoreManagement) ||
|
||||||
|
context.HasScopes(BTCPayScopes.ViewStores));
|
||||||
|
AddScopePolicy(options, CanManageStores,
|
||||||
|
context => context.HasScopes(BTCPayScopes.StoreManagement));
|
||||||
|
AddScopePolicy(options, CanViewInvoices,
|
||||||
|
context => context.HasScopes(BTCPayScopes.ViewInvoices) ||
|
||||||
|
context.HasScopes(BTCPayScopes.InvoiceManagement));
|
||||||
|
AddScopePolicy(options, CanCreateInvoices,
|
||||||
|
context => context.HasScopes(BTCPayScopes.CreateInvoices) ||
|
||||||
|
context.HasScopes(BTCPayScopes.InvoiceManagement));
|
||||||
|
AddScopePolicy(options, CanViewApps,
|
||||||
|
context => context.HasScopes(BTCPayScopes.AppManagement) || context.HasScopes(BTCPayScopes.ViewApps));
|
||||||
|
AddScopePolicy(options, CanManageInvoices,
|
||||||
|
context => context.HasScopes(BTCPayScopes.InvoiceManagement));
|
||||||
|
AddScopePolicy(options, CanManageApps,
|
||||||
|
context => context.HasScopes(BTCPayScopes.AppManagement));
|
||||||
|
AddScopePolicy(options, CanManageWallet,
|
||||||
|
context => context.HasScopes(BTCPayScopes.WalletManagement));
|
||||||
|
AddScopePolicy(options, CanViewProfile,
|
||||||
|
context => context.HasScopes(OpenIddictConstants.Scopes.Profile));
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddScopePolicy(AuthorizationOptions options, string name,
|
||||||
|
Func<AuthorizationHandlerContext, bool> scopeGroups)
|
||||||
|
{
|
||||||
|
options.AddPolicy(name,
|
||||||
|
builder => builder.AddRequirements(new LambdaRequirement(scopeGroups)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasScopes(this AuthorizationHandlerContext context, params string[] scopes)
|
||||||
|
{
|
||||||
|
return scopes.All(s => context.User.HasClaim(OpenIddictConstants.Claims.Scope, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LambdaRequirement :
|
||||||
|
AuthorizationHandler<LambdaRequirement>, IAuthorizationRequirement
|
||||||
|
{
|
||||||
|
private readonly Func<AuthorizationHandlerContext, bool> _Func;
|
||||||
|
|
||||||
|
public LambdaRequirement(Func<AuthorizationHandlerContext, bool> func)
|
||||||
|
{
|
||||||
|
_Func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task HandleRequirementAsync(
|
||||||
|
AuthorizationHandlerContext context, LambdaRequirement requirement)
|
||||||
|
{
|
||||||
|
if (_Func.Invoke(context))
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,7 +78,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
ApplicationName = await _applicationManager.GetDisplayNameAsync(application),
|
ApplicationName = await _applicationManager.GetDisplayNameAsync(application),
|
||||||
RequestId = request.RequestId,
|
RequestId = request.RequestId,
|
||||||
Scope = request.Scope
|
Scope = request.GetScopes()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Authentication;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
@@ -41,9 +42,10 @@ namespace BTCPayServer.Controllers.RestApi
|
|||||||
|
|
||||||
[HttpGet("me/is-admin")]
|
[HttpGet("me/is-admin")]
|
||||||
public bool AmIAnAdmin()
|
public bool AmIAnAdmin()
|
||||||
{
|
{
|
||||||
return User.IsInRole(Roles.ServerAdmin);
|
return User.IsInRole(Roles.ServerAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("me/stores")]
|
[HttpGet("me/stores")]
|
||||||
public async Task<StoreData[]> GetCurrentUserStores()
|
public async Task<StoreData[]> GetCurrentUserStores()
|
||||||
{
|
{
|
||||||
@@ -52,10 +54,63 @@ namespace BTCPayServer.Controllers.RestApi
|
|||||||
|
|
||||||
|
|
||||||
[HttpGet("me/stores/{storeId}/can-edit")]
|
[HttpGet("me/stores/{storeId}/can-edit")]
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings.Key, AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings.Key,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
public bool CanEdit(string storeId)
|
public bool CanEdit(string storeId)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region scopes tests
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanViewStores,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanViewStores))]
|
||||||
|
public bool ScopeCanViewStores() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanManageStores,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanManageStores))]
|
||||||
|
public bool ScopeCanManageStores() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanViewInvoices,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanViewInvoices))]
|
||||||
|
public bool ScopeCanViewInvoices() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanCreateInvoices,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanCreateInvoices))]
|
||||||
|
public bool ScopeCanCreateInvoices() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanManageInvoices,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanManageInvoices))]
|
||||||
|
public bool ScopeCanManageInvoices() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanManageApps,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanManageApps))]
|
||||||
|
public bool ScopeCanManageApps() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanViewApps,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
|
||||||
|
[HttpGet(nameof(ScopeCanViewApps))]
|
||||||
|
public bool ScopeCanViewApps() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanManageWallet,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet(nameof(ScopeCanManageWallet))]
|
||||||
|
public bool ScopeCanManageWallet() { return true; }
|
||||||
|
|
||||||
|
[Authorize(Policy = RestAPIPolicies.CanViewProfile,
|
||||||
|
AuthenticationSchemes = OpenIddictValidationDefaults.AuthenticationScheme)]
|
||||||
|
|
||||||
|
[HttpGet(nameof(ScopeCanViewProfile))]
|
||||||
|
public bool ScopeCanViewProfile() { return true; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ namespace BTCPayServer.Hosting
|
|||||||
services.AddSingleton<EmailSenderFactory>();
|
services.AddSingleton<EmailSenderFactory>();
|
||||||
// bundling
|
// bundling
|
||||||
|
|
||||||
services.AddAuthorization(o => Policies.AddBTCPayPolicies(o));
|
services.AddAuthorization(o => o.AddBTCPayPolicies().AddBTCPayRESTApiPolicies());
|
||||||
services.AddBtcPayServerAuthenticationSchemes(configuration);
|
services.AddBtcPayServerAuthenticationSchemes(configuration);
|
||||||
|
|
||||||
services.AddSingleton<IBundleProvider, ResourceBundleProvider>();
|
services.AddSingleton<IBundleProvider, ResourceBundleProvider>();
|
||||||
|
|||||||
@@ -19,10 +19,13 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
|
|||||||
using OpenIddict.Abstractions;
|
using OpenIddict.Abstractions;
|
||||||
using OpenIddict.EntityFrameworkCore.Models;
|
using OpenIddict.EntityFrameworkCore.Models;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using BTCPayServer.Authentication;
|
||||||
using BTCPayServer.Authentication.OpenId;
|
using BTCPayServer.Authentication.OpenId;
|
||||||
using BTCPayServer.PaymentRequest;
|
using BTCPayServer.PaymentRequest;
|
||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
using BTCPayServer.Storage;
|
using BTCPayServer.Storage;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using OpenIddict.Core;
|
||||||
|
|
||||||
namespace BTCPayServer.Hosting
|
namespace BTCPayServer.Hosting
|
||||||
{
|
{
|
||||||
@@ -160,7 +163,7 @@ namespace BTCPayServer.Hosting
|
|||||||
options.EnableLogoutEndpoint("/connect/logout");
|
options.EnableLogoutEndpoint("/connect/logout");
|
||||||
|
|
||||||
//we do not care about these granular controls for now
|
//we do not care about these granular controls for now
|
||||||
options.DisableScopeValidation();
|
options.IgnoreScopePermissions();
|
||||||
options.IgnoreEndpointPermissions();
|
options.IgnoreEndpointPermissions();
|
||||||
// Allow client applications various flows
|
// Allow client applications various flows
|
||||||
options.AllowImplicitFlow();
|
options.AllowImplicitFlow();
|
||||||
@@ -176,7 +179,14 @@ namespace BTCPayServer.Hosting
|
|||||||
OpenIdConnectConstants.Scopes.OfflineAccess,
|
OpenIdConnectConstants.Scopes.OfflineAccess,
|
||||||
OpenIdConnectConstants.Scopes.Email,
|
OpenIdConnectConstants.Scopes.Email,
|
||||||
OpenIdConnectConstants.Scopes.Profile,
|
OpenIdConnectConstants.Scopes.Profile,
|
||||||
OpenIddictConstants.Scopes.Roles);
|
OpenIddictConstants.Scopes.Roles,
|
||||||
|
RestAPIPolicies.BTCPayScopes.ViewStores,
|
||||||
|
RestAPIPolicies.BTCPayScopes.CreateInvoices,
|
||||||
|
RestAPIPolicies.BTCPayScopes.StoreManagement,
|
||||||
|
RestAPIPolicies.BTCPayScopes.ViewApps,
|
||||||
|
RestAPIPolicies.BTCPayScopes.AppManagement
|
||||||
|
);
|
||||||
|
|
||||||
options.AddEventHandler<PasswordGrantTypeEventHandler>();
|
options.AddEventHandler<PasswordGrantTypeEventHandler>();
|
||||||
options.AddEventHandler<AuthorizationCodeGrantTypeEventHandler>();
|
options.AddEventHandler<AuthorizationCodeGrantTypeEventHandler>();
|
||||||
options.AddEventHandler<RefreshTokenGrantTypeEventHandler>();
|
options.AddEventHandler<RefreshTokenGrantTypeEventHandler>();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace BTCPayServer.Models.Authorization
|
namespace BTCPayServer.Models.Authorization
|
||||||
@@ -9,6 +10,6 @@ namespace BTCPayServer.Models.Authorization
|
|||||||
|
|
||||||
[BindNever] public string RequestId { get; set; }
|
[BindNever] public string RequestId { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Scope")] public string Scope { get; set; }
|
[Display(Name = "Scope")] public IEnumerable<string> Scope { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
@model BTCPayServer.Models.Authorization.AuthorizeViewModel
|
@using BTCPayServer.Authentication
|
||||||
|
@using OpenIddict.Abstractions
|
||||||
|
@model BTCPayServer.Models.Authorization.AuthorizeViewModel
|
||||||
|
@{
|
||||||
|
|
||||||
|
var scopeMappings = new Dictionary<string, (string Title, string Description)>()
|
||||||
|
{
|
||||||
|
{RestAPIPolicies.BTCPayScopes.AppManagement, ("Manage your apps", "The app will be able to create, modify and delete all your apps.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.ViewApps, ("View your apps", "The app will be able to list and view all your apps.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.CreateInvoices, ("Create invoices", "The app will be able to create new invoices.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.InvoiceManagement, ("Manage invoices", "The app will be able to create new invoices and mark existing invoices as complete or invalid.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.StoreManagement, ("Manage your stores", "The app will be able to create, modify and delete all your stores.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.ViewStores, ("View your stores", "The app will be able to list and view all your stores.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.WalletManagement, ("Manage your wallet", "The app will be able to manage your wallet associate to stores. This includes configuring it, transaction creation and signing.")},
|
||||||
|
{RestAPIPolicies.BTCPayScopes.ViewInvoices, ("View your invoices", "The app will be able to list and view all your apps.")},
|
||||||
|
{OpenIddictConstants.Scopes.Email, ("View your email", "The app will have access to your email.")},
|
||||||
|
{OpenIddictConstants.Scopes.Profile, ("View your account", "The app will have access to your account details.")},
|
||||||
|
{OpenIddictConstants.Scopes.Roles, ("View your roles", "The app will know if you are a server admin.")},
|
||||||
|
};
|
||||||
|
}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="request_id" value="@Model.RequestId"/>
|
<input type="hidden" name="request_id" value="@Model.RequestId"/>
|
||||||
<section>
|
<section>
|
||||||
<div class="container">
|
<div class="card container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 text-center">
|
<div class="col-lg-12 text-center">
|
||||||
<h2 class="section-heading">Authorization Request</h2>
|
<h2 class="section-heading">Authorization Request</h2>
|
||||||
@@ -11,9 +30,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
@foreach (var scope in Model.Scope)
|
||||||
|
{
|
||||||
|
@if (scopeMappings.TryGetValue(scope, out var text))
|
||||||
|
{
|
||||||
|
<li class="list-group-item">
|
||||||
|
<h5 class="mb-1">@text.Title</h5>
|
||||||
|
<p class="mb-1">@text.Description.</p>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
<div class="col-lg-12 text-center">
|
<div class="col-lg-12 text-center">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-lg btn-success" name="consent" id="consent-yes" type="submit" value="Yes">Authorize app</button>
|
<button class="btn btn-lg btn-primary" name="consent" id="consent-yes" type="submit" value="Yes">Authorize app</button>
|
||||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="sr-only">Toggle Dropdown</span>
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -11,3 +11,4 @@
|
|||||||
<partial name="@extension.Partial"/>
|
<partial name="@extension.Partial"/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user