aboutsummaryrefslogtreecommitdiff
path: root/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs')
-rw-r--r--plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs234
1 files changed, 178 insertions, 56 deletions
diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs b/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs
index f61647f..96b56b4 100644
--- a/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs
+++ b/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs
@@ -23,20 +23,21 @@
*/
using System;
-using System.Linq;
-using System.Collections.Generic;
+using System.Text.Json;
using System.ComponentModel.Design;
+using VNLib.Utils;
using VNLib.Utils.Memory;
using VNLib.Utils.Logging;
using VNLib.Plugins.Attributes;
using VNLib.Plugins.Essentials.Users;
using VNLib.Plugins.Essentials.Middleware;
+using VNLib.Plugins.Essentials.Accounts.MFA;
using VNLib.Plugins.Essentials.Accounts.Endpoints;
+using VNLib.Plugins.Essentials.Accounts.SecurityProvider;
using VNLib.Plugins.Extensions.Loading;
using VNLib.Plugins.Extensions.Loading.Users;
using VNLib.Plugins.Extensions.Loading.Routing;
-using VNLib.Plugins.Essentials.Accounts.SecurityProvider;
namespace VNLib.Plugins.Essentials.Accounts
{
@@ -45,6 +46,8 @@ namespace VNLib.Plugins.Essentials.Accounts
public override string PluginName => "Essentials.Accounts";
+ private bool SetupMode => PluginConfig.TryGetProperty("setup_mode", out JsonElement el) && el.GetBoolean();
+
private AccountSecProvider? _securityProvider;
[ServiceConfigurator]
@@ -83,7 +86,7 @@ namespace VNLib.Plugins.Essentials.Accounts
if (this.HasConfigForType<PasswordChangeEndpoint>())
{
this.Route<PasswordChangeEndpoint>();
- }
+ }
if (this.HasConfigForType<MFAEndpoint>())
{
@@ -104,6 +107,11 @@ namespace VNLib.Plugins.Essentials.Accounts
Log.Information("Configuring the account security provider service");
}
+ if (SetupMode)
+ {
+ Log.Warn("Setup mode is enabled, this is not recommended for production use");
+ }
+
//Write loaded to log
Log.Information("Plugin loaded");
}
@@ -118,90 +126,115 @@ namespace VNLib.Plugins.Essentials.Accounts
protected override async void ProcessHostCommand(string cmd)
{
- //Only process commands if the plugin is in debug mode
- if (!this.IsDebug())
+ //Only process commands if the plugin is in setup mode
+ if (!SetupMode)
{
return;
}
try
{
+ //Create argument parser
+ ArgumentList args = new(cmd.Split(' '));
+
IUserManager Users = this.GetOrCreateSingleton<UserManager>();
IPasswordHashingProvider Passwords = this.GetOrCreateSingleton<ManagedPasswordHashing>();
- //get args as a list
- List<string> args = cmd.Split(' ').ToList();
+ string? username = args.GetArgument("-u");
+ string? password = args.GetArgument("-p");
+
if (args.Count < 3)
{
- Log.Warn("No command specified");
+ Log.Warn("Not enough arguments, use the help command to view available commands");
+ return;
}
- switch (args[2].ToLower())
+
+ switch (args[2].ToLower(null))
{
+ case "help":
+ const string help = @"
+
+Command help for {name}
+
+Usage: p {name} <command> [options]
+
+Commands:
+ create -u <username> -p <password> Create a new user
+ reset-password -u <username> -p <password> -l <priv level> Reset a user's password
+ delete -u <username> Delete a user
+ disable-mfa -u <username> Disable a user's MFA configuration
+ enable-totp -u <username> -s <base32 secret> Enable TOTP MFA for a user
+ set-privilege -u <username> -l <priv level> Set a user's privilege level
+ help Display this help message
+";
+ Log.Information(help, PluginName);
+ break;
//Create new user
- case "create":
+ case "create":
{
- int uid = args.IndexOf("-u");
- int pwd = args.IndexOf("-p");
- if (uid < 0 || pwd < 0)
+ if (username == null || password == null)
{
Log.Warn("You are missing required argument values. Format 'create -u <username> -p <password>'");
- return;
+ break;
}
- string username = args[uid + 1].Trim();
- string randomUserId = AccountUtil.GetRandomUserId();
- //Password as privatestring DANGEROUS to refs
- using (PrivateString password = (PrivateString)args[pwd + 1].Trim()!)
+
+ string? privilege = args.GetArgument("-l");
+
+ if(!ulong.TryParse(privilege, out ulong privLevel))
{
- //Hash the password
- using PrivateString passHash = Passwords.Hash(password);
- //Create the user
- using IUser user = await Users.CreateUserAsync(randomUserId, username, AccountUtil.MINIMUM_LEVEL, passHash);
- //Set active flag
- user.Status = UserStatus.Active;
- //Set local account
- user.SetAccountOrigin(AccountUtil.LOCAL_ACCOUNT_ORIGIN);
-
- await user.ReleaseAsync();
+ privLevel = AccountUtil.MINIMUM_LEVEL;
}
- Log.Information("Successfully created user {id}", username);
+ //Hash the password
+ using PrivateString passHash = Passwords.Hash(password);
+ //Create the user
+ using IUser user = await Users.CreateUserAsync(username, passHash, privLevel);
+
+ //Set active flag
+ user.Status = UserStatus.Active;
+ //Set local account
+ user.SetAccountOrigin(AccountUtil.LOCAL_ACCOUNT_ORIGIN);
+
+ await user.ReleaseAsync();
+
+ Log.Information("Successfully created user {id}", username);
}
break;
- case "reset":
+ case "reset-password":
{
- int uid = args.IndexOf("-u");
- int pwd = args.IndexOf("-p");
- if (uid < 0 || pwd < 0)
+ if (username == null || password == null)
{
- Log.Warn("You are missing required argument values. Format 'reset -u <username> -p <password>'");
- return;
+ Log.Warn("You are missing required argument values. Format 'create -u <username> -p <password>'");
+ break;
}
- string username = args[uid + 1].Trim();
- //Password as privatestring DANGEROUS to refs
- using (PrivateString password = (PrivateString)args[pwd + 1].Trim()!)
+
+ //Hash the password
+ using PrivateString passHash = Passwords.Hash(password);
+
+ //Get the user
+ using IUser? user = await Users.GetUserFromEmailAsync(username);
+
+ if(user == null)
{
- //Hash the password
- using PrivateString passHash = Passwords.Hash(password);
- //Get the user
- using IUser? user = await Users.GetUserFromEmailAsync(username);
-
- if(user == null)
- {
- Log.Warn("The specified user does not exist");
- break;
- }
-
- //Set the password
- await Users.UpdatePassAsync(user, passHash);
+ Log.Warn("The specified user does not exist");
+ break;
}
+
+ //Set the password
+ await Users.UpdatePassAsync(user, passHash);
+
Log.Information("Successfully reset password for {id}", username);
}
break;
case "delete":
{
- //get user-id
- string userId = args[3].Trim();
+ if(username == null)
+ {
+ Log.Warn("You are missing required argument values. Format 'delete -u <username>'");
+ break;
+ }
+
//Get user
- using IUser? user = await Users.GetUserFromEmailAsync(userId);
+ using IUser? user = await Users.GetUserFromEmailAsync(username);
if (user == null)
{
@@ -213,10 +246,99 @@ namespace VNLib.Plugins.Essentials.Accounts
user.Delete();
//Release user
await user.ReleaseAsync();
+
+ Log.Information("Successfully deleted user {id}", username);
+ }
+ break;
+ case "disable-mfa":
+ {
+ if (username == null)
+ {
+ Log.Warn("You are missing required argument values. Format 'disable-mfa -u <username>'");
+ break;
+ }
+
+ //Get user
+ using IUser? user = await Users.GetUserFromEmailAsync(username);
+
+ if (user == null)
+ {
+ Log.Warn("The specified user does not exist");
+ break;
+ }
+
+ user.MFADisable();
+ await user.ReleaseAsync();
+
+ Log.Information("Successfully disabled MFA for {id}", username);
+ }
+ break;
+ case "enable-totp":
+ {
+ string? secret = args.GetArgument("-s");
+
+ if (username == null || secret == null)
+ {
+ Log.Warn("You are missing required argument values. Format 'enable-totp -u <username> -s <secret>'");
+ break;
+ }
+
+ //Get user
+ using IUser? user = await Users.GetUserFromEmailAsync(username);
+
+ if (user == null)
+ {
+ Log.Warn("The specified user does not exist");
+ break;
+ }
+
+ try
+ {
+ byte[] sec = VnEncoding.FromBase32String(secret) ?? throw new Exception("");
+ }
+ catch
+ {
+ Log.Error("Your TOTP secret is not valid base32");
+ break;
+ }
+
+ //Update the totp secret and flush changes
+ user.MFASetTOTPSecret(secret);
+ await user.ReleaseAsync();
+
+ Log.Information("Successfully set TOTP secret for {id}", username);
+ }
+ break;
+ case "set-privilege":
+ {
+ if (username == null)
+ {
+ Log.Warn("You are missing required argument values. Format 'set-privilege -u <username> -l <privilege level>'");
+ break;
+ }
+
+ string? privilege = args.GetArgument("-l");
+ if (!ulong.TryParse(privilege, out ulong privLevel))
+ {
+ Log.Warn("You are missing required argument values. Format 'set-privilege -u <username> -l <privilege level>'");
+ break;
+ }
+
+ //Get user
+ using IUser? user = await Users.GetUserFromEmailAsync(username);
+ if (user == null)
+ {
+ Log.Warn("The specified user does not exist");
+ break;
+ }
+
+ user.Privileges = privLevel;
+ await user.ReleaseAsync();
+ Log.Information("Successfully set privilege level for {id}", username);
}
break;
default:
- Log.Warn("Uknown command");
+ Log.Warn("Uknown command, use the help command");
break;
}
}