Show target certificate validity after PFX exchange.

Reuse the source PFX password for path probes and fall back to the loaded certificate expiry for successfully exchanged targets.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-31 08:12:45 +02:00
co-authored by Cursor
parent 89a694ba21
commit f98daec656
+58 -13
View File
@@ -47,6 +47,7 @@ namespace ZA.CoreService.ESBCertificateManager
private LocalSetupSelection? _localSetupSelection; private LocalSetupSelection? _localSetupSelection;
private CertificateInfo? _loadedCertificateInfo; private CertificateInfo? _loadedCertificateInfo;
private string? _loadedCertificatePassword;
private IReadOnlyList<DeploymentTarget> _loadedTargets = []; private IReadOnlyList<DeploymentTarget> _loadedTargets = [];
private bool _isOperationRunning; private bool _isOperationRunning;
private CancellationTokenSource? _runCts; private CancellationTokenSource? _runCts;
@@ -953,7 +954,9 @@ namespace ZA.CoreService.ESBCertificateManager
return; return;
} }
CertificateInfo? certificateInfo = TryReadSelectedCertificate(selectedPath); CertificateInfo? certificateInfo = TryReadSelectedCertificate(
selectedPath,
out string? certificatePassword);
if (certificateInfo == null) if (certificateInfo == null)
{ {
return; return;
@@ -961,15 +964,26 @@ namespace ZA.CoreService.ESBCertificateManager
txtCertificatePath.Text = selectedPath; txtCertificatePath.Text = selectedPath;
_loadedCertificateInfo = certificateInfo; _loadedCertificateInfo = certificateInfo;
_loadedCertificatePassword = certificatePassword;
SetStatus($"Zertifikat ausgewählt: {Path.GetFileName(selectedPath)}", isError: false); SetStatus($"Zertifikat ausgewählt: {Path.GetFileName(selectedPath)}", isError: false);
DisplayCertificateInfo(certificateInfo); DisplayCertificateInfo(certificateInfo);
UpdateToNextStep(2); UpdateToNextStep(2);
SetFileButtonState(fileLoaded: true); SetFileButtonState(fileLoaded: true);
RefreshActionButtonStates(); RefreshActionButtonStates();
// Zielpfade mit Quell-Kennwort erneut prüfen, damit Ablauf/Gültigkeit sichtbar wird
if (_loadedTargets.Count > 0)
{
_ = ProbeTargetCertificatesAsync();
}
} }
private CertificateInfo? TryReadSelectedCertificate(string selectedPath) private CertificateInfo? TryReadSelectedCertificate(
string selectedPath,
out string? certificatePassword)
{ {
certificatePassword = null;
string extension = Path.GetExtension(selectedPath); string extension = Path.GetExtension(selectedPath);
bool needsPassword = bool needsPassword =
extension.Equals(".pfx", StringComparison.OrdinalIgnoreCase) extension.Equals(".pfx", StringComparison.OrdinalIgnoreCase)
@@ -991,7 +1005,9 @@ namespace ZA.CoreService.ESBCertificateManager
try try
{ {
return ReadCertificate(selectedPath, pfxPassword); CertificateInfo info = ReadCertificate(selectedPath, pfxPassword);
certificatePassword = pfxPassword;
return info;
} }
catch (CryptographicException) catch (CryptographicException)
{ {
@@ -1019,6 +1035,7 @@ namespace ZA.CoreService.ESBCertificateManager
{ {
txtCertificatePath.Text = string.Empty; txtCertificatePath.Text = string.Empty;
_loadedCertificateInfo = null; _loadedCertificateInfo = null;
_loadedCertificatePassword = null;
SetStatus("Keine Datei ausgewählt", isError: false); SetStatus("Keine Datei ausgewählt", isError: false);
lblCertificateSubject.Text = "-"; lblCertificateSubject.Text = "-";
@@ -1671,9 +1688,14 @@ namespace ZA.CoreService.ESBCertificateManager
return merged; return merged;
} }
private async Task ProbeTargetCertificatesAsync() private async Task ProbeTargetCertificatesAsync(
IReadOnlySet<int>? preferLoadedCertificateForTargetIds = null)
{ {
CertificateProbeService probe = new(); CertificateProbeService probe = new();
string? password = _loadedCertificatePassword;
Func<string?>? passwordPrompt = password is null
? null
: () => password;
foreach (DataGridViewRow row in dgvTargets.Rows) foreach (DataGridViewRow row in dgvTargets.Rows)
{ {
@@ -1683,7 +1705,7 @@ namespace ZA.CoreService.ESBCertificateManager
} }
CertificateProbeResult result = await Task.Run( CertificateProbeResult result = await Task.Run(
() => probe.Probe(target.FullTargetPath)); () => probe.Probe(target.FullTargetPath, passwordPrompt));
if (IsDisposed || !dgvTargets.Columns.Contains("Expiry")) if (IsDisposed || !dgvTargets.Columns.Contains("Expiry"))
{ {
@@ -1692,13 +1714,20 @@ namespace ZA.CoreService.ESBCertificateManager
if (result.Success && result.Certificate is not null) if (result.Success && result.Certificate is not null)
{ {
string expiry = result.Certificate.ValidUntil row.Cells["Expiry"].Value = FormatCertificateExpiryCell(
.ToLocalTime() result.Certificate);
.ToString("dd.MM.yyyy"); continue;
}
row.Cells["Expiry"].Value = result.Certificate.IsCurrentlyValid // Nach erfolgreichem Tausch: Quellzertifikat liegt am Ziel
? $"gültig bis {expiry}" // Gültigkeit auch zeigen, falls Probe am Kennwort scheitert.
: $"abgelaufen {expiry}"; if (preferLoadedCertificateForTargetIds is not null
&& preferLoadedCertificateForTargetIds.Contains(target.Id)
&& _loadedCertificateInfo is not null
&& result.FileExists)
{
row.Cells["Expiry"].Value = FormatCertificateExpiryCell(
_loadedCertificateInfo);
continue; continue;
} }
@@ -1714,6 +1743,17 @@ namespace ZA.CoreService.ESBCertificateManager
} }
} }
private static string FormatCertificateExpiryCell(CertificateInfo certificate)
{
string expiry = certificate.ValidUntil
.ToLocalTime()
.ToString("dd.MM.yyyy");
return certificate.IsCurrentlyValid
? $"gültig bis {expiry}"
: $"abgelaufen {expiry}";
}
private List<DeploymentTarget> GetSelectedTargets() private List<DeploymentTarget> GetSelectedTargets()
{ {
List<DeploymentTarget> selected = []; List<DeploymentTarget> selected = [];
@@ -2071,6 +2111,11 @@ namespace ZA.CoreService.ESBCertificateManager
targetResult.StatusText); targetResult.StatusText);
} }
HashSet<int> exchangedTargetIds = runResult.TargetResults
.Where(result => result.Success)
.Select(result => result.TargetId)
.ToHashSet();
if (runResult.OverallSuccess) if (runResult.OverallSuccess)
{ {
SetStatus( SetStatus(
@@ -2078,7 +2123,7 @@ namespace ZA.CoreService.ESBCertificateManager
isError: false); isError: false);
UpdateToNextStep(4); UpdateToNextStep(4);
await ProbeTargetCertificatesAsync(); await ProbeTargetCertificatesAsync(exchangedTargetIds);
} }
else else
{ {
@@ -2100,7 +2145,7 @@ namespace ZA.CoreService.ESBCertificateManager
"Austausch fehlgeschlagen", "Austausch fehlgeschlagen",
details); details);
await ProbeTargetCertificatesAsync(); await ProbeTargetCertificatesAsync(exchangedTargetIds);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)