aboutsummaryrefslogtreecommitdiff
path: root/cmnext-cli/src/Commands/AuthnticationCommands.cs
diff options
context:
space:
mode:
Diffstat (limited to 'cmnext-cli/src/Commands/AuthnticationCommands.cs')
-rw-r--r--cmnext-cli/src/Commands/AuthnticationCommands.cs166
1 files changed, 166 insertions, 0 deletions
diff --git a/cmnext-cli/src/Commands/AuthnticationCommands.cs b/cmnext-cli/src/Commands/AuthnticationCommands.cs
new file mode 100644
index 0000000..5e67594
--- /dev/null
+++ b/cmnext-cli/src/Commands/AuthnticationCommands.cs
@@ -0,0 +1,166 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Package: CMNext.Cli
+* File: Program.cs
+*
+* CMNext.Cli is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* CMNext.Cli 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
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CMNext.Cli. If not, see http://www.gnu.org/licenses/.
+*/
+
+using CMNext.Cli.Security;
+using CMNext.Cli.Site;
+
+using System;
+using System.Security.Authentication;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Typin.Attributes;
+using Typin.Console;
+using Typin.Exceptions;
+
+
+namespace CMNext.Cli.Commands
+{
+ public sealed class AuthnticationCommands
+ {
+
+ [Command("auth", Description = "Manages your local authentication data")]
+ public sealed class AuthCommand : BaseCommand
+ { }
+
+ [Command("auth login", Description = "Authenticates this client against your CMNext server")]
+ public sealed class AuthLoginCommand(SiteManager siteManager, VauthRunner vauth, ConsoleLogProvider logger) : BaseCommand
+ {
+ [CommandOption("stdin", 's', Description = "Reads the token from stdin instead of using vauth")]
+ public bool FromStdin { get; set; }
+
+ [CommandOption("force", 'f', Description = "Forces a login even if you already have a valid authorization")]
+ public bool Force { get; set; }
+
+ ///<inheritdoc/>
+ public override async ValueTask ExecuteAsync(IConsole console)
+ {
+ logger.SetVerbose(Verbose);
+
+ //global cancel
+ CancellationToken cancellation = console.GetCancellationToken();
+
+ IPkiCredential token;
+
+ //See if current auth is valid
+ if(await siteManager.HasValidAuth())
+ {
+ if (!Force)
+ {
+ console.WithForegroundColor(ConsoleColor.Green, c => c.Output.WriteLine("You already have a valid authorization!"));
+ return;
+ }
+ }
+
+ if (FromStdin)
+ {
+ console.Output.WriteLine("Please enter your PKI token:");
+
+ //Read the token in from stdin
+ string? otp = await console.Input.ReadLineAsync(cancellation);
+
+ if (string.IsNullOrWhiteSpace(otp))
+ {
+ throw new CommandException("You must enter a one time login token to continue");
+ }
+
+ token = new PkiToken(otp);
+ }
+ else
+ {
+ console.Output.WriteLine("Getting token from vauth");
+ //Get the token from vauth
+ token = await vauth.GetOptTokenAsync();
+ }
+
+
+ console.Output.WriteLine("Logging in...");
+
+ try
+ {
+ await siteManager.AuthenticateAsync(token);
+ console.WithForegroundColor(ConsoleColor.Green, c => c.Output.WriteLine("Login successful!"));
+ }
+ catch (AuthenticationException ae)
+ {
+ console.WithForegroundColor(ConsoleColor.Red, c => c.Output.WriteLine($"Authentication failed: {ae.Message}"));
+ }
+ finally
+ {
+ await siteManager.SaveStateAsync();
+ }
+ }
+
+ sealed record class PkiToken(string Token) : IPkiCredential
+ {
+ public string GetToken() => Token;
+ }
+ }
+
+ [Command("auth logout", Description = "Destroys any local previous login state")]
+ public sealed class AuthLogoutCommand(SiteManager siteManager, ConsoleLogProvider logger) : BaseCommand
+ {
+ ///<inheritdoc/>
+ public override async ValueTask ExecuteAsync(IConsole console)
+ {
+ logger.SetVerbose(Verbose);
+
+ console.Output.WriteLine("Logging out...");
+
+ try
+ {
+ //See if current auth is valid
+ await siteManager.LogoutAsync();
+ console.WithForegroundColor(ConsoleColor.Green, c => c.Output.WriteLine("Logout successful!"));
+ }
+ finally
+ {
+ await siteManager.SaveStateAsync();
+ }
+ }
+
+ sealed record class PkiToken(string Token) : IPkiCredential
+ {
+ public string GetToken() => Token;
+ }
+ }
+
+ [Command("auth status", Description = "Gets you client's current authorization status")]
+ public sealed class AuthStatusCommand(SiteManager siteManager) : BaseCommand
+ {
+ public override async ValueTask ExecuteAsync(IConsole console)
+ {
+ //global cancel
+ CancellationToken cancellation = console.GetCancellationToken();
+
+ console.Output.WriteLine("Checking login status...");
+
+ if (await siteManager.HasValidAuth())
+ {
+ console.WithForegroundColor(ConsoleColor.Green, c => c.Output.WriteLine("You have a valid authorization"));
+ }
+ else
+ {
+ console.WithForegroundColor(ConsoleColor.Red, c => c.Output.WriteLine("You do not have a valid authorization"));
+ }
+ }
+ }
+ }
+} \ No newline at end of file