Skip to content

Commit 783336d

Browse files
committed
Add configuration
1 parent 65c018f commit 783336d

File tree

4 files changed

+126
-16
lines changed

4 files changed

+126
-16
lines changed

src/EasySign.Cli/Program.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ private static int Main(string[] args)
3030
Microsoft.Extensions.Logging.ILogger commandProviderLogger = new SerilogLoggerFactory(Log.Logger.ForContext("Context", "CommandProvider"))
3131
.CreateLogger("CommandProvider");
3232

33-
RootCommand root = new BundleCommandProvider(AppDirectory, commandProviderLogger, bundleLogger).GetRootCommand();
34-
int exitCode = root.Invoke(args);
35-
33+
int exitCode;
34+
using (var cp = new BundleCommandProvider(AppDirectory, commandProviderLogger, bundleLogger))
35+
{
36+
RootCommand root = cp.GetRootCommand();
37+
exitCode = root.Invoke(args);
38+
}
39+
3640
appLogger.Information("Shutting down EasySign CLI at {DateTime} with exit code {ExitCode}", DateTime.Now, exitCode);
3741

3842
Log.CloseAndFlush();

src/EasySign.CommandLine/BundleWorker.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66

77
namespace SAPTeam.EasySign.CommandLine
88
{
9-
public abstract partial class CommandProvider<T>
10-
where T : Bundle
9+
public abstract partial class CommandProvider<TBundle>
1110
{
1211
/// <summary>
1312
/// Gets or sets the bundle.
1413
/// </summary>
15-
public T? Bundle { get; protected set; }
14+
public TBundle? Bundle { get; protected set; }
1615

1716
/// <summary>
1817
/// Initializes the bundle.

src/EasySign.CommandLine/CommandProvider.cs

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System.CommandLine;
22
using System.Security.Cryptography.X509Certificates;
3+
using System.Text;
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
36

47
using Microsoft.Extensions.Logging;
58
using Microsoft.Extensions.Logging.Abstractions;
@@ -11,8 +14,9 @@ namespace SAPTeam.EasySign.CommandLine
1114
/// <summary>
1215
/// Provides command definitions and handlers for the EasySign command line interface.
1316
/// </summary>
14-
/// <typeparam name="T">The type of the bundle.</typeparam>
15-
public abstract partial class CommandProvider<T>
17+
/// <typeparam name="TBundle">The type of the bundle.</typeparam>
18+
public abstract partial class CommandProvider<TBundle> : IDisposable
19+
where TBundle : Bundle
1620
{
1721
/// <summary>
1822
/// Gets or sets the logger to use for logging.
@@ -24,6 +28,11 @@ public abstract partial class CommandProvider<T>
2428
/// </summary>
2529
public string AppDirectory { get; set; }
2630

31+
/// <summary>
32+
/// Gets the application configurations.
33+
/// </summary>
34+
public Configuration Configuration { get; }
35+
2736
/// <summary>
2837
/// Initializes a new instance of the <see cref="CommandProvider{T}"/> class with the specified application directory and logger.
2938
/// </summary>
@@ -37,6 +46,17 @@ public abstract partial class CommandProvider<T>
3746
protected CommandProvider(string appDirectory, ILogger? logger)
3847
{
3948
AppDirectory = appDirectory ?? throw new ArgumentNullException(nameof(appDirectory));
49+
50+
if (File.Exists(Path.Combine(AppDirectory, "config.json")))
51+
{
52+
using var fs = File.OpenRead(Path.Combine(AppDirectory, "config.json"));
53+
Configuration = JsonSerializer.Deserialize(fs, typeof(Configuration), SourceGenerationConfigurationContext.Default) as Configuration ?? new();
54+
}
55+
else
56+
{
57+
Configuration = new();
58+
}
59+
4060
Logger = logger ?? NullLogger.Instance;
4161
}
4262

@@ -66,11 +86,11 @@ public Command Add
6686
continueOpt.AddAlias("-c");
6787

6888
Command command = new Command("add", "Create new bundle or update an existing one")
69-
{
70-
BundlePath,
71-
replaceOpt,
72-
continueOpt,
73-
};
89+
{
90+
BundlePath,
91+
replaceOpt,
92+
continueOpt,
93+
};
7494

7595
command.SetHandler((bundlePath, replace, continueOnError) =>
7696
{
@@ -121,10 +141,46 @@ public Command Sign
121141
return;
122142
}
123143

124-
var subject = CertificateUtilities.GetSubjectNameFromUser();
125-
var issuedCert = CertificateUtilities.IssueCertificate(subject, rootCA);
144+
string? selectedCert = null;
145+
if (Configuration.IssuedCertificates.Count > 0)
146+
{
147+
selectedCert = AnsiConsole.Prompt<string>(
148+
new SelectionPrompt<string>()
149+
.PageSize(10)
150+
.Title("Select Self-Signing Certificate")
151+
.MoreChoicesText("[grey](Move up and down to see more certificates)[/]")
152+
.AddChoices(Configuration.IssuedCertificates.Keys)
153+
.AddChoices("Issue New Certificate"));
154+
}
155+
156+
if (string.IsNullOrEmpty(selectedCert) || selectedCert == "Issue New Certificate")
157+
{
158+
var subject = CertificateUtilities.GetSubjectNameFromUser();
159+
var issuedCert = CertificateUtilities.IssueCertificate(subject, rootCA);
160+
161+
var certFileName = $"{issuedCert.GetNameInfo(X509NameType.SimpleName, false).Replace(" ", "_")}-{issuedCert.GetSerialNumberString()[^6]}.pfx";
162+
var certFilePath = Path.Combine(AppDirectory, "certs", certFileName);
126163

127-
certs = new X509Certificate2Collection(issuedCert);
164+
Directory.CreateDirectory(Path.Combine(AppDirectory, "certs"));
165+
166+
using (var fs = File.Create(certFilePath))
167+
{
168+
fs.Write(issuedCert.Export(X509ContentType.Pfx));
169+
}
170+
171+
Configuration.IssuedCertificates.Add(subject, certFileName);
172+
certs = new X509Certificate2Collection(issuedCert);
173+
}
174+
else
175+
{
176+
certs = [];
177+
var certFilePath = Path.Combine(AppDirectory, "certs", Configuration.IssuedCertificates[selectedCert]);
178+
#if NET9_0_OR_GREATER
179+
certs.AddRange(X509CertificateLoader.LoadPkcs12CollectionFromFile(certFilePath, null, X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable));
180+
#else
181+
certs.Import(certFilePath, null, X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable);
182+
#endif
183+
}
128184
}
129185
else
130186
{
@@ -286,5 +342,29 @@ public Command SelfSign
286342

287343
return null;
288344
}
345+
346+
/// <summary>
347+
/// Writes the configuration to disk.
348+
/// </summary>
349+
public void WriteConfig()
350+
{
351+
string json = JsonSerializer.Serialize(Configuration, typeof(Configuration), SourceGenerationConfigurationContext.Default);
352+
var buffer = Encoding.UTF8.GetBytes(json);
353+
354+
using (FileStream fs = File.OpenWrite(Path.Combine(AppDirectory, "config.json")))
355+
{
356+
fs.Write(buffer);
357+
}
358+
}
359+
360+
/// <inheritdoc/>
361+
public void Dispose()
362+
{
363+
WriteConfig();
364+
365+
Bundle = null;
366+
367+
GC.SuppressFinalize(this);
368+
}
289369
}
290370
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Text.Json.Serialization;
6+
using System.Threading.Tasks;
7+
8+
namespace SAPTeam.EasySign.CommandLine
9+
{
10+
/// <summary>
11+
/// Represents the configuration for the easysign command line tool.
12+
/// </summary>
13+
public class Configuration
14+
{
15+
/// <summary>
16+
/// Gets or sets the list of issued certificates by the self signing root CA.
17+
/// </summary>
18+
public Dictionary<string, string> IssuedCertificates { get; set; } = [];
19+
}
20+
21+
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata, WriteIndented = true, DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)]
22+
[JsonSerializable(typeof(Configuration))]
23+
internal partial class SourceGenerationConfigurationContext : JsonSerializerContext
24+
{
25+
26+
}
27+
}

0 commit comments

Comments
 (0)