aboutsummaryrefslogtreecommitdiff
path: root/VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs
diff options
context:
space:
mode:
authorLibravatar vman <public@vaughnnugent.com>2022-11-18 16:08:51 -0500
committerLibravatar vman <public@vaughnnugent.com>2022-11-18 16:08:51 -0500
commit526c2364b9ad685d1c000fc8a168bf1305aaa8b7 (patch)
treea2bc01607320a6a75e1a869d5bd34e79fd63c595 /VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs
parent2080400119be00bdc354f3121d84ec2f89606ac7 (diff)
Add project files.
Diffstat (limited to 'VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs')
-rw-r--r--VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs116
1 files changed, 116 insertions, 0 deletions
diff --git a/VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs b/VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs
new file mode 100644
index 0000000..81bba51
--- /dev/null
+++ b/VNLib.Plugins.Essentials.Accounts/Endpoints/PasswordResetEndpoint.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Net;
+using System.Text.Json;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+using FluentValidation;
+
+using VNLib.Utils.Memory;
+using VNLib.Utils.Extensions;
+using VNLib.Plugins.Essentials.Users;
+using VNLib.Plugins.Essentials.Extensions;
+using VNLib.Plugins.Extensions.Validation;
+using VNLib.Plugins.Extensions.Loading;
+using VNLib.Plugins.Extensions.Loading.Users;
+using VNLib.Plugins.Essentials.Endpoints;
+
+namespace VNLib.Plugins.Essentials.Accounts.Endpoints
+{
+
+ /// <summary>
+ /// Password reset for user's that are logged in and know
+ /// their passwords to reset their MFA methods
+ /// </summary>
+ [ConfigurationName("password_endpoint")]
+ internal sealed class PasswordChangeEndpoint : ProtectedWebEndpoint
+ {
+ private readonly IUserManager Users;
+ private readonly PasswordHashing Passwords;
+
+ public PasswordChangeEndpoint(PluginBase pbase, IReadOnlyDictionary<string, JsonElement> config)
+ {
+ string? path = config["path"].GetString();
+ InitPathAndLog(path, pbase.Log);
+
+ Users = pbase.GetUserManager();
+ Passwords = pbase.GetPasswords();
+ }
+
+ protected override async ValueTask<VfReturnType> PostAsync(HttpEntity entity)
+ {
+ ValErrWebMessage webm = new();
+ //get the request body
+ using JsonDocument? request = await entity.GetJsonFromFileAsync();
+ if (request == null)
+ {
+ webm.Result = "No request specified";
+ entity.CloseResponseJson(HttpStatusCode.BadRequest, webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //get the user's old password
+ using PrivateString? currentPass = (PrivateString?)request.RootElement.GetPropString("current");
+ //Get password as a private string
+ using PrivateString? newPass = (PrivateString?)request.RootElement.GetPropString("new_password");
+ if (PrivateString.IsNullOrEmpty(currentPass))
+ {
+ webm.Result = "You must specifiy your current password.";
+ entity.CloseResponseJson(HttpStatusCode.UnprocessableEntity, webm);
+ return VfReturnType.VirtualSkip;
+ }
+ if (PrivateString.IsNullOrEmpty(newPass))
+ {
+ webm.Result = "You must specifiy a new password.";
+ entity.CloseResponseJson(HttpStatusCode.UnprocessableEntity, webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //Test the password against minimum
+ if (!AccountValidations.PasswordValidator.Validate((string)newPass, webm))
+ {
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ if (webm.Assert(!currentPass.Equals(newPass), "Passwords cannot be the same."))
+ {
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //get the user's entry in the table
+ using IUser? user = await Users.GetUserAndPassFromIDAsync(entity.Session.UserID);
+ if(webm.Assert(user != null, "An error has occured, please log-out and try again"))
+ {
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //Make sure the account's origin is a local profile
+ if (webm.Assert(user.IsLocalAccount(), "External accounts cannot be modified"))
+ {
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //Verify the user's old password
+ if (!Passwords.Verify(user.PassHash, currentPass))
+ {
+ webm.Result = "Please check your current password";
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ //Hash the user's new password
+ using PrivateString newPassHash = Passwords.Hash(newPass);
+ //Update the user's password
+ if (!await Users.UpdatePassAsync(user, newPassHash))
+ {
+ //error
+ webm.Result = "Your password could not be updated";
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ await user.ReleaseAsync();
+ //delete the user's MFA entry so they can re-enable it
+ webm.Result = "Your password has been updated";
+ webm.Success = true;
+ entity.CloseResponse(webm);
+ return VfReturnType.VirtualSkip;
+ }
+ }
+}