2020-06-29 04:44:35 +02:00
|
|
|
using System;
|
2020-03-02 16:50:28 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
namespace BTCPayServer.Client
|
|
|
|
{
|
2020-03-20 05:41:47 +01:00
|
|
|
public class Policies
|
2020-03-02 16:50:28 +01:00
|
|
|
{
|
2023-01-16 13:42:54 +01:00
|
|
|
public const string CanViewLightningInvoiceInternalNode = "btcpay.server.canviewlightninginvoiceinternalnode";
|
2020-05-29 02:00:13 +02:00
|
|
|
public const string CanCreateLightningInvoiceInternalNode = "btcpay.server.cancreatelightninginvoiceinternalnode";
|
2023-01-16 13:42:54 +01:00
|
|
|
public const string CanViewLightningInvoiceInStore = "btcpay.store.canviewlightninginvoice";
|
2020-05-29 02:00:13 +02:00
|
|
|
public const string CanCreateLightningInvoiceInStore = "btcpay.store.cancreatelightninginvoice";
|
|
|
|
public const string CanUseInternalLightningNode = "btcpay.server.canuseinternallightningnode";
|
|
|
|
public const string CanUseLightningNodeInStore = "btcpay.store.canuselightningnode";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string CanModifyServerSettings = "btcpay.server.canmodifyserversettings";
|
|
|
|
public const string CanModifyStoreSettings = "btcpay.store.canmodifystoresettings";
|
2020-11-13 06:01:51 +01:00
|
|
|
public const string CanModifyStoreWebhooks = "btcpay.store.webhooks.canmodifywebhooks";
|
2020-06-27 08:34:03 +02:00
|
|
|
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
|
2020-07-22 13:58:41 +02:00
|
|
|
public const string CanViewInvoices = "btcpay.store.canviewinvoices";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string CanCreateInvoice = "btcpay.store.cancreateinvoice";
|
2021-07-10 17:30:01 +02:00
|
|
|
public const string CanModifyInvoices = "btcpay.store.canmodifyinvoices";
|
2020-05-19 19:59:23 +02:00
|
|
|
public const string CanViewPaymentRequests = "btcpay.store.canviewpaymentrequests";
|
|
|
|
public const string CanModifyPaymentRequests = "btcpay.store.canmodifypaymentrequests";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string CanModifyProfile = "btcpay.user.canmodifyprofile";
|
|
|
|
public const string CanViewProfile = "btcpay.user.canviewprofile";
|
2020-12-11 15:11:08 +01:00
|
|
|
public const string CanManageNotificationsForUser = "btcpay.user.canmanagenotificationsforuser";
|
|
|
|
public const string CanViewNotificationsForUser = "btcpay.user.canviewnotificationsforuser";
|
2022-02-15 16:19:52 +01:00
|
|
|
public const string CanViewUsers = "btcpay.server.canviewusers";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string CanCreateUser = "btcpay.server.cancreateuser";
|
2023-02-24 08:19:03 +01:00
|
|
|
public const string CanManageUsers = "btcpay.server.canmanageusers";
|
2021-04-08 05:40:57 +02:00
|
|
|
public const string CanDeleteUser = "btcpay.user.candeleteuser";
|
2020-06-24 03:34:09 +02:00
|
|
|
public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments";
|
2023-01-26 01:46:05 +01:00
|
|
|
public const string CanCreatePullPayments = "btcpay.store.cancreatepullpayments";
|
|
|
|
public const string CanCreateNonApprovedPullPayments = "btcpay.store.cancreatenonapprovedpullpayments";
|
2022-05-18 07:59:56 +02:00
|
|
|
public const string CanViewCustodianAccounts = "btcpay.store.canviewcustodianaccounts";
|
|
|
|
public const string CanManageCustodianAccounts = "btcpay.store.canmanagecustodianaccounts";
|
|
|
|
public const string CanDepositToCustodianAccounts = "btcpay.store.candeposittocustodianaccount";
|
|
|
|
public const string CanWithdrawFromCustodianAccounts = "btcpay.store.canwithdrawfromcustodianaccount";
|
|
|
|
public const string CanTradeCustodianAccount = "btcpay.store.cantradecustodianaccount";
|
2020-03-19 11:11:15 +01:00
|
|
|
public const string Unrestricted = "unrestricted";
|
|
|
|
public static IEnumerable<string> AllPolicies
|
2020-03-12 14:59:24 +01:00
|
|
|
{
|
2020-03-19 11:11:15 +01:00
|
|
|
get
|
2020-03-12 14:59:24 +01:00
|
|
|
{
|
2020-07-22 13:58:41 +02:00
|
|
|
yield return CanViewInvoices;
|
2020-03-19 11:11:15 +01:00
|
|
|
yield return CanCreateInvoice;
|
2021-07-10 17:30:01 +02:00
|
|
|
yield return CanModifyInvoices;
|
2020-11-13 06:01:51 +01:00
|
|
|
yield return CanModifyStoreWebhooks;
|
2020-03-19 11:11:15 +01:00
|
|
|
yield return CanModifyServerSettings;
|
|
|
|
yield return CanModifyStoreSettings;
|
|
|
|
yield return CanViewStoreSettings;
|
2020-05-19 19:59:23 +02:00
|
|
|
yield return CanViewPaymentRequests;
|
|
|
|
yield return CanModifyPaymentRequests;
|
2020-03-19 11:11:15 +01:00
|
|
|
yield return CanModifyProfile;
|
|
|
|
yield return CanViewProfile;
|
2022-02-15 16:19:52 +01:00
|
|
|
yield return CanViewUsers;
|
2020-03-19 11:11:15 +01:00
|
|
|
yield return CanCreateUser;
|
2021-03-10 03:21:33 +01:00
|
|
|
yield return CanDeleteUser;
|
2020-12-11 15:11:08 +01:00
|
|
|
yield return CanManageNotificationsForUser;
|
|
|
|
yield return CanViewNotificationsForUser;
|
2020-03-19 11:11:15 +01:00
|
|
|
yield return Unrestricted;
|
2020-05-29 02:00:13 +02:00
|
|
|
yield return CanUseInternalLightningNode;
|
2023-01-16 13:42:54 +01:00
|
|
|
yield return CanViewLightningInvoiceInternalNode;
|
2020-05-29 02:00:13 +02:00
|
|
|
yield return CanCreateLightningInvoiceInternalNode;
|
|
|
|
yield return CanUseLightningNodeInStore;
|
2023-01-16 13:42:54 +01:00
|
|
|
yield return CanViewLightningInvoiceInStore;
|
2020-05-29 02:00:13 +02:00
|
|
|
yield return CanCreateLightningInvoiceInStore;
|
2020-06-24 03:34:09 +02:00
|
|
|
yield return CanManagePullPayments;
|
2023-01-26 01:46:05 +01:00
|
|
|
yield return CanCreatePullPayments;
|
|
|
|
yield return CanCreateNonApprovedPullPayments;
|
2022-05-18 07:59:56 +02:00
|
|
|
yield return CanViewCustodianAccounts;
|
|
|
|
yield return CanManageCustodianAccounts;
|
|
|
|
yield return CanDepositToCustodianAccounts;
|
|
|
|
yield return CanWithdrawFromCustodianAccounts;
|
|
|
|
yield return CanTradeCustodianAccount;
|
2023-02-24 08:19:03 +01:00
|
|
|
yield return CanManageUsers;
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
2020-03-12 14:59:24 +01:00
|
|
|
}
|
2020-03-20 05:41:47 +01:00
|
|
|
public static bool IsValidPolicy(string policy)
|
|
|
|
{
|
|
|
|
return AllPolicies.Any(p => p.Equals(policy, StringComparison.OrdinalIgnoreCase));
|
|
|
|
}
|
2020-03-02 16:50:28 +01:00
|
|
|
|
2020-03-20 05:41:47 +01:00
|
|
|
public static bool IsStorePolicy(string policy)
|
|
|
|
{
|
|
|
|
return policy.StartsWith("btcpay.store", StringComparison.OrdinalIgnoreCase);
|
|
|
|
}
|
2020-06-12 11:26:20 +02:00
|
|
|
public static bool IsStoreModifyPolicy(string policy)
|
|
|
|
{
|
|
|
|
return policy.StartsWith("btcpay.store.canmodify", StringComparison.OrdinalIgnoreCase);
|
|
|
|
}
|
2020-03-23 14:17:17 +01:00
|
|
|
public static bool IsServerPolicy(string policy)
|
|
|
|
{
|
|
|
|
return policy.StartsWith("btcpay.server", StringComparison.OrdinalIgnoreCase);
|
|
|
|
}
|
2022-08-02 07:20:16 +02:00
|
|
|
public static bool IsPluginPolicy(string policy)
|
|
|
|
{
|
|
|
|
return policy.StartsWith("btcpay.plugin", StringComparison.OrdinalIgnoreCase);
|
|
|
|
}
|
2023-03-20 02:46:46 +01:00
|
|
|
public static bool IsUserPolicy(string policy)
|
|
|
|
{
|
|
|
|
return policy.StartsWith("btcpay.user", StringComparison.OrdinalIgnoreCase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class PermissionSet
|
|
|
|
{
|
|
|
|
public PermissionSet() : this(Array.Empty<Permission>())
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
public PermissionSet(Permission[] permissions)
|
|
|
|
{
|
|
|
|
Permissions = permissions;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Permission[] Permissions { get; }
|
|
|
|
|
|
|
|
public bool Contains(Permission requestedPermission)
|
|
|
|
{
|
|
|
|
return Permissions.Any(p => p.Contains(requestedPermission));
|
|
|
|
}
|
|
|
|
public bool Contains(string permission, string store)
|
|
|
|
{
|
|
|
|
if (permission is null)
|
|
|
|
throw new ArgumentNullException(nameof(permission));
|
|
|
|
if (store is null)
|
|
|
|
throw new ArgumentNullException(nameof(store));
|
|
|
|
return Contains(Permission.Create(permission, store));
|
|
|
|
}
|
2020-03-20 05:41:47 +01:00
|
|
|
}
|
|
|
|
public class Permission
|
|
|
|
{
|
2023-01-26 01:46:05 +01:00
|
|
|
static Permission()
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
2023-03-20 02:46:46 +01:00
|
|
|
|
2020-06-07 16:17:48 +02:00
|
|
|
public static Permission Create(string policy, string scope = null)
|
2020-03-19 11:11:15 +01:00
|
|
|
{
|
2020-06-07 16:17:48 +02:00
|
|
|
if (TryCreatePermission(policy, scope, out var r))
|
2020-03-19 11:11:15 +01:00
|
|
|
return r;
|
|
|
|
throw new ArgumentException("Invalid Permission");
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:17:48 +02:00
|
|
|
public static bool TryCreatePermission(string policy, string scope, out Permission permission)
|
2020-03-19 11:11:15 +01:00
|
|
|
{
|
|
|
|
permission = null;
|
|
|
|
if (policy == null)
|
|
|
|
throw new ArgumentNullException(nameof(policy));
|
|
|
|
policy = policy.Trim().ToLowerInvariant();
|
2020-03-20 05:41:47 +01:00
|
|
|
if (!Policies.IsValidPolicy(policy))
|
2020-03-19 11:11:15 +01:00
|
|
|
return false;
|
2023-03-20 02:46:46 +01:00
|
|
|
if (!string.IsNullOrEmpty(scope) && !Policies.IsStorePolicy(policy))
|
2020-03-19 11:11:15 +01:00
|
|
|
return false;
|
2020-06-07 16:17:48 +02:00
|
|
|
permission = new Permission(policy, scope);
|
2020-03-19 11:11:15 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool TryParse(string str, out Permission permission)
|
|
|
|
{
|
|
|
|
permission = null;
|
|
|
|
if (str == null)
|
|
|
|
throw new ArgumentNullException(nameof(str));
|
|
|
|
str = str.Trim();
|
|
|
|
var separator = str.IndexOf(':');
|
|
|
|
if (separator == -1)
|
|
|
|
{
|
|
|
|
str = str.ToLowerInvariant();
|
2020-03-20 05:41:47 +01:00
|
|
|
if (!Policies.IsValidPolicy(str))
|
2020-03-19 11:11:15 +01:00
|
|
|
return false;
|
|
|
|
permission = new Permission(str, null);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var policy = str.Substring(0, separator).ToLowerInvariant();
|
2020-03-20 05:41:47 +01:00
|
|
|
if (!Policies.IsValidPolicy(policy))
|
2020-03-19 11:11:15 +01:00
|
|
|
return false;
|
2020-03-20 05:41:47 +01:00
|
|
|
if (!Policies.IsStorePolicy(policy))
|
2020-03-19 11:11:15 +01:00
|
|
|
return false;
|
|
|
|
var storeId = str.Substring(separator + 1);
|
|
|
|
if (storeId.Length == 0)
|
|
|
|
return false;
|
|
|
|
permission = new Permission(policy, storeId);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:17:48 +02:00
|
|
|
internal Permission(string policy, string scope)
|
2020-03-19 11:11:15 +01:00
|
|
|
{
|
|
|
|
Policy = policy;
|
2020-06-07 16:17:48 +02:00
|
|
|
Scope = scope;
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool Contains(Permission subpermission)
|
|
|
|
{
|
|
|
|
if (subpermission is null)
|
|
|
|
throw new ArgumentNullException(nameof(subpermission));
|
|
|
|
|
|
|
|
if (!ContainsPolicy(subpermission.Policy))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2020-03-20 05:41:47 +01:00
|
|
|
if (!Policies.IsStorePolicy(subpermission.Policy))
|
2020-03-19 11:11:15 +01:00
|
|
|
return true;
|
2023-03-20 02:46:46 +01:00
|
|
|
return Scope == null || subpermission.Scope == Scope;
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public static IEnumerable<Permission> ToPermissions(string[] permissions)
|
|
|
|
{
|
|
|
|
if (permissions == null)
|
|
|
|
throw new ArgumentNullException(nameof(permissions));
|
|
|
|
foreach (var p in permissions)
|
|
|
|
{
|
|
|
|
if (TryParse(p, out var pp))
|
|
|
|
yield return pp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool ContainsPolicy(string subpolicy)
|
|
|
|
{
|
2023-01-26 01:46:05 +01:00
|
|
|
return ContainsPolicy(Policy, subpolicy);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool ContainsPolicy(string policy, string subpolicy)
|
|
|
|
{
|
|
|
|
if (policy == Policies.Unrestricted)
|
2020-03-19 11:11:15 +01:00
|
|
|
return true;
|
2023-01-26 01:46:05 +01:00
|
|
|
if (policy == subpolicy)
|
2020-03-19 11:11:15 +01:00
|
|
|
return true;
|
2023-03-20 02:46:46 +01:00
|
|
|
if (!PolicyMap.TryGetValue(policy, out var subPolicies))
|
|
|
|
return false;
|
2023-01-26 01:46:05 +01:00
|
|
|
return subPolicies.Contains(subpolicy) || subPolicies.Any(s => ContainsPolicy(s, subpolicy));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Dictionary<string, HashSet<string>> PolicyMap = new();
|
|
|
|
|
|
|
|
private static void Init()
|
|
|
|
{
|
|
|
|
PolicyHasChild(Policies.CanModifyStoreSettings,
|
2023-02-24 08:19:03 +01:00
|
|
|
Policies.CanManageCustodianAccounts,
|
|
|
|
Policies.CanManagePullPayments,
|
|
|
|
Policies.CanModifyInvoices,
|
|
|
|
Policies.CanViewStoreSettings,
|
|
|
|
Policies.CanModifyStoreWebhooks,
|
2023-03-20 02:46:46 +01:00
|
|
|
Policies.CanModifyPaymentRequests,
|
|
|
|
Policies.CanUseLightningNodeInStore);
|
2023-02-24 08:19:03 +01:00
|
|
|
|
|
|
|
PolicyHasChild(Policies.CanManageUsers, Policies.CanCreateUser);
|
2023-03-20 02:46:46 +01:00
|
|
|
PolicyHasChild(Policies.CanManagePullPayments, Policies.CanCreatePullPayments);
|
|
|
|
PolicyHasChild(Policies.CanCreatePullPayments, Policies.CanCreateNonApprovedPullPayments);
|
|
|
|
PolicyHasChild(Policies.CanModifyPaymentRequests, Policies.CanViewPaymentRequests);
|
|
|
|
PolicyHasChild(Policies.CanModifyProfile, Policies.CanViewProfile);
|
|
|
|
PolicyHasChild(Policies.CanUseLightningNodeInStore, Policies.CanViewLightningInvoiceInStore, Policies.CanCreateLightningInvoiceInStore);
|
|
|
|
PolicyHasChild(Policies.CanManageNotificationsForUser, Policies.CanViewNotificationsForUser);
|
2023-02-24 08:19:03 +01:00
|
|
|
PolicyHasChild(Policies.CanModifyServerSettings,
|
|
|
|
Policies.CanUseInternalLightningNode,
|
|
|
|
Policies.CanManageUsers);
|
2023-03-20 02:46:46 +01:00
|
|
|
PolicyHasChild(Policies.CanUseInternalLightningNode, Policies.CanCreateLightningInvoiceInternalNode, Policies.CanViewLightningInvoiceInternalNode);
|
|
|
|
PolicyHasChild(Policies.CanManageCustodianAccounts, Policies.CanViewCustodianAccounts);
|
|
|
|
PolicyHasChild(Policies.CanModifyInvoices, Policies.CanViewInvoices, Policies.CanCreateInvoice, Policies.CanCreateLightningInvoiceInStore);
|
|
|
|
PolicyHasChild(Policies.CanViewStoreSettings, Policies.CanViewInvoices, Policies.CanViewPaymentRequests);
|
2023-01-26 01:46:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void PolicyHasChild(string policy, params string[] subPolicies)
|
|
|
|
{
|
|
|
|
if (PolicyMap.TryGetValue(policy, out var existingSubPolicies))
|
2020-06-28 10:55:27 +02:00
|
|
|
{
|
2023-01-26 01:46:05 +01:00
|
|
|
foreach (string subPolicy in subPolicies)
|
|
|
|
{
|
|
|
|
existingSubPolicies.Add(subPolicy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-20 02:46:46 +01:00
|
|
|
PolicyMap.Add(policy, subPolicies.ToHashSet());
|
2020-05-19 19:59:23 +02:00
|
|
|
}
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
|
|
|
|
2020-06-07 16:17:48 +02:00
|
|
|
public string Scope { get; }
|
2020-03-19 11:11:15 +01:00
|
|
|
public string Policy { get; }
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
{
|
2023-03-20 02:46:46 +01:00
|
|
|
return Scope != null ? $"{Policy}:{Scope}" : Policy;
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
{
|
|
|
|
Permission item = obj as Permission;
|
2023-03-20 02:46:46 +01:00
|
|
|
return item != null && ToString().Equals(item.ToString());
|
2020-03-19 11:11:15 +01:00
|
|
|
}
|
|
|
|
public static bool operator ==(Permission a, Permission b)
|
|
|
|
{
|
2023-03-20 02:46:46 +01:00
|
|
|
if (ReferenceEquals(a, b))
|
2020-03-19 11:11:15 +01:00
|
|
|
return true;
|
|
|
|
if (((object)a == null) || ((object)b == null))
|
|
|
|
return false;
|
|
|
|
return a.ToString() == b.ToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator !=(Permission a, Permission b)
|
|
|
|
{
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
{
|
|
|
|
return ToString().GetHashCode();
|
|
|
|
}
|
2020-03-02 16:50:28 +01:00
|
|
|
}
|
|
|
|
}
|