aboutsummaryrefslogtreecommitdiff
path: root/cmnext-cli/src/Commands/AuthnticationCommands.cs
blob: 5e67594756e7bff50b2efb9bd3cc7c37f8c00b40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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"));
                }
            }
        }
    }
}