Skip to content

Commit

Permalink
Merge pull request #2362 from win-acme/2.2.4
Browse files Browse the repository at this point in the history
2.2.4
  • Loading branch information
WouterTinus committed Apr 20, 2023
2 parents 0ef4d70 + 8861692 commit 46e9aa5
Show file tree
Hide file tree
Showing 20 changed files with 378 additions and 29 deletions.
3 changes: 2 additions & 1 deletion appveyor.yml
@@ -1,4 +1,4 @@
version: 2.2.3.{build}
version: 2.2.4.{build}
image: Visual Studio 2022
platform: Any CPU
shallow_clone: true
Expand Down Expand Up @@ -41,6 +41,7 @@ build_script:
- cmd: dotnet publish ./src/plugin.validation.dns.linode/wacs.validation.dns.linode.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.luadns/wacs.validation.dns.luadns.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.ns1/wacs.validation.dns.ns1.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.rfc2136/wacs.validation.dns.rfc2136.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.route53/wacs.validation.dns.route53.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.simply/wacs.validation.dns.simply.csproj -c Release
- cmd: dotnet publish ./src/plugin.validation.dns.transip/wacs.validation.dns.transip.csproj -c Release
Expand Down
1 change: 1 addition & 0 deletions build/build.ps1
Expand Up @@ -48,6 +48,7 @@ foreach ($release in @("Release", "ReleaseTrimmed")) {
& dotnet publish $RepoRoot\src\plugin.validation.dns.linode\wacs.validation.dns.linode.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.luadns\wacs.validation.dns.luadns.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.ns1\wacs.validation.dns.ns1.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.rfc2136\wacs.validation.dns.rfc2136.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.route53\wacs.validation.dns.route53.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.simply\wacs.validation.dns.simply.csproj -c "Release"
& dotnet publish $RepoRoot\src\plugin.validation.dns.transip\wacs.validation.dns.transip.csproj -c "Release"
Expand Down
4 changes: 4 additions & 0 deletions build/create-artifacts.ps1
Expand Up @@ -181,6 +181,10 @@ PluginRelease plugin.validation.dns.luadns @(
PluginRelease plugin.validation.dns.ns1 @(
"PKISharp.WACS.Plugins.ValidationPlugins.NS1.dll"
)
PluginRelease plugin.validation.dns.rfc2136 @(
"ARSoft.Tools.Net.dll",
"PKISharp.WACS.Plugins.ValidationPlugins.Rfc2136.dll"
)
PluginRelease plugin.validation.dns.route53 @(
"AWSSDK.Core.dll",
"AWSSDK.Route53.dll",
Expand Down
9 changes: 4 additions & 5 deletions src/main.lib/DomainObjects/CertificateInfo.cs
Expand Up @@ -50,12 +50,11 @@ public CertificateInfo(X509Certificate2Collection rawCollection)
// Check if we have the private key
if (main.HasPrivateKey)
{
var bytes = rawCollection.Export(X509ContentType.Pfx);
if (bytes == null)
{
var bytes = rawCollection.Export(X509ContentType.Pfx) ??
throw new InvalidOperationException();
}
var store = new Pkcs12Store(new MemoryStream(bytes), "".ToCharArray());
var builder = new Pkcs12StoreBuilder();
var store = builder.Build();
store.Load(new MemoryStream(bytes), "".ToCharArray());
var alias = store.Aliases.OfType<string>().FirstOrDefault(store.IsKeyEntry);
if (alias != null)
{
Expand Down
5 changes: 2 additions & 3 deletions src/main.lib/Plugins/CsrPlugins/CsrPlugin.cs
Expand Up @@ -15,7 +15,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Target = PKISharp.WACS.DomainObjects.Target;
using X509Extension = Org.BouncyCastle.Asn1.X509.X509Extension;
Expand Down Expand Up @@ -224,11 +223,11 @@ private X509Name CommonName(Identifier? commonName, List<Identifier> identifiers
}
}
var finalCommonName = commonName ?? identifiers.FirstOrDefault();
IDictionary attrs = new Hashtable
var attrs = new Dictionary<DerObjectIdentifier, string?>
{
[X509Name.CN] = finalCommonName?.Value
};
IList ord = new ArrayList
var ord = new List<DerObjectIdentifier>
{
X509Name.CN
};
Expand Down
7 changes: 5 additions & 2 deletions src/main.lib/Plugins/StorePlugins/PfxFile/PfxFile.cs
Expand Up @@ -76,8 +76,11 @@ internal class PfxFile : IStorePlugin
};
collection.AddRange(input.Chain.ToArray());
var ms = new MemoryStream(collection.Export(X509ContentType.Pfx)!);
var bcPfxIn = new Bc.Pkcs.Pkcs12Store(ms, Array.Empty<char>());
var bcPfxOut = new Bc.Pkcs.Pkcs12Store();
var bcPfxBuilder = new Bc.Pkcs.Pkcs12StoreBuilder();
var bcPfxIn = bcPfxBuilder.Build();
bcPfxIn.Load(ms, Array.Empty<char>());
var bcPfxOut = bcPfxBuilder.Build();

var aliases = bcPfxIn.Aliases.OfType<string>().ToList();
var keyAlias = aliases.FirstOrDefault(a => bcPfxIn.IsKeyEntry(a));
if (keyAlias != null)
Expand Down
2 changes: 2 additions & 0 deletions src/main.lib/Plugins/TargetPlugins/IIS/IISOptions.cs
Expand Up @@ -2,6 +2,7 @@
using PKISharp.WACS.Services;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;

namespace PKISharp.WACS.Plugins.TargetPlugins
{
Expand All @@ -20,6 +21,7 @@ internal class IISOptions : TargetPluginOptions
/// <summary>
/// Regular expression to select hosts
/// </summary>
[JsonConverter(typeof(IISOptionsRegexConverter))]
public string? IncludeRegex { get; set; }

/// <summary>
Expand Down
38 changes: 38 additions & 0 deletions src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsRegexConverter.cs
@@ -0,0 +1,38 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace PKISharp.WACS.Plugins.TargetPlugins
{
internal class IISOptionsRegexConverter : JsonConverter<string>
{
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var ret = default(string?);
if (reader.TokenType == JsonTokenType.StartObject)
{
while (reader.TokenType != JsonTokenType.EndObject)
{
if (reader.TokenType == JsonTokenType.PropertyName)
{
var propertyName = reader.GetString();
if (propertyName == "Pattern")
{
reader.Read();
ret = reader.GetString();
}
}
reader.Read();
}
}
else if (reader.TokenType == JsonTokenType.String)
{
ret = reader.GetString();
}
return ret;
}

public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
writer.WriteStringValue(value);
}
}
48 changes: 34 additions & 14 deletions src/main.lib/RenewalManager.cs
Expand Up @@ -18,6 +18,25 @@

namespace PKISharp.WACS
{

public enum Shortcuts
{
A, // List all selected
C, // Cancel
D, // Show details
E, // Edit
F, // Filter
L, // Show command line
O, // Sort
Q, // Quit
R, // Run
S, // Run force
T, // Run force, no cache
U, // Analyze
V, // Revoke
X, // Reset filter and sort
}

internal class RenewalManager
{
private readonly IInputService _input;
Expand All @@ -36,6 +55,7 @@ internal class RenewalManager
private readonly DueDateStaticService _dueDate;
private readonly AccountManager _accountManager;


public RenewalManager(
ArgumentsParser arguments, MainArguments args,
IRenewalStore renewalStore, ISharingLifetimeScope container,
Expand Down Expand Up @@ -132,29 +152,29 @@ internal async Task ManageRenewals()
options.Add(
Choice.Create<Func<Task>>(
() => { displayAll = true; return Task.CompletedTask; },
"List all selected renewals", "A"));
"List all selected renewals", Shortcuts.A.ToString()));
}
options.Add(
Choice.Create<Func<Task>>(
async () => { quit = true; await EditRenewal(selectedRenewals.First()); },
"Edit renewal", "E", state: editState));
"Edit renewal", Shortcuts.E.ToString(), state: editState));
if (selectedRenewals.Count() > 1)
{
options.Add(
Choice.Create<Func<Task>>(
async () => selectedRenewals = await FilterRenewalsMenu(selectedRenewals),
all ? "Apply filter" : "Apply additional filter", "I", state: sortFilterState));
all ? "Apply filter" : "Apply additional filter", Shortcuts.F.ToString(), state: sortFilterState));
options.Add(
Choice.Create<Func<Task>>(
async () => selectedRenewals = await SortRenewalsMenu(selectedRenewals),
"Sort renewals", "S", state: sortFilterState));
"Sort renewals", Shortcuts.O.ToString(), state: sortFilterState));
}
if (!all)
{
options.Add(
Choice.Create<Func<Task>>(
() => { selectedRenewals = originalSelection; return Task.CompletedTask; },
"Reset sorting and filtering", "X"));
"Reset sorting and filtering", Shortcuts.X.ToString()));
}
options.Add(
Choice.Create<Func<Task>>(
Expand All @@ -181,7 +201,7 @@ internal async Task ManageRenewals()
}
},
$"Show details for {selectionLabel}", "D",
$"Show details for {selectionLabel}", Shortcuts.D.ToString(),
state: noneState));
options.Add(
Choice.Create<Func<Task>>(
Expand All @@ -193,24 +213,24 @@ internal async Task ManageRenewals()
}
await _input.Wait();
},
$"Show command line for {selectionLabel}", "L",
$"Show command line for {selectionLabel}", Shortcuts.L.ToString(),
state: noneState));
options.Add(
Choice.Create<Func<Task>>(() => Run(selectedRenewals, RunLevel.Interactive),
$"Run {selectionLabel}", "R", state: noneState));
$"Run {selectionLabel}", Shortcuts.R.ToString(), state: noneState));
options.Add(
Choice.Create<Func<Task>>(() => Run(selectedRenewals, RunLevel.Interactive | RunLevel.Force),
$"Run {selectionLabel} (force)", "S", state: noneState));
$"Run {selectionLabel} (force)", Shortcuts.S.ToString(), state: noneState));
if (_settings.Cache.ReuseDays > 0)
{
options.Add(
Choice.Create<Func<Task>>(() => Run(selectedRenewals, RunLevel.Interactive | RunLevel.Force | RunLevel.NoCache),
$"Run {selectionLabel} (force, no cache)", "T", state: noneState));
$"Run {selectionLabel} (force, no cache)", Shortcuts.T.ToString(), state: noneState));
}
options.Add(
Choice.Create<Func<Task>>(
async () => selectedRenewals = await Analyze(selectedRenewals),
$"Analyze duplicates for {selectionLabel}", "U", state: noneState));
$"Analyze duplicates for {selectionLabel}", Shortcuts.U.ToString(), state: noneState));
options.Add(
Choice.Create<Func<Task>>(
async () => {
Expand All @@ -222,7 +242,7 @@ internal async Task ManageRenewals()
selectedRenewals = originalSelection;
}
},
$"Cancel {selectionLabel}", "C", state: noneState));
$"Cancel {selectionLabel}", Shortcuts.C.ToString(), state: noneState));
options.Add(
Choice.Create<Func<Task>>(
async () => {
Expand All @@ -232,11 +252,11 @@ internal async Task ManageRenewals()
await _renewalRevoker.RevokeCertificates(selectedRenewals);
}
},
$"Revoke certificate(s) for {selectionLabel}", "V", state: noneState));
$"Revoke certificate(s) for {selectionLabel}", Shortcuts.V.ToString(), state: noneState));
options.Add(
Choice.Create<Func<Task>>(
() => { quit = true; return Task.CompletedTask; },
"Back", "Q",
"Back", Shortcuts.Q.ToString(),
@default: !originalSelection.Any()));

if (selectedRenewals.Count() > 1)
Expand Down
3 changes: 2 additions & 1 deletion src/main.lib/Services/CertificateService.cs
Expand Up @@ -186,7 +186,8 @@ private CertificateInfo ParseCertificate(byte[] bytes, string friendlyName, Asym
// Build pfx archive including any intermediates provided
_log.Verbose("Parsing certificate from {bytes} bytes received", bytes.Length);
var text = Encoding.UTF8.GetString(bytes);
var pfx = new Bc.Pkcs.Pkcs12Store();
var pfxBuilder = new Bc.Pkcs.Pkcs12StoreBuilder();
var pfx = pfxBuilder.Build();
var startIndex = 0;
const string startString = "-----BEGIN CERTIFICATE-----";
const string endString = "-----END CERTIFICATE-----";
Expand Down
8 changes: 8 additions & 0 deletions src/main.lib/Services/InputService.cs
Expand Up @@ -385,6 +385,14 @@ public async Task<T> ChooseFromMenu<T>(string what, List<Choice<T>> choices, Fun
{
throw new Exception("Default option is disabled");
}
var duplicates = choices.
Where(c => c.Command != null).
GroupBy(c => c.Command).
Where(g => g.Count() > 1);
if (duplicates.Any())
{
throw new Exception($"Duplicate command: {duplicates.First().Key}");
}

await WritePagedList(choices);

Expand Down
1 change: 0 additions & 1 deletion src/main.lib/Services/Serialization/WacsJsonPlugins.cs
Expand Up @@ -16,7 +16,6 @@ namespace PKISharp.WACS.Services.Serialization
[JsonSerializable(typeof(Target.IISBindingOptions))]
[JsonSerializable(typeof(Target.IISSiteOptions))]
[JsonSerializable(typeof(Target.IISSitesOptions))]
[JsonSerializable(typeof(Target.IISOptions))]
[JsonSerializable(typeof(Target.CsrOptions))]
[JsonSerializable(typeof(Validation.Dns.AcmeOptions))]
[JsonSerializable(typeof(Validation.Dns.ManualOptions), TypeInfoPropertyName = "DnsManualOptions")]
Expand Down
3 changes: 2 additions & 1 deletion src/main.lib/wacs.lib.csproj
Expand Up @@ -34,9 +34,10 @@

<ItemGroup>
<PackageReference Include="Autofac" Version="7.0.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.0" />
<PackageReference Include="DnsClient" Version="1.7.0" />
<PackageReference Include="FluentFTP" Version="46.0.2" />
<PackageReference Include="MailKit" Version="3.6.0" />
<PackageReference Include="MailKit" Version="4.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
Expand Down
2 changes: 1 addition & 1 deletion src/plugin.validation.dns.azure/Azure.cs
Expand Up @@ -83,7 +83,7 @@ public override async Task<bool> CreateRecord(DnsValidationRecord record)
}
catch
{
_recordSets[zone].Add(relativeKey, new DnsTxtRecordData());
_recordSets[zone].Add(relativeKey, new DnsTxtRecordData() { TtlInSeconds = 60 });
}
}
if (!_recordSets[zone][relativeKey].DnsTxtRecords.Any(x => x.Values.Contains(record.Value)))
Expand Down

0 comments on commit 46e9aa5

Please sign in to comment.