From d9935ada9dd83578978ac51c4d7550b491085a69 Mon Sep 17 00:00:00 2001 From: Umar Bolatov Date: Wed, 7 Apr 2021 20:40:57 -0700 Subject: [PATCH] Add "/api/v1/users/me" endpoint --- BTCPayServer.Client/Permissions.cs | 2 +- .../Controllers/GreenField/UsersController.cs | 32 ++++++++++++++++++- .../Controllers/ManageController.APIKeys.cs | 2 +- .../GreenFieldAuthorizationHandler.cs | 1 + .../swagger/v1/swagger.template.users.json | 30 ++++++++++++----- 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/BTCPayServer.Client/Permissions.cs b/BTCPayServer.Client/Permissions.cs index 3e6ad1b46..adc1480f5 100644 --- a/BTCPayServer.Client/Permissions.cs +++ b/BTCPayServer.Client/Permissions.cs @@ -24,7 +24,7 @@ namespace BTCPayServer.Client public const string CanManageNotificationsForUser = "btcpay.user.canmanagenotificationsforuser"; public const string CanViewNotificationsForUser = "btcpay.user.canviewnotificationsforuser"; public const string CanCreateUser = "btcpay.server.cancreateuser"; - public const string CanDeleteUser = "btcpay.server.candeleteuser"; + public const string CanDeleteUser = "btcpay.user.candeleteuser"; public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments"; public const string Unrestricted = "unrestricted"; public static IEnumerable AllPolicies diff --git a/BTCPayServer/Controllers/GreenField/UsersController.cs b/BTCPayServer/Controllers/GreenField/UsersController.cs index e3fa08df7..51fccca01 100644 --- a/BTCPayServer/Controllers/GreenField/UsersController.cs +++ b/BTCPayServer/Controllers/GreenField/UsersController.cs @@ -79,6 +79,21 @@ namespace BTCPayServer.Controllers.GreenField return await FromModel(user); } + [Authorize(Policy = Policies.CanDeleteUser, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpDelete("~/api/v1/users/me")] + public async Task> DeleteCurrentUser() + { + // Don't want to allow the user to delete themselves if they are the only admin + if (await IsUserTheOnlyOneAdmin()) { + return Forbid(AuthenticationSchemes.GreenfieldBasic); + } + + var user = await _userManager.GetUserAsync(User); + await _userService.DeleteUserAndAssociatedData(user); + + return Ok(); + } + [AllowAnonymous] [HttpPost("~/api/v1/users")] public async Task CreateUser(CreateApplicationUserRequest request, CancellationToken cancellationToken = default) @@ -206,7 +221,7 @@ namespace BTCPayServer.Controllers.GreenField } // User shouldn't be deleted if it's the only admin - if ((await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Count == 1) + if (await IsUserTheOnlyOneAdmin(user)) { return Forbid(AuthenticationSchemes.GreenfieldBasic); } @@ -245,5 +260,20 @@ namespace BTCPayServer.Controllers.GreenField Created = data.Created }; } + + private async Task IsUserTheOnlyOneAdmin() + { + return await IsUserTheOnlyOneAdmin(await _userManager.GetUserAsync(User)); + } + + private async Task IsUserTheOnlyOneAdmin(ApplicationUser user) + { + var isUserAdmin = await _userService.IsAdminUser(user); + if (!isUserAdmin) { + return false; + } + + return (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Count == 1; + } } } diff --git a/BTCPayServer/Controllers/ManageController.APIKeys.cs b/BTCPayServer/Controllers/ManageController.APIKeys.cs index d17552663..945ff12b4 100644 --- a/BTCPayServer/Controllers/ManageController.APIKeys.cs +++ b/BTCPayServer/Controllers/ManageController.APIKeys.cs @@ -470,7 +470,7 @@ namespace BTCPayServer.Controllers { {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.")}, - {BTCPayServer.Client.Policies.CanDeleteUser, ("Delete users", "The app will be able to delete users on this server.")}, + {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.")}, {BTCPayServer.Client.Policies.CanModifyStoreSettings, ("Modify your stores", "The app will be able to view, modify, delete and create new invoices on all your stores.")}, {$"{BTCPayServer.Client.Policies.CanModifyStoreSettings}:", ("Manage selected stores", "The app will be able to view, modify, delete and create new invoices on the selected stores.")}, {BTCPayServer.Client.Policies.CanModifyStoreWebhooks, ("Modify stores webhooks", "The app will modify the webhooks of all your stores.")}, diff --git a/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs b/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs index ffb65688f..c545f72dc 100644 --- a/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs +++ b/BTCPayServer/Security/GreenField/GreenFieldAuthorizationHandler.cs @@ -93,6 +93,7 @@ namespace BTCPayServer.Security.GreenField case Policies.CanViewNotificationsForUser: case Policies.CanModifyProfile: case Policies.CanViewProfile: + case Policies.CanDeleteUser: case Policies.Unrestricted: success = context.HasPermission(Permission.Create(policy), requiredUnscoped); break; diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json index d7af9c565..1ecd2586e 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.users.json @@ -28,6 +28,27 @@ "Basic": [] } ] + }, + "delete": { + "tags": [ + "Users" + ], + "summary": "Deletes user profile", + "description": "Deletes user profile and associated user data for user making the request", + "operationId": "Users_DeleteCurrentUser", + "responses": { + "200": { + "description": "User and associated data deleted successfully" + } + }, + "security": [ + { + "API Key": [ + "btcpay.user.candeleteuser" + ], + "Basic": [] + } + ] } }, "/api/v1/users": { @@ -140,14 +161,7 @@ "description": "User with provided ID was not found" } }, - "security": [ - { - "API Key": [ - "btcpay.server.candeleteuser" - ], - "Basic": [] - } - ] + "security": [] } } },