aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Essentials/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Plugins.Essentials/src')
-rw-r--r--lib/Plugins.Essentials/src/Accounts/AccountUtils.cs121
-rw-r--r--lib/Plugins.Essentials/src/Accounts/UserCreationRequest.cs51
-rw-r--r--lib/Plugins.Essentials/src/Extensions/ICookieController.cs54
-rw-r--r--lib/Plugins.Essentials/src/Extensions/SingleCookieController.cs124
-rw-r--r--lib/Plugins.Essentials/src/Users/IUser.cs23
-rw-r--r--lib/Plugins.Essentials/src/Users/IUserCreationRequest.cs61
-rw-r--r--lib/Plugins.Essentials/src/Users/IUserManager.cs79
-rw-r--r--lib/Plugins.Essentials/src/Users/PassValidateFlags.cs45
8 files changed, 415 insertions, 143 deletions
diff --git a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
index a5fb074..396d496 100644
--- a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
+++ b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
@@ -48,7 +48,7 @@ namespace VNLib.Plugins.Essentials.Accounts
{
/// <summary>
- /// The size in bytes of the random passwords generated when invoking the <see cref="SetRandomPasswordAsync(IPasswordHashingProvider, IUserManager, IUser, int)"/>
+ /// The size in bytes of the random passwords generated when invoking the
/// </summary>
public const int RANDOM_PASS_SIZE = 240;
@@ -90,56 +90,37 @@ namespace VNLib.Plugins.Essentials.Accounts
#region Password/User helper extensions
/// <summary>
- /// Generates and sets a random password for the specified user account
+ /// Validates a password associated with the specified user
/// </summary>
- /// <param name="manager">The configured <see cref="IUserManager"/> to process the password update on</param>
- /// <param name="user">The user instance to update the password on</param>
- /// <param name="passHashing">The <see cref="PasswordHashing"/> instance to hash the random password with</param>
- /// <param name="size">Size (in bytes) of the generated random password</param>
- /// <returns>A value indicating the results of the event (number of rows affected, should evaluate to true)</returns>
- /// <exception cref="VnArgon2Exception"></exception>
- /// <exception cref="ArgumentException"></exception>
+ /// <param name="manager"></param>
+ /// <param name="user">The user to validate the password against</param>
+ /// <param name="password">The password to test against the user</param>
+ /// <param name="flags">Validation flags</param>
+ /// <param name="cancellation">A token to cancel the validation</param>
/// <exception cref="ArgumentNullException"></exception>
- public static async Task<ERRNO> SetRandomPasswordAsync(this IPasswordHashingProvider passHashing, IUserManager manager, IUser user, int size = RANDOM_PASS_SIZE)
+ /// <returns>A value greater than 0 if successful, 0 or negative values if a failure occured</returns>
+ public static async Task<ERRNO> ValidatePasswordAsync(this IUserManager manager, IUser user, string password, PassValidateFlags flags, CancellationToken cancellation)
{
_ = manager ?? throw new ArgumentNullException(nameof(manager));
- _ = user ?? throw new ArgumentNullException(nameof(user));
- _ = passHashing ?? throw new ArgumentNullException(nameof(passHashing));
- if (user.IsReleased)
- {
- throw new ObjectDisposedException("The specifed user object has been released");
- }
- //Alloc a buffer
- using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(size);
- //Use the CGN to get a random set
- RandomHash.GetRandomBytes(buffer.Span);
- //Hash the new random password
- using PrivateString passHash = passHashing.Hash(buffer.Span);
- //Write the password to the user account
- return await manager.UpdatePassAsync(user, passHash);
+ using PrivateString ps = new(password, false);
+ return await manager.ValidatePasswordAsync(user, ps, flags, cancellation).ConfigureAwait(false);
}
-
+
/// <summary>
- /// Creates a new user with a random user id and the specified email address and password.
- /// If privileges are left null, the minimum privileges will be set.
+ /// Updates a password associated with the specified user. If the update fails, the transaction
+ /// is rolled back.
/// </summary>
/// <param name="manager"></param>
- /// <param name="emailAddress">The user's email address or secondary id</param>
- /// <param name="password">The user's password</param>
- /// <param name="privileges">Optional user privilage level</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>A task that resolves the new user</returns>
+ /// <param name="user">The user account to update the password of</param>
+ /// <param name="password">The new password to set</param>
/// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="UserExistsException"></exception>
- /// <exception cref="UserCreationFailedException"></exception>
- public static Task<IUser> CreateUserAsync(this IUserManager manager, string emailAddress, PrivateString password, ulong? privileges, CancellationToken cancellation = default)
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>The result of the operation, the result should be 1 (aka true)</returns>
+ public static async Task<ERRNO> UpdatePasswordAsync(this IUserManager manager, IUser user, string password, CancellationToken cancellation = default)
{
_ = manager ?? throw new ArgumentNullException(nameof(manager));
- //Create a random user id
- string randomId = GetRandomUserId();
- //Set the default/minimum privileges
- privileges ??= MINIMUM_LEVEL;
- return manager.CreateUserAsync(randomId, emailAddress, privileges.Value, password, cancellation);
+ using PrivateString ps = new(password, false);
+ return await manager.UpdatePasswordAsync(user, ps, cancellation).ConfigureAwait(false);
}
/// <summary>
@@ -169,14 +150,6 @@ namespace VNLib.Plugins.Essentials.Accounts
public static void SetAccountOrigin(this IUser ud, string origin) => ud[ACC_ORIGIN_ENTRY] = origin;
/// <summary>
- /// Gets a random user-id generated from crypograhic random number
- /// then hashed (SHA1) and returns a hexadecimal string
- /// </summary>
- /// <returns>The random string user-id</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static string GetRandomUserId() => RandomHash.GetRandomHash(HashAlg.SHA1, 64, HashEncodingMode.Hexadecimal);
-
- /// <summary>
/// Generates a cryptographically secure random password, then hashes it
/// and returns the hash of the new password
/// </summary>
@@ -207,58 +180,6 @@ namespace VNLib.Plugins.Essentials.Accounts
}
/// <summary>
- /// Asynchronously verifies the desired user's password. If the user is not found or the password is not found
- /// returns false. Returns true if the user exist's has a valid password hash and matches the supplied password value.
- /// </summary>
- /// <param name="manager"></param>
- /// <param name="userId">The id of the user to check the password against</param>
- /// <param name="rawPassword">The raw password of the user to compare hashes against</param>
- /// <param name="hashing">The password hashing tools</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>A task that completes with the value of the password hashing match.</returns>
- /// <exception cref="ArgumentNullException"></exception>
- public static async Task<bool> VerifyPasswordAsync(this IUserManager manager, string userId, PrivateString rawPassword, IPasswordHashingProvider hashing, CancellationToken cancellation)
- {
- _ = manager ?? throw new ArgumentNullException(nameof(manager));
- _ = userId ?? throw new ArgumentNullException(nameof(userId));
- _ = rawPassword ?? throw new ArgumentNullException(nameof(rawPassword));
- _ = hashing ?? throw new ArgumentNullException(nameof(hashing));
-
- //Get the user, may be null if the user does not exist
- using IUser? user = await manager.GetUserAndPassFromIDAsync(userId, cancellation);
-
- if(user == null)
- {
- return false;
- }
-
- if(user.PassHash == null)
- {
- return false;
- }
-
- return hashing.Verify(user.PassHash.ToReadOnlySpan(), rawPassword.ToReadOnlySpan());
- }
-
- /// <summary>
- /// Verifies the user's raw password against the hashed password using the specified
- /// <see cref="PasswordHashing"/> instance
- /// </summary>
- /// <param name="user"></param>
- /// <param name="rawPassword"></param>
- /// <param name="hashing">The <see cref="IPasswordHashingProvider"/> provider instance</param>
- /// <returns>True if the password </returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool VerifyPassword(this IUser user, PrivateString rawPassword, IPasswordHashingProvider hashing)
- {
- _ = user ?? throw new ArgumentNullException(nameof(user));
- _ = rawPassword ?? throw new ArgumentNullException(nameof(rawPassword));
- _ = hashing ?? throw new ArgumentNullException(nameof(hashing));
-
- return user.PassHash != null && hashing.Verify(user.PassHash.ToReadOnlySpan(), rawPassword.ToReadOnlySpan());
- }
-
- /// <summary>
/// Verifies a password against its previously encoded hash.
/// </summary>
/// <param name="provider"></param>
diff --git a/lib/Plugins.Essentials/src/Accounts/UserCreationRequest.cs b/lib/Plugins.Essentials/src/Accounts/UserCreationRequest.cs
new file mode 100644
index 0000000..e346af1
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Accounts/UserCreationRequest.cs
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: UserCreationRequest.cs
+*
+* UserCreationRequest.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using VNLib.Utils.Memory;
+using VNLib.Plugins.Essentials.Users;
+
+namespace VNLib.Plugins.Essentials.Accounts
+{
+ /// <summary>
+ /// A concrete implementation of <see cref="IUserCreationRequest"/>
+ /// that can be used to create a new user.
+ /// </summary>
+ public class UserCreationRequest : IUserCreationRequest
+ {
+ ///<inheritdoc/>
+ public PrivateString? Password { get; init; }
+
+ ///<inheritdoc/>
+ public ulong Privileges { get; init; } = AccountUtil.MINIMUM_LEVEL;
+
+ ///<inheritdoc/>
+ public string EmailAddress { get; init; } = string.Empty;
+
+ ///<inheritdoc/>
+ public bool UseRawPassword { get; init; }
+
+ ///<inheritdoc/>
+ public UserStatus InitialStatus { get; init; } = UserStatus.Unverified;
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Extensions/ICookieController.cs b/lib/Plugins.Essentials/src/Extensions/ICookieController.cs
new file mode 100644
index 0000000..b88e648
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Extensions/ICookieController.cs
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: ICookieController.cs
+*
+* ICookieController.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Plugins.Essentials.Extensions
+{
+ /// <summary>
+ /// Manges a single cookie for connections
+ /// </summary>
+ public interface ICookieController
+ {
+ /// <summary>
+ /// Sets the cookie value for the given entity
+ /// </summary>
+ /// <param name="entity">The http connection to set the cookie value for</param>
+ /// <param name="value">The cookie value</param>
+ void SetCookie(HttpEntity entity, string value);
+
+ /// <summary>
+ /// Gets the cookie value for the given entity
+ /// </summary>
+ /// <param name="entity">The entity to get the cookie for</param>
+ /// <returns>The cookie value if set, null otherwise</returns>
+ string? GetCookie(HttpEntity entity);
+
+ /// <summary>
+ /// Expires an existing request cookie for the given entity, avoiding
+ /// setting the response cookie unless necessary
+ /// </summary>
+ /// <param name="entity">The http connection to expire the cookie on</param>
+ /// <param name="force">Forcibly set the response cookie regardless of it's existence</param>
+ void ExpireCookie(HttpEntity entity, bool force);
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Extensions/SingleCookieController.cs b/lib/Plugins.Essentials/src/Extensions/SingleCookieController.cs
new file mode 100644
index 0000000..1893b6e
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Extensions/SingleCookieController.cs
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: SingleCookieController.cs
+*
+* SingleCookieController.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Collections.Generic;
+
+using VNLib.Net.Http;
+
+namespace VNLib.Plugins.Essentials.Extensions
+{
+ /// <summary>
+ /// Implements a sinlge cookie controller
+ /// </summary>
+ public class SingleCookieController : ICookieController
+ {
+ private readonly string _cookieName;
+ private readonly TimeSpan _validFor;
+
+ /// <summary>
+ /// Creates a new <see cref="SingleCookieController"/> instance
+ /// </summary>
+ /// <param name="cookieName">The name of the cookie to manage</param>
+ /// <param name="validFor">The max-age cookie value</param>
+ public SingleCookieController(string cookieName, TimeSpan validFor)
+ {
+ _cookieName = cookieName;
+ _validFor = validFor;
+ }
+
+ /// <summary>
+ /// The domain of the cookie
+ /// </summary>
+ public string? Domain { get; init; }
+
+ /// <summary>
+ /// The path of the cookie
+ /// </summary>
+ public string? Path { get; init; }
+
+ /// <summary>
+ /// Whether the cookie is secure
+ /// </summary>
+ public bool Secure { get; init; }
+
+ /// <summary>
+ /// Whether the cookie is HTTP only
+ /// </summary>
+ public bool HttpOnly { get; init; }
+
+ /// <summary>
+ /// The SameSite policy of the cookie
+ /// </summary>
+ public CookieSameSite SameSite { get; init; }
+
+
+ /// <summary>
+ /// Optionally clears the cookie (does not force)
+ /// </summary>
+ /// <param name="entity">The entity to clear the cookie for</param>
+ public void ExpireCookie(HttpEntity entity) => ExpireCookie(entity, false);
+
+ ///<inheritdoc/>
+ public void ExpireCookie(HttpEntity entity, bool force)
+ {
+ _ = entity ?? throw new ArgumentNullException(nameof(entity));
+ SetCookieInternal(entity, string.Empty, force);
+ }
+
+ ///<inheritdoc/>
+ public string? GetCookie(HttpEntity entity)
+ {
+ _ = entity ?? throw new ArgumentNullException(nameof(entity));
+ return entity.Server.RequestCookies.GetValueOrDefault(_cookieName);
+ }
+
+ ///<inheritdoc/>
+ public void SetCookie(HttpEntity entity, string value)
+ {
+ _ = entity ?? throw new ArgumentNullException(nameof(entity));
+ SetCookieInternal(entity, value, true);
+ }
+
+ private void SetCookieInternal(HttpEntity entity, string value, bool force)
+ {
+ //Only set cooke if already exists or force is true
+ if (entity.Server.RequestCookies.ContainsKey(value) || force)
+ {
+ //Build and set cookie
+ HttpCookie cookie = new(_cookieName, value)
+ {
+ Secure = Secure,
+ HttpOnly = HttpOnly,
+ ValidFor = _validFor,
+ SameSite = SameSite,
+ Path = Path,
+ Domain = Domain
+ };
+
+ entity.Server.SetCookie(in cookie);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Users/IUser.cs b/lib/Plugins.Essentials/src/Users/IUser.cs
index a36ba70..315c8c5 100644
--- a/lib/Plugins.Essentials/src/Users/IUser.cs
+++ b/lib/Plugins.Essentials/src/Users/IUser.cs
@@ -27,14 +27,19 @@ using System.Collections.Generic;
using VNLib.Utils;
using VNLib.Utils.Async;
-using VNLib.Utils.Memory;
namespace VNLib.Plugins.Essentials.Users
{
+
/// <summary>
/// Represents an abstract user account
/// </summary>
- public interface IUser : IAsyncExclusiveResource, IDisposable, IObjectStorage, IEnumerable<KeyValuePair<string, string>>, IIndexable<string, string>
+ public interface IUser :
+ IAsyncExclusiveResource,
+ IDisposable,
+ IObjectStorage,
+ IEnumerable<KeyValuePair<string, string>>,
+ IIndexable<string, string>
{
/// <summary>
/// The user's privilege level
@@ -52,9 +57,9 @@ namespace VNLib.Plugins.Essentials.Users
DateTimeOffset Created { get; }
/// <summary>
- /// The user's password hash if retreived from the backing store, otherwise null
+ /// The user's email address
/// </summary>
- PrivateString? PassHash { get; }
+ string EmailAddress { get; set; }
/// <summary>
/// Status of account
@@ -62,16 +67,6 @@ namespace VNLib.Plugins.Essentials.Users
UserStatus Status { get; set; }
/// <summary>
- /// Is the account only usable from local network?
- /// </summary>
- bool LocalOnly { get; set; }
-
- /// <summary>
- /// The user's email address
- /// </summary>
- string EmailAddress { get; set; }
-
- /// <summary>
/// Marks the user for deletion on release
/// </summary>
void Delete();
diff --git a/lib/Plugins.Essentials/src/Users/IUserCreationRequest.cs b/lib/Plugins.Essentials/src/Users/IUserCreationRequest.cs
new file mode 100644
index 0000000..a5b9a30
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Users/IUserCreationRequest.cs
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: IUserCreationRequest.cs
+*
+* IUserCreationRequest.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using VNLib.Utils.Memory;
+
+namespace VNLib.Plugins.Essentials.Users
+{
+ /// <summary>
+ /// A request to create a new user
+ /// </summary>
+ public interface IUserCreationRequest
+ {
+ /// <summary>
+ /// The value to store in the users password field. By default this
+ /// value will be hashed before being stored in the database, unless
+ /// <see cref="UseRawPassword"/> is set to true.
+ /// </summary>
+ PrivateString? Password { get; }
+
+ /// <summary>
+ /// The user's initial privilege level
+ /// </summary>
+ ulong Privileges { get; }
+
+ /// <summary>
+ /// The user's email address
+ /// </summary>
+ string EmailAddress { get; }
+
+ /// <summary>
+ /// Should the password be stored as-is in the database?
+ /// </summary>
+ bool UseRawPassword { get; }
+
+ /// <summary>
+ /// The user's initial status
+ /// </summary>
+ UserStatus InitialStatus { get; }
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Users/IUserManager.cs b/lib/Plugins.Essentials/src/Users/IUserManager.cs
index b731033..400a5d0 100644
--- a/lib/Plugins.Essentials/src/Users/IUserManager.cs
+++ b/lib/Plugins.Essentials/src/Users/IUserManager.cs
@@ -28,15 +28,37 @@ using System.Threading.Tasks;
using VNLib.Utils;
using VNLib.Utils.Memory;
+using VNLib.Plugins.Essentials.Accounts;
namespace VNLib.Plugins.Essentials.Users
{
+
/// <summary>
/// A backing store that provides user accounts
/// </summary>
public interface IUserManager
{
/// <summary>
+ /// Gets the internal password hash provider if one is available
+ /// </summary>
+ /// <returns>The internal hash provider if available, null otherwise</returns>
+ IPasswordHashingProvider? GetHashProvider();
+
+ /// <summary>
+ /// Computes uinuqe user-id that is safe for use in the database.
+ /// </summary>
+ /// <param name="input">The value to convert to a safe user-id</param>
+ /// <returns>The safe-user id</returns>
+ string ComputeSafeUserId(string input);
+
+ /// <summary>
+ /// Gets the number of entries in the current user table
+ /// </summary>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>The number of users in the table, or -1 if the operation failed</returns>
+ Task<long> GetUserCountAsync(CancellationToken cancellation = default);
+
+ /// <summary>
/// Attempts to get a user object without their password from the database asynchronously
/// </summary>
/// <param name="userId">The id of the user</param>
@@ -55,36 +77,42 @@ namespace VNLib.Plugins.Essentials.Users
Task<IUser?> GetUserFromEmailAsync(string emailAddress, CancellationToken cancellationToken = default);
/// <summary>
- /// Attempts to get a user object with their password from the database on the current thread
+ /// Creates a new user account in the store as per the request. The user-id field is optional,
+ /// and if set to null or empty, will be generated automatically by the store.
/// </summary>
- /// <param name="userid">The id of the user</param>
+ /// <param name="userId">An optional user id to force</param>
/// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns>
+ /// <param name="creation">The account email address</param>
+ /// <returns>An object representing a user's account if successful, null otherwise</returns>
+ /// <exception cref="UserExistsException"></exception>
/// <exception cref="ArgumentNullException"></exception>
- Task<IUser?> GetUserAndPassFromIDAsync(string userid, CancellationToken cancellation = default);
+ /// <exception cref="UserCreationFailedException"></exception>
+ Task<IUser> CreateUserAsync(IUserCreationRequest creation, string? userId, CancellationToken cancellation = default);
/// <summary>
- /// Attempts to get a user object with their password from the database asynchronously
+ /// Validates a password associated with the specified user
/// </summary>
- /// <param name="emailAddress">The user's email address</param>
- /// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns>
- /// <exception cref="ArgumentNullException"></exception>
- Task<IUser?> GetUserAndPassFromEmailAsync(string emailAddress, CancellationToken cancellationToken = default);
+ /// <param name="user">The user to validate the password against</param>
+ /// <param name="password">The password to test against the user</param>
+ /// <param name="flags">Validation flags</param>
+ /// <param name="cancellation">A token to cancel the validation</param>
+ /// <returns>A value greater than 0 if successful, 0 or negative values if a failure occured</returns>
+ Task<ERRNO> ValidatePasswordAsync(IUser user, PrivateString password, PassValidateFlags flags, CancellationToken cancellation = default);
/// <summary>
- /// Creates a new user in the current user's table and if successful returns the new user object (without password)
+ /// An operation that will attempt to recover a user's password if possible. Not all user
+ /// managment systems allow recovering passwords for users. This method should return
+ /// null if the operation is not supported.
+ /// <para>
+ /// The returned value will likely not be the user's raw password but instead a hashed
+ /// or encrypted version of the password.
+ /// </para>
/// </summary>
- /// <param name="userid">The user id</param>
- /// <param name="privileges">A number representing the privilage level of the account</param>
- /// <param name="passHash">Value to store in the password field</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <param name="emailAddress">The account email address</param>
- /// <returns>An object representing a user's account if successful, null otherwise</returns>
- /// <exception cref="UserExistsException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="UserCreationFailedException"></exception>
- Task<IUser> CreateUserAsync(string userid, string emailAddress, ulong privileges, PrivateString passHash, CancellationToken cancellation = default);
+ /// <param name="user">The user to recover the password for</param>
+ /// <param name="cancellation">A token to cancel the opertion</param>
+ /// <returns>The password if found</returns>
+ /// <exception cref="NotSupportedException"></exception>
+ Task<PrivateString?> RecoverPasswordAsync(IUser user, CancellationToken cancellation = default);
/// <summary>
/// Updates a password associated with the specified user. If the update fails, the transaction
@@ -94,13 +122,6 @@ namespace VNLib.Plugins.Essentials.Users
/// <param name="newPass">The new password to set</param>
/// <param name="cancellation">A token to cancel the operation</param>
/// <returns>The result of the operation, the result should be 1 (aka true)</returns>
- Task<ERRNO> UpdatePassAsync(IUser user, PrivateString newPass, CancellationToken cancellation = default);
-
- /// <summary>
- /// Gets the number of entries in the current user table
- /// </summary>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>The number of users in the table, or -1 if the operation failed</returns>
- Task<long> GetUserCountAsync(CancellationToken cancellation = default);
+ Task<ERRNO> UpdatePasswordAsync(IUser user, PrivateString newPass, CancellationToken cancellation = default);
}
} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Users/PassValidateFlags.cs b/lib/Plugins.Essentials/src/Users/PassValidateFlags.cs
new file mode 100644
index 0000000..f6ff43a
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Users/PassValidateFlags.cs
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: PassValidateFlags.cs
+*
+* PassValidateFlags.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+
+namespace VNLib.Plugins.Essentials.Users
+{
+ /// <summary>
+ /// Flags for password validation
+ /// </summary>
+ [Flags]
+ public enum PassValidateFlags
+ {
+ /// <summary>
+ /// No flags/default
+ /// </summary>
+ None = 0,
+
+ /// <summary>
+ /// Bypasses hashing of the password if possible
+ /// </summary>
+ BypassHashing = 1,
+ }
+} \ No newline at end of file