From c21cd65edbdb50b4856335ca93314bbaa6832c97 Mon Sep 17 00:00:00 2001 From: Saif Aqqad Date: Sat, 28 Jan 2023 11:48:06 +0300 Subject: [PATCH] Add clipboard service + Argument parser --- Arguments.cs | 37 +++++++++++++++++++++++++++++++ Program.cs | 33 ++++++++++++++++++++-------- Utils/Status.cs => Status.cs | 3 ++- SteamAuth.csproj | 7 +++++- Utils/ConsoleWriter.cs | 42 ++++++++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 Arguments.cs rename Utils/Status.cs => Status.cs (93%) create mode 100644 Utils/ConsoleWriter.cs diff --git a/Arguments.cs b/Arguments.cs new file mode 100644 index 0000000..39eb17d --- /dev/null +++ b/Arguments.cs @@ -0,0 +1,37 @@ +using System.ComponentModel; +using Ookii.CommandLine; + +namespace SteamAuth +{ + [ParseOptions( + Mode = ParsingMode.LongShort, + CaseSensitive = false, + ArgumentNameTransform = NameTransform.DashCase, + ValueDescriptionTransform = NameTransform.DashCase + )] + [Description("Generates a steam TOTP code using a provided secret.")] + public class Arguments + { + + [CommandLineArgument(Position = 0, IsRequired = false)] + [Description("Steam TOTP secret")] + public string? Secret { get; set; } + + [CommandLineArgument(IsRequired = false, ShortName = 's')] + [Description("Whether to save the encrypted secret to a config file")] + public bool Save { get; set; } + + internal bool IsInvalid { get; private set; } + + public Arguments() + { + Secret = null; + Save = false; + } + + internal Arguments(bool isInvalid) : this() + { + IsInvalid = isInvalid; + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index 15f5f52..1c01cb9 100644 --- a/Program.cs +++ b/Program.cs @@ -2,6 +2,9 @@ using SteamGuardTotp = SteamGuard.TOTP.SteamGuard; using SteamAuth.Utils; using System.Security.Cryptography; +using TextCopy; +using Ookii.CommandLine; +using Ookii.CommandLine.Terminal; namespace SteamAuth; @@ -10,23 +13,29 @@ class Program const string STEAMGUARD_FILE = "steamauth.json"; private static readonly SteamGuardTotp steamGuard = new(); private static readonly string steamGuardPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, STEAMGUARD_FILE); + private static readonly ConsoleWriter console = new(); - private static int Main(string[] args) + private static int Main() { - var result = args.Length == 0 ? ProcessFile() : ProcessArgs(args); + var args = CommandLineParser.Parse() ?? new(isInvalid: true); + if (args.IsInvalid) + { + return (int)Status.InvalidArguments; + } + + var result = string.IsNullOrWhiteSpace(args.Secret) ? ProcessFile() : ProcessArgs(args); if (result != Status.Success) { - Console.Error.WriteLine(result.GetMessage()); + console.WriteLine(result.GetMessage(), TextFormat.ForegroundRed, TextFormat.BoldBright); } return (int)result; } - private static Status ProcessArgs(string[] args) + private static Status ProcessArgs(Arguments args) { - var secret = args[0]; - var shouldSave = args.Length > 1 && args[1].Contains("-s", StringComparison.InvariantCultureIgnoreCase); + var secret = args.Secret ?? string.Empty; var code = steamGuard.GenerateAuthenticationCode(secret); if (code is null) @@ -34,9 +43,9 @@ private static Status ProcessArgs(string[] args) return Status.TotpGenerationFailure; } - Console.WriteLine(code); + OutputTotpCode(code); - if (shouldSave) + if (args.Save) { var entropy = new byte[20]; RandomNumberGenerator.Fill(entropy); @@ -84,10 +93,16 @@ private static Status ProcessFile() var code = steamGuard.GenerateAuthenticationCode(secret); if (code is not null) { - Console.WriteLine(code); + OutputTotpCode(code); return Status.Success; } return Status.TotpGenerationFailure; } + + private static void OutputTotpCode(string code) + { + console.WriteLine(code, TextFormat.ForegroundGreen, TextFormat.BoldBright); + ClipboardService.SetText(code); + } } \ No newline at end of file diff --git a/Utils/Status.cs b/Status.cs similarity index 93% rename from Utils/Status.cs rename to Status.cs index 1b06d4b..9425529 100644 --- a/Utils/Status.cs +++ b/Status.cs @@ -1,7 +1,8 @@ -namespace SteamAuth.Utils; +namespace SteamAuth; enum Status { Success = 0, + InvalidArguments = -1, PlatformNotSupported = -2, ConfigFileNotFound = -3, EncryptionFailure = -4, diff --git a/SteamAuth.csproj b/SteamAuth.csproj index e06d5b9..d84b662 100644 --- a/SteamAuth.csproj +++ b/SteamAuth.csproj @@ -1,10 +1,12 @@ + 0.0.2 net7.0 SteamAuth enable enable + Nullable @@ -12,11 +14,14 @@ true true true + true + + - + \ No newline at end of file diff --git a/Utils/ConsoleWriter.cs b/Utils/ConsoleWriter.cs new file mode 100644 index 0000000..41dd9c1 --- /dev/null +++ b/Utils/ConsoleWriter.cs @@ -0,0 +1,42 @@ +using Ookii.CommandLine.Terminal; + +namespace SteamAuth.Utils +{ + public class ConsoleWriter : IDisposable + { + private readonly VirtualTerminalSupport virtualTerminal; + private readonly bool _formatSupported = false; + + public ConsoleWriter() + { + virtualTerminal = VirtualTerminal.EnableColor(StandardStream.Output); + _formatSupported = virtualTerminal.IsSupported; + } + + public void Write(string text, params string[] formats) + { + if (_formatSupported) + { + Console.Write(formats); + } + + Console.Write(text); + } + + public void WriteLine(string text, params string[] formats) + { + if (_formatSupported) + { + Console.Write(string.Concat(formats)); + } + + Console.WriteLine(text); + } + + public void Dispose() + { + virtualTerminal.Dispose(); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file