/*
* 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; }
///
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
{
///
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"));
}
}
}
}
}