2020-02-24 14:36:15 +01:00
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Linq ;
using System.Threading.Tasks ;
2020-11-17 13:46:23 +01:00
using BTCPayServer.Abstractions.Extensions ;
using BTCPayServer.Abstractions.Models ;
2020-03-02 16:50:28 +01:00
using BTCPayServer.Client ;
2020-02-24 14:36:15 +01:00
using BTCPayServer.Data ;
using BTCPayServer.Models ;
2020-03-27 04:55:21 +01:00
using BTCPayServer.Security.GreenField ;
2020-02-24 14:36:15 +01:00
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
2020-03-10 13:30:46 +01:00
using NBitcoin ;
using NBitcoin.DataEncoders ;
2020-02-24 14:36:15 +01:00
namespace BTCPayServer.Controllers
{
public partial class ManageController
{
[HttpGet]
public async Task < IActionResult > APIKeys ( )
{
return View ( new ApiKeysViewModel ( )
{
ApiKeyDatas = await _apiKeyRepository . GetKeys ( new APIKeyRepository . APIKeyQuery ( )
{
2020-03-19 11:11:15 +01:00
UserId = new [ ] { _userManager . GetUserId ( User ) }
2020-02-24 14:36:15 +01:00
} )
} ) ;
}
2020-03-19 11:11:15 +01:00
2021-09-07 04:55:53 +02:00
[HttpGet("~/api-keys/{id}/delete")]
public async Task < IActionResult > DeleteAPIKey ( string id )
2020-02-24 14:36:15 +01:00
{
2020-02-26 10:26:38 +01:00
var key = await _apiKeyRepository . GetKey ( id ) ;
if ( key = = null | | key . UserId ! = _userManager . GetUserId ( User ) )
{
return NotFound ( ) ;
}
2021-09-07 04:55:53 +02:00
return View ( "Confirm" , new ConfirmModel
2020-02-26 10:26:38 +01:00
{
2021-09-07 04:55:53 +02:00
Title = "Delete API key" ,
2020-09-17 11:37:49 +02:00
DescriptionHtml = true ,
2021-09-07 04:55:53 +02:00
Description = $"Any application using the API key <strong>{key.Label ?? key.Id}<strong> will immediately lose access." ,
2020-02-26 10:26:38 +01:00
Action = "Delete" ,
2021-09-07 04:55:53 +02:00
ActionUrl = Url . ActionLink ( nameof ( DeleteAPIKeyPost ) , values : new { id } )
2020-02-26 10:26:38 +01:00
} ) ;
}
2021-09-07 04:55:53 +02:00
[HttpPost("~/api-keys/{id}/delete")]
public async Task < IActionResult > DeleteAPIKeyPost ( string id )
2020-02-26 10:26:38 +01:00
{
var key = await _apiKeyRepository . GetKey ( id ) ;
if ( key = = null | | key . UserId ! = _userManager . GetUserId ( User ) )
{
return NotFound ( ) ;
}
2020-02-24 14:36:15 +01:00
await _apiKeyRepository . Remove ( id , _userManager . GetUserId ( User ) ) ;
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Success ,
Message = "API Key removed"
} ) ;
return RedirectToAction ( "APIKeys" ) ;
}
[HttpGet]
public async Task < IActionResult > AddApiKey ( )
{
if ( ! _btcPayServerEnvironment . IsSecure )
{
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Error ,
Message = "Cannot generate api keys while not on https or tor"
} ) ;
return RedirectToAction ( "APIKeys" ) ;
}
return View ( "AddApiKey" , await SetViewModelValues ( new AddApiKeyViewModel ( ) ) ) ;
}
2020-02-28 19:42:17 +01:00
2020-02-24 14:36:15 +01:00
[HttpGet("~/api-keys/authorize")]
2020-09-17 11:37:49 +02:00
public async Task < IActionResult > AuthorizeAPIKey ( string [ ] permissions , string applicationName = null , Uri redirect = null ,
2020-02-28 19:42:17 +01:00
bool strict = true , bool selectiveStores = false , string applicationIdentifier = null )
2020-02-24 14:36:15 +01:00
{
if ( ! _btcPayServerEnvironment . IsSecure )
{
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Error ,
Message = "Cannot generate api keys while not on https or tor"
} ) ;
return RedirectToAction ( "APIKeys" ) ;
}
2020-06-28 10:55:27 +02:00
2020-02-24 14:36:15 +01:00
permissions ? ? = Array . Empty < string > ( ) ;
2020-08-04 10:03:51 +02:00
var requestPermissions = Permission . ToPermissions ( permissions ) ;
2020-12-23 05:19:38 +01:00
if ( redirect ? . IsAbsoluteUri is false )
{
redirect = null ;
}
2020-02-28 19:42:17 +01:00
if ( ! string . IsNullOrEmpty ( applicationIdentifier ) & & redirect ! = null )
{
2020-12-23 05:19:38 +01:00
2020-02-28 19:42:17 +01:00
//check if there is an app identifier that matches and belongs to the current user
var keys = await _apiKeyRepository . GetKeys ( new APIKeyRepository . APIKeyQuery ( )
{
UserId = new [ ] { _userManager . GetUserId ( User ) }
} ) ;
2020-08-28 09:15:08 +02:00
foreach ( var key in keys )
2020-02-28 19:42:17 +01:00
{
2020-08-28 09:15:08 +02:00
var blob = key . GetBlob ( ) ;
if ( blob . ApplicationIdentifier ! = applicationIdentifier | |
2020-12-23 05:19:38 +01:00
blob . ApplicationAuthority ! = redirect . AbsoluteUri )
2020-08-28 09:15:08 +02:00
{
continue ;
}
//matched the identifier and authority, but we need to check if what the app is requesting in terms of permissions is enough
var alreadyPresentPermissions = Permission . ToPermissions ( blob . Permissions )
. GroupBy ( permission = > permission . Policy ) ;
var fail = false ;
foreach ( var permission in requestPermissions . GroupBy ( permission = > permission . Policy ) )
2020-02-28 19:42:17 +01:00
{
2020-08-28 09:15:08 +02:00
var presentPermission =
alreadyPresentPermissions . SingleOrDefault ( grouping = > permission . Key = = grouping . Key ) ;
if ( strict & & presentPermission = = null )
2020-02-28 19:42:17 +01:00
{
2020-08-28 09:15:08 +02:00
fail = true ;
break ;
2020-02-28 19:42:17 +01:00
}
2020-08-28 09:15:08 +02:00
if ( Policies . IsStorePolicy ( permission . Key ) )
2020-08-04 10:03:51 +02:00
{
2020-08-28 09:15:08 +02:00
if ( ! selectiveStores & &
permission . Any ( permission1 = > ! string . IsNullOrEmpty ( permission1 . Scope ) ) )
2020-08-04 10:03:51 +02:00
{
2020-08-28 09:15:08 +02:00
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Error ,
Message =
"Cannot request specific store permission when selectiveStores is not enable"
} ) ;
return RedirectToAction ( "APIKeys" ) ;
2020-08-04 10:03:51 +02:00
}
2020-08-28 09:15:08 +02:00
else if ( ! selectiveStores & & presentPermission . Any ( permission1 = >
! string . IsNullOrEmpty ( permission1 . Scope ) ) )
2020-08-04 10:03:51 +02:00
{
2020-08-28 09:15:08 +02:00
fail = true ;
break ;
2020-08-04 10:03:51 +02:00
}
}
2020-08-28 09:15:08 +02:00
}
2020-02-28 19:42:17 +01:00
2020-08-28 09:15:08 +02:00
if ( fail )
{
continue ;
2020-02-28 19:42:17 +01:00
}
2020-08-28 09:15:08 +02:00
//we have a key that is sufficient, redirect to a page to confirm that it's ok to provide this key to the app.
2020-09-17 11:37:49 +02:00
return View ( "ConfirmAPIKey" ,
new AuthorizeApiKeysViewModel ( )
2020-08-28 09:15:08 +02:00
{
2020-09-17 11:37:49 +02:00
ApiKey = key . Id ,
RedirectUrl = redirect ,
Label = applicationName ,
ApplicationName = applicationName ,
SelectiveStores = selectiveStores ,
Strict = strict ,
Permissions = string . Join ( ';' , permissions ) ,
ApplicationIdentifier = applicationIdentifier
2020-08-28 09:15:08 +02:00
} ) ;
2020-02-28 19:42:17 +01:00
}
}
2020-08-28 09:15:08 +02:00
2020-03-23 14:17:17 +01:00
var vm = await SetViewModelValues ( new AuthorizeApiKeysViewModel ( )
2020-02-24 14:36:15 +01:00
{
2020-02-28 19:42:17 +01:00
RedirectUrl = redirect ,
2020-02-25 14:43:53 +01:00
Label = applicationName ,
2020-02-24 14:36:15 +01:00
ApplicationName = applicationName ,
SelectiveStores = selectiveStores ,
Strict = strict ,
2020-08-04 10:03:51 +02:00
Permissions = string . Join ( ';' , requestPermissions ) ,
2020-02-28 19:42:17 +01:00
ApplicationIdentifier = applicationIdentifier
2020-02-24 14:36:15 +01:00
} ) ;
2020-03-23 14:17:17 +01:00
AdjustVMForAuthorization ( vm ) ;
2020-06-28 10:55:27 +02:00
2020-02-24 14:36:15 +01:00
return View ( vm ) ;
}
2020-03-23 14:17:17 +01:00
private void AdjustVMForAuthorization ( AuthorizeApiKeysViewModel vm )
2020-02-24 14:36:15 +01:00
{
2021-09-19 07:38:00 +02:00
var permissions = vm . Permissions ? . Split ( ';' ) ? ? Array . Empty < string > ( ) ;
var permissionsWithStoreIDs = new List < string > ( ) ;
/ * *
* Go over each permission and associated store IDs and
* join them so that permission for a specific store is parsed correctly
* /
for ( var i = 0 ; i < permissions . Length ; i + + ) {
var currPerm = permissions [ i ] ;
var storeIds = vm . PermissionValues [ i ] . SpecificStores . ToArray ( ) ;
if ( storeIds . Length > 0 ) {
for ( var x = 0 ; x < storeIds . Length ; x + + ) {
permissionsWithStoreIDs . Add ( $"{currPerm}:{storeIds[x]}" ) ;
}
} else {
permissionsWithStoreIDs . Add ( currPerm ) ;
}
}
var parsedPermissions = Permission . ToPermissions ( permissionsWithStoreIDs . ToArray ( ) ) . GroupBy ( permission = > permission . Policy ) ;
2020-02-24 14:36:15 +01:00
2020-03-23 14:17:17 +01:00
for ( var index = vm . PermissionValues . Count - 1 ; index > = 0 ; index - - )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
var permissionValue = vm . PermissionValues [ index ] ;
var wanted = parsedPermissions ? . SingleOrDefault ( permission = >
permission . Key . Equals ( permissionValue . Permission ,
StringComparison . InvariantCultureIgnoreCase ) ) ;
2020-06-28 10:55:27 +02:00
if ( vm . Strict & & ! ( wanted ? . Any ( ) ? ? false ) )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
vm . PermissionValues . RemoveAt ( index ) ;
continue ;
}
2020-06-28 10:55:27 +02:00
else if ( wanted ? . Any ( ) ? ? false )
2020-03-23 14:17:17 +01:00
{
2021-09-20 01:19:14 +02:00
var commandParts = vm . Command ? . Split ( ':' , StringSplitOptions . RemoveEmptyEntries ) ? ? Array . Empty < string > ( ) ;
var command = commandParts . Length > 1 ? commandParts [ 1 ] : null ;
var isPerformingAnAction = command = = "change-store-mode" | | command = = "add-store" ;
// Don't want to accidentally change mode for the user if they are explicitly performing some action
if ( isPerformingAnAction ) {
continue ;
}
2020-03-23 14:17:17 +01:00
if ( vm . SelectiveStores & & Policies . IsStorePolicy ( permissionValue . Permission ) & &
2020-06-07 16:17:48 +02:00
wanted . Any ( permission = > ! string . IsNullOrEmpty ( permission . Scope ) ) )
2020-03-23 14:17:17 +01:00
{
permissionValue . StoreMode = AddApiKeyViewModel . ApiKeyStoreMode . Specific ;
2020-06-07 16:17:48 +02:00
permissionValue . SpecificStores = wanted . Select ( permission = > permission . Scope ) . ToList ( ) ;
2020-03-23 14:17:17 +01:00
}
else
2020-03-19 11:11:15 +01:00
{
2020-03-23 14:17:17 +01:00
permissionValue . StoreMode = AddApiKeyViewModel . ApiKeyStoreMode . AllStores ;
permissionValue . SpecificStores = new List < string > ( ) ;
permissionValue . Value = true ;
2020-03-19 11:11:15 +01:00
}
2020-02-24 14:36:15 +01:00
}
}
2020-03-23 14:17:17 +01:00
}
2020-02-24 14:36:15 +01:00
2020-03-23 14:17:17 +01:00
[HttpPost("~/api-keys/authorize")]
public async Task < IActionResult > AuthorizeAPIKey ( [ FromForm ] AuthorizeApiKeysViewModel viewModel )
{
await SetViewModelValues ( viewModel ) ;
2020-06-28 10:55:27 +02:00
2020-03-23 14:17:17 +01:00
AdjustVMForAuthorization ( viewModel ) ;
var ar = HandleCommands ( viewModel ) ;
2020-06-28 10:55:27 +02:00
2020-03-23 14:17:17 +01:00
if ( ar ! = null )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
return ar ;
}
2020-06-28 10:55:27 +02:00
2020-03-23 14:17:17 +01:00
for ( int i = 0 ; i < viewModel . PermissionValues . Count ; i + + )
{
if ( viewModel . PermissionValues [ i ] . Forbidden & & viewModel . Strict )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
viewModel . PermissionValues [ i ] . Value = false ;
ModelState . AddModelError ( $"{viewModel.PermissionValues}[{i}].Value" ,
$"The permission '{viewModel.PermissionValues[i].Title}' is required for this application." ) ;
2020-02-24 14:36:15 +01:00
}
2020-03-23 14:17:17 +01:00
if ( viewModel . PermissionValues [ i ] . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . Specific & &
! viewModel . SelectiveStores )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
viewModel . PermissionValues [ i ] . StoreMode = AddApiKeyViewModel . ApiKeyStoreMode . AllStores ;
ModelState . AddModelError ( $"{viewModel.PermissionValues}[{i}].Value" ,
$"The permission '{viewModel.PermissionValues[i].Title}' cannot be store specific for this application." ) ;
2020-02-24 14:36:15 +01:00
}
}
2020-06-28 10:55:27 +02:00
2020-02-24 14:36:15 +01:00
if ( ! ModelState . IsValid )
{
return View ( viewModel ) ;
}
2020-06-28 10:55:27 +02:00
2020-09-17 11:37:49 +02:00
var command = viewModel . Command . ToLowerInvariant ( ) ;
switch ( command )
2020-02-24 14:36:15 +01:00
{
2020-09-17 11:37:49 +02:00
case "cancel" :
2020-02-24 14:36:15 +01:00
return RedirectToAction ( "APIKeys" ) ;
2020-09-17 11:37:49 +02:00
case "authorize" :
case "confirm" :
var key = command = = "authorize"
2020-12-23 05:19:38 +01:00
? await CreateKey ( viewModel , ( viewModel . ApplicationIdentifier , viewModel . RedirectUrl . AbsoluteUri ) )
2020-09-17 11:37:49 +02:00
: await _apiKeyRepository . GetKey ( viewModel . ApiKey ) ;
2020-08-28 09:15:08 +02:00
2020-02-28 19:42:17 +01:00
if ( viewModel . RedirectUrl ! = null )
{
2020-09-17 11:37:49 +02:00
var permissions = key . GetBlob ( ) . Permissions ;
var redirectVm = new PostRedirectViewModel ( )
{
2020-12-23 05:19:38 +01:00
FormUrl = viewModel . RedirectUrl . AbsoluteUri ,
2020-09-17 11:37:49 +02:00
Parameters =
{
new KeyValuePair < string , string > ( "apiKey" , key . Id ) ,
new KeyValuePair < string , string > ( "userId" , key . UserId )
}
} ;
foreach ( var permission in permissions )
{
redirectVm . Parameters . Add (
new KeyValuePair < string , string > ( "permissions[]" , permission ) ) ;
}
return View ( "PostRedirect" , redirectVm ) ;
2020-02-28 19:42:17 +01:00
}
2020-02-24 14:36:15 +01:00
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Success ,
2020-04-06 12:22:50 +02:00
Html = $"API key generated! <code class='alert-link'>{key.Id}</code>"
2020-02-24 14:36:15 +01:00
} ) ;
2020-09-17 11:37:49 +02:00
2020-03-19 11:11:15 +01:00
return RedirectToAction ( "APIKeys" , new { key = key . Id } ) ;
2020-09-17 11:37:49 +02:00
2020-03-19 11:11:15 +01:00
default :
return View ( viewModel ) ;
2020-02-24 14:36:15 +01:00
}
}
[HttpPost]
public async Task < IActionResult > AddApiKey ( AddApiKeyViewModel viewModel )
{
await SetViewModelValues ( viewModel ) ;
var ar = HandleCommands ( viewModel ) ;
if ( ar ! = null )
{
return ar ;
}
if ( ! ModelState . IsValid )
{
return View ( viewModel ) ;
}
var key = await CreateKey ( viewModel ) ;
TempData . SetStatusMessageModel ( new StatusMessageModel ( )
{
Severity = StatusMessageModel . StatusSeverity . Success ,
2020-04-06 12:22:50 +02:00
Html = $"API key generated! <code class='alert-link'>{key.Id}</code>"
2020-02-24 14:36:15 +01:00
} ) ;
return RedirectToAction ( "APIKeys" ) ;
}
2020-09-17 11:37:49 +02:00
2020-02-24 14:36:15 +01:00
private IActionResult HandleCommands ( AddApiKeyViewModel viewModel )
{
2020-03-23 14:17:17 +01:00
if ( string . IsNullOrEmpty ( viewModel . Command ) )
{
return null ;
}
var parts = viewModel . Command . Split ( ':' , StringSplitOptions . RemoveEmptyEntries ) ;
var permission = parts [ 0 ] ;
if ( ! Policies . IsStorePolicy ( permission ) )
{
return null ;
}
var permissionValueItem = viewModel . PermissionValues . Single ( item = > item . Permission = = permission ) ;
var command = parts [ 1 ] ;
var storeIndex = parts . Length = = 3 ? parts [ 2 ] : null ;
2020-06-28 10:55:27 +02:00
2020-03-23 14:17:17 +01:00
ModelState . Clear ( ) ;
switch ( command )
2020-02-24 14:36:15 +01:00
{
case "change-store-mode" :
2020-03-23 14:17:17 +01:00
permissionValueItem . StoreMode = permissionValueItem . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . Specific
2020-02-24 14:36:15 +01:00
? AddApiKeyViewModel . ApiKeyStoreMode . AllStores
: AddApiKeyViewModel . ApiKeyStoreMode . Specific ;
2021-09-19 07:38:00 +02:00
// Make sure we don't keep specific store IDs if we switched back to "all stores" from "specific stores"
if ( permissionValueItem . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . AllStores )
{
permissionValueItem . SpecificStores = new List < string > ( ) ;
}
2020-02-24 14:36:15 +01:00
2020-03-23 14:17:17 +01:00
if ( permissionValueItem . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . Specific & &
! permissionValueItem . SpecificStores . Any ( ) & & viewModel . Stores . Any ( ) )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
permissionValueItem . SpecificStores . Add ( null ) ;
2020-02-24 14:36:15 +01:00
}
return View ( viewModel ) ;
2020-09-17 11:37:49 +02:00
2020-02-24 14:36:15 +01:00
case "add-store" :
2020-03-23 14:17:17 +01:00
permissionValueItem . SpecificStores . Add ( null ) ;
2020-02-24 14:36:15 +01:00
return View ( viewModel ) ;
2020-03-23 14:17:17 +01:00
case "remove-store" :
2020-06-28 10:55:27 +02:00
{
if ( storeIndex ! = null )
permissionValueItem . SpecificStores . RemoveAt ( int . Parse ( storeIndex ,
CultureInfo . InvariantCulture ) ) ;
return View ( viewModel ) ;
}
2020-02-24 14:36:15 +01:00
}
2020-06-28 10:55:27 +02:00
2020-02-24 14:36:15 +01:00
return null ;
}
2020-08-04 13:10:48 +02:00
private async Task < APIKeyData > CreateKey ( AddApiKeyViewModel viewModel , ( string appIdentifier , string appAuthority ) app = default )
2020-02-24 14:36:15 +01:00
{
var key = new APIKeyData ( )
{
2020-03-10 13:30:46 +01:00
Id = Encoders . Hex . EncodeData ( RandomUtils . GetBytes ( 20 ) ) ,
2020-02-25 14:43:53 +01:00
Type = APIKeyType . Permanent ,
UserId = _userManager . GetUserId ( User ) ,
2020-02-28 19:42:17 +01:00
Label = viewModel . Label ,
2020-02-24 14:36:15 +01:00
} ;
2020-04-02 08:59:20 +02:00
key . SetBlob ( new APIKeyBlob ( )
{
2020-08-04 13:10:48 +02:00
Permissions = GetPermissionsFromViewModel ( viewModel ) . Select ( p = > p . ToString ( ) ) . Distinct ( ) . ToArray ( ) ,
ApplicationAuthority = app . appAuthority ,
ApplicationIdentifier = app . appIdentifier
2020-04-02 08:59:20 +02:00
} ) ;
2020-02-24 14:36:15 +01:00
await _apiKeyRepository . CreateKey ( key ) ;
return key ;
}
2020-03-19 11:11:15 +01:00
private IEnumerable < Permission > GetPermissionsFromViewModel ( AddApiKeyViewModel viewModel )
2020-02-24 14:36:15 +01:00
{
2020-03-19 11:11:15 +01:00
List < Permission > permissions = new List < Permission > ( ) ;
2020-03-23 14:17:17 +01:00
foreach ( var p in viewModel . PermissionValues . Where ( tuple = > ! tuple . Forbidden ) )
2020-02-24 14:36:15 +01:00
{
2020-03-23 14:17:17 +01:00
if ( Policies . IsStorePolicy ( p . Permission ) )
{
if ( p . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . AllStores & & p . Value )
{
permissions . Add ( Permission . Create ( p . Permission ) ) ;
}
else if ( p . StoreMode = = AddApiKeyViewModel . ApiKeyStoreMode . Specific )
{
permissions . AddRange ( p . SpecificStores . Select ( s = > Permission . Create ( p . Permission , s ) ) ) ;
}
}
2020-06-28 10:55:27 +02:00
else if ( p . Value & & Permission . TryCreatePermission ( p . Permission , null , out var pp ) )
2020-03-19 11:11:15 +01:00
permissions . Add ( pp ) ;
2020-02-24 14:36:15 +01:00
}
2020-03-23 14:17:17 +01:00
2020-06-28 10:55:27 +02:00
2020-03-12 14:59:24 +01:00
return permissions . Distinct ( ) ;
2020-02-24 14:36:15 +01:00
}
private async Task < T > SetViewModelValues < T > ( T viewModel ) where T : AddApiKeyViewModel
{
viewModel . Stores = await _StoreRepository . GetStoresByUserId ( _userManager . GetUserId ( User ) ) ;
2020-03-23 14:17:17 +01:00
var isAdmin = ( await _authorizationService . AuthorizeAsync ( User , Policies . CanModifyServerSettings ) )
. Succeeded ;
viewModel . PermissionValues ? ? = Policies . AllPolicies
2020-06-24 03:34:09 +02:00
. Where ( p = > AddApiKeyViewModel . PermissionValueItem . PermissionDescriptions . ContainsKey ( p ) )
2020-03-23 14:17:17 +01:00
. Select ( s = > new AddApiKeyViewModel . PermissionValueItem ( )
{
2020-06-28 10:55:27 +02:00
Permission = s ,
Value = false ,
2020-03-23 14:17:17 +01:00
Forbidden = Policies . IsServerPolicy ( s ) & & ! isAdmin
} ) . ToList ( ) ;
2020-03-19 11:11:15 +01:00
if ( ! isAdmin )
{
2020-12-08 07:20:59 +01:00
foreach ( var p in viewModel . PermissionValues . Where ( item = > item . Permission is null | | Policies . IsServerPolicy ( item . Permission ) ) )
2020-03-19 11:11:15 +01:00
{
2020-03-23 14:17:17 +01:00
p . Forbidden = true ;
2020-03-19 11:11:15 +01:00
}
}
2020-03-23 14:17:17 +01:00
2020-02-24 14:36:15 +01:00
return viewModel ;
}
public class AddApiKeyViewModel
{
2020-02-25 14:43:53 +01:00
public string Label { get ; set ; }
2020-02-24 14:36:15 +01:00
public StoreData [ ] Stores { get ; set ; }
public string Command { get ; set ; }
2020-03-12 14:59:24 +01:00
public List < PermissionValueItem > PermissionValues { get ; set ; }
2020-02-24 14:36:15 +01:00
public enum ApiKeyStoreMode
{
AllStores ,
Specific
}
2020-03-12 14:59:24 +01:00
public class PermissionValueItem
{
2020-03-19 11:11:15 +01:00
public static readonly Dictionary < string , ( string Title , string Description ) > PermissionDescriptions = new Dictionary < string , ( string Title , string Description ) > ( )
{
2020-03-20 05:58:07 +01:00
{ BTCPayServer . Client . Policies . Unrestricted , ( "Unrestricted access" , "The app will have unrestricted access to your account." ) } ,
{ BTCPayServer . Client . Policies . CanCreateUser , ( "Create new users" , "The app will be able to create new users on this server." ) } ,
2021-04-08 05:40:57 +02:00
{ BTCPayServer . Client . Policies . CanDeleteUser , ( "Delete user" , "The app will be able to delete the user to whom it is assigned. Admin users can delete any user without this permission." ) } ,
2021-07-10 17:30:01 +02:00
{ BTCPayServer . Client . Policies . CanModifyStoreSettings , ( "Modify your stores" , "The app will be able to manage invoices on all your stores and modify their settings." ) } ,
{ $"{BTCPayServer.Client.Policies.CanModifyStoreSettings}:" , ( "Manage selected stores" , "The app will be able to manage invoices on the selected stores and modify their settings." ) } ,
2021-05-07 18:51:10 +02:00
{ BTCPayServer . Client . Policies . CanModifyStoreWebhooks , ( "Modify stores webhooks" , "The app will modify the webhooks of all your stores." ) } ,
{ $"{BTCPayServer.Client.Policies.CanModifyStoreWebhooks}:" , ( "Modify selected stores' webhooks" , "The app will modify the webhooks of the selected stores." ) } ,
2020-03-23 14:17:17 +01:00
{ BTCPayServer . Client . Policies . CanViewStoreSettings , ( "View your stores" , "The app will be able to view stores settings." ) } ,
{ $"{BTCPayServer.Client.Policies.CanViewStoreSettings}:" , ( "View your stores" , "The app will be able to view the selected stores' settings." ) } ,
2021-08-03 14:10:48 +02:00
{ BTCPayServer . Client . Policies . CanModifyServerSettings , ( "Manage your server" , "The app will have total control on the server settings of your server." ) } ,
2020-03-20 05:58:07 +01:00
{ BTCPayServer . Client . Policies . CanViewProfile , ( "View your profile" , "The app will be able to view your user profile." ) } ,
{ BTCPayServer . Client . Policies . CanModifyProfile , ( "Manage your profile" , "The app will be able to view and modify your user profile." ) } ,
2020-12-11 15:11:08 +01:00
{ BTCPayServer . Client . Policies . CanManageNotificationsForUser , ( "Manage your notifications" , "The app will be able to view and modify your user notifications." ) } ,
{ BTCPayServer . Client . Policies . CanViewNotificationsForUser , ( "View your notifications" , "The app will be able to view your user notifications." ) } ,
2020-03-23 14:17:17 +01:00
{ BTCPayServer . Client . Policies . CanCreateInvoice , ( "Create an invoice" , "The app will be able to create new invoices." ) } ,
{ $"{BTCPayServer.Client.Policies.CanCreateInvoice}:" , ( "Create an invoice" , "The app will be able to create new invoices on the selected stores." ) } ,
2020-07-22 13:58:41 +02:00
{ BTCPayServer . Client . Policies . CanViewInvoices , ( "View invoices" , "The app will be able to view invoices." ) } ,
2021-08-15 04:44:37 +02:00
{ BTCPayServer . Client . Policies . CanModifyInvoices , ( "Modify invoices" , "The app will be able to modify and view invoices." ) } ,
2020-07-22 13:58:41 +02:00
{ $"{BTCPayServer.Client.Policies.CanViewInvoices}:" , ( "View invoices" , "The app will be able to view invoices on the selected stores." ) } ,
2021-08-15 04:44:37 +02:00
{ $"{BTCPayServer.Client.Policies.CanModifyInvoices}:" , ( "Modify invoices" , "The app will be able to modify and view invoices on the selected stores." ) } ,
2020-05-19 19:59:23 +02:00
{ BTCPayServer . Client . Policies . CanModifyPaymentRequests , ( "Modify your payment requests" , "The app will be able to view, modify, delete and create new payment requests on all your stores." ) } ,
{ $"{BTCPayServer.Client.Policies.CanModifyPaymentRequests}:" , ( "Manage selected stores' payment requests" , "The app will be able to view, modify, delete and create new payment requests on the selected stores." ) } ,
{ BTCPayServer . Client . Policies . CanViewPaymentRequests , ( "View your payment requests" , "The app will be able to view payment requests." ) } ,
{ $"{BTCPayServer.Client.Policies.CanViewPaymentRequests}:" , ( "View your payment requests" , "The app will be able to view the selected stores' payment requests." ) } ,
2020-05-29 02:00:13 +02:00
{ BTCPayServer . Client . Policies . CanUseInternalLightningNode , ( "Use the internal lightning node" , "The app will be able to use the internal BTCPay Server lightning node to create BOLT11 invoices, connect to other nodes, open new channels and pay BOLT11 invoices." ) } ,
{ BTCPayServer . Client . Policies . CanCreateLightningInvoiceInternalNode , ( "Create invoices with internal lightning node" , "The app will be able to use the internal BTCPay Server lightning node to create BOLT11 invoices." ) } ,
{ BTCPayServer . Client . Policies . CanUseLightningNodeInStore , ( "Use the lightning nodes associated with your stores" , "The app will be able to use the lightning nodes connected to all your stores to create BOLT11 invoices, connect to other nodes, open new channels and pay BOLT11 invoices." ) } ,
{ BTCPayServer . Client . Policies . CanCreateLightningInvoiceInStore , ( "Create invoices the lightning nodes associated with your stores" , "The app will be able to use the lightning nodes connected to all your stores to create BOLT11 invoices." ) } ,
{ $"{BTCPayServer.Client.Policies.CanUseLightningNodeInStore}:" , ( "Use the lightning nodes associated with your stores" , "The app will be able to use the lightning nodes connected to the selected stores to create BOLT11 invoices, connect to other nodes, open new channels and pay BOLT11 invoices." ) } ,
{ $"{BTCPayServer.Client.Policies.CanCreateLightningInvoiceInStore}:" , ( "Create invoices the lightning nodes associated with your stores" , "The app will be able to use the lightning nodes connected to the selected stores to create BOLT11 invoices." ) } ,
2020-03-19 11:11:15 +01:00
} ;
public string Title
{
get
{
2020-06-28 10:55:27 +02:00
return PermissionDescriptions [ $"{Permission}{(StoreMode == ApiKeyStoreMode.Specific ? " : " : " ")}" ] . Title ;
2020-03-19 11:11:15 +01:00
}
}
public string Description
{
get
{
2020-06-28 10:55:27 +02:00
return PermissionDescriptions [ $"{Permission}{(StoreMode == ApiKeyStoreMode.Specific ? " : " : " ")}" ] . Description ;
2020-03-19 11:11:15 +01:00
}
}
2020-03-12 14:59:24 +01:00
public string Permission { get ; set ; }
public bool Value { get ; set ; }
2020-03-19 11:11:15 +01:00
public bool Forbidden { get ; set ; }
2020-03-23 14:17:17 +01:00
public ApiKeyStoreMode StoreMode { get ; set ; } = ApiKeyStoreMode . AllStores ;
public List < string > SpecificStores { get ; set ; } = new List < string > ( ) ;
2020-03-12 14:59:24 +01:00
}
2020-02-24 14:36:15 +01:00
}
public class AuthorizeApiKeysViewModel : AddApiKeyViewModel
{
public string ApplicationName { get ; set ; }
2020-02-28 19:42:17 +01:00
public string ApplicationIdentifier { get ; set ; }
public Uri RedirectUrl { get ; set ; }
2020-02-24 14:36:15 +01:00
public bool Strict { get ; set ; }
public bool SelectiveStores { get ; set ; }
public string Permissions { get ; set ; }
2020-09-17 11:37:49 +02:00
public string ApiKey { get ; set ; }
2020-02-24 14:36:15 +01:00
}
public class ApiKeysViewModel
{
public List < APIKeyData > ApiKeyDatas { get ; set ; }
}
}
}