Improve certificate path probing with demo UNC target and remove Sonic container scan.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 09:14:25 +02:00
co-authored by Cursor
parent f7e9bd43e2
commit f584fd68fe
16 changed files with 1026 additions and 999 deletions
@@ -1,16 +1,22 @@
using ZA.CoreService.ESBCertificateManager.Models;
using ZA.CoreService.ESBCertificateManager.Services;
namespace ZA.CoreService.ESBCertificateManager.Setup;
public sealed class AddTargetPathForm : Form
{
private readonly SetupCoordinator _coordinator;
private readonly CertificateProbeService _probeService = new();
private readonly ComboBox _cmbContainer;
private readonly TextBox _txtDirectory;
private readonly TextBox _txtFileName;
private readonly TextBox _txtFullPath;
private readonly TextBox _txtBackupFolder;
private readonly CheckBox _chkBackup;
private readonly Label _lblProbeResult;
private readonly Button _btnProbe;
private readonly Button _btnSave;
private CertificateProbeResult? _lastProbe;
private bool _running;
public int? CreatedCertificateTargetId { get; private set; }
@@ -27,15 +33,15 @@ public sealed class AddTargetPathForm : Form
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
ClientSize = new Size(560, 450);
ClientSize = new Size(640, 560);
BackColor = SettingsUi.Background;
ForeColor = SettingsUi.Text;
Font = new Font("Segoe UI", 10f);
Label title = new()
{
Text = "Neuer Zertifikat-Pfad",
Location = new Point(28, 22),
Text = "Zertifikat-Datei-Pfad",
Location = new Point(28, 18),
AutoSize = true,
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
ForeColor = SettingsUi.Text
@@ -44,23 +50,45 @@ public sealed class AddTargetPathForm : Form
Label subtitle = new()
{
Text =
"Zielverzeichnis und Dateiname für die Zertifikatsablage.",
Location = new Point(30, 58),
"UNC- oder lokaler Dateipfad zur .cer/.crt/.pem/.pfx/.p12-Datei. "
+ "Der Container ist nur das Neustart-Ziel.",
Location = new Point(30, 54),
MaximumSize = new Size(580, 40),
AutoSize = true,
ForeColor = SettingsUi.Muted
};
Panel card = SettingsUi.CreateCard();
card.Location = new Point(28, 95);
card.Size = new Size(504, 270);
card.Location = new Point(28, 100);
card.Size = new Size(584, 360);
card.Paint += SettingsUi.PaintCardBorder;
_txtFullPath = SettingsUi.CreateTextBox();
_txtFullPath.Text = DemoCertificatePath.FullPath;
_txtFullPath.PlaceholderText = DemoCertificatePath.FullPath;
Button browse = SettingsUi.CreateGhostButton("…");
browse.Size = new Size(40, 32);
browse.Click += (_, _) => BrowseForFile();
_btnProbe = SettingsUi.CreateGhostButton("Prüfen");
_btnProbe.Size = new Size(100, 32);
_btnProbe.Click += (_, _) => RunProbe();
_lblProbeResult = new Label
{
AutoSize = false,
Size = new Size(548, 52),
ForeColor = SettingsUi.Muted,
Font = new Font("Segoe UI", 9f),
Text =
"Noch nicht geprüft. Bitte Pfad prüfen bei vorhandener "
+ "Datei wird der Ablauf angezeigt."
};
_cmbContainer = SettingsUi.CreateComboBox();
_txtDirectory = SettingsUi.CreateTextBox();
_txtFileName = SettingsUi.CreateTextBox();
_txtBackupFolder = SettingsUi.CreateTextBox();
_txtBackupFolder.Text = "Backup";
_txtFileName.Text = "server.crt";
_chkBackup = new CheckBox
{
@@ -71,21 +99,54 @@ public sealed class AddTargetPathForm : Form
Font = new Font("Segoe UI", 9.5f)
};
AddField(card, "Container", _cmbContainer, 18, 18, 460);
AddField(card, "Zielverzeichnis", _txtDirectory, 18, 78, 460);
AddField(card, "Dateiname", _txtFileName, 18, 138, 220);
AddField(card, "Backup-Ordner", _txtBackupFolder, 258, 138, 220);
Label pathLabel = SettingsUi.CreateFieldLabel(
"Vollständiger Pfad zur Zertifikatsdatei");
pathLabel.Location = new Point(18, 16);
_txtFullPath.Location = new Point(18, 38);
_txtFullPath.Width = 370;
browse.Location = new Point(394, 38);
_btnProbe.Location = new Point(440, 38);
_chkBackup.Location = new Point(18, 210);
_lblProbeResult.Location = new Point(18, 78);
Label containerLabel = SettingsUi.CreateFieldLabel(
"Neustart-Ziel (Sonic-Container) nicht der Dateipfad");
containerLabel.Location = new Point(18, 140);
_cmbContainer.Location = new Point(18, 162);
_cmbContainer.Width = 548;
Label hint = new()
{
Text =
"Nach dem Austausch wird dieser Container über MfApi "
+ "neu gestartet. Der Pfad oben ist unabhängig davon.",
Location = new Point(18, 202),
MaximumSize = new Size(548, 36),
AutoSize = true,
ForeColor = SettingsUi.Muted,
Font = new Font("Segoe UI", 8.5f)
};
AddField(card, "Backup-Ordner", _txtBackupFolder, 18, 250, 220);
_chkBackup.Location = new Point(258, 272);
card.Controls.Add(_chkBackup);
card.Controls.Add(pathLabel);
card.Controls.Add(_txtFullPath);
card.Controls.Add(browse);
card.Controls.Add(_btnProbe);
card.Controls.Add(_lblProbeResult);
card.Controls.Add(containerLabel);
card.Controls.Add(_cmbContainer);
card.Controls.Add(hint);
_btnSave = SettingsUi.CreatePrimaryButton("Pfad anlegen");
_btnSave.Location = new Point(312, 385);
_btnSave.Location = new Point(392, 490);
_btnSave.Size = new Size(220, 40);
_btnSave.Click += async (_, _) => await SaveAsync();
Button cancel = SettingsUi.CreateGhostButton("Abbrechen");
cancel.Location = new Point(190, 385);
cancel.Location = new Point(270, 490);
cancel.Size = new Size(110, 40);
cancel.Click += (_, _) =>
{
@@ -103,6 +164,64 @@ public sealed class AddTargetPathForm : Form
await LoadContainersAsync(preferredSonicContainerId);
}
private void BrowseForFile()
{
using OpenFileDialog dialog = new()
{
Title = "Vorhandene Zertifikatsdatei wählen",
Filter =
"Zertifikate (*.cer;*.crt;*.pem;*.pfx;*.p12)|"
+ "*.cer;*.crt;*.pem;*.pfx;*.p12|"
+ "Alle Dateien (*.*)|*.*",
CheckFileExists = false,
Multiselect = false
};
if (dialog.ShowDialog(this) != DialogResult.OK)
{
return;
}
_txtFullPath.Text = dialog.FileName;
RunProbe();
}
private void RunProbe()
{
_lastProbe = _probeService.Probe(
_txtFullPath.Text,
() => PromptForPassword(this));
if (!_lastProbe.Success)
{
_lblProbeResult.ForeColor = Color.FromArgb(220, 100, 100);
_lblProbeResult.Text = _lastProbe.Message;
return;
}
if (!_lastProbe.FileExists)
{
_lblProbeResult.ForeColor = Color.FromArgb(230, 180, 80);
_lblProbeResult.Text =
_lastProbe.Message
+ " Pfad kann trotzdem gespeichert werden "
+ "(erstes Deployment).";
return;
}
CertificateInfo cert = _lastProbe.Certificate!;
string expiry = cert.ValidUntil.ToLocalTime()
.ToString("dd.MM.yyyy HH:mm");
_lblProbeResult.ForeColor = cert.IsCurrentlyValid
? Color.FromArgb(90, 200, 140)
: Color.FromArgb(220, 100, 100);
_lblProbeResult.Text =
$"Datei vorhanden · Subject: {cert.Subject}\n"
+ $"Ablauf: {expiry} · Fingerprint: {cert.FingerprintSha256}";
}
private async Task LoadContainersAsync(int? preferredSonicContainerId)
{
try
@@ -151,13 +270,59 @@ public sealed class AddTargetPathForm : Form
{
MessageBox.Show(
this,
"Bitte einen Container wählen.",
"Bitte ein Neustart-Ziel (Sonic-Container) wählen.",
"Zertifikat-Pfad",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
if (!CertificateProbeService.TrySplitTargetPath(
_txtFullPath.Text,
out string directory,
out string fileName,
out string? splitError))
{
MessageBox.Show(
this,
splitError ?? "Ungültiger Pfad.",
"Zertifikat-Pfad",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
// Vor dem Speichern immer prüfen
RunProbe();
if (_lastProbe is null || !_lastProbe.Success)
{
MessageBox.Show(
this,
_lastProbe?.Message
?? "Pfad konnte nicht geprüft werden.",
"Zertifikat-Pfad",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
if (!_lastProbe.FileExists)
{
DialogResult confirm = MessageBox.Show(
this,
"Am Ziel liegt noch keine Zertifikatsdatei.\n\n"
+ "Pfad trotzdem speichern?",
"Datei fehlt",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (confirm != DialogResult.Yes)
{
return;
}
}
_running = true;
_btnSave.Enabled = false;
Cursor = Cursors.WaitCursor;
@@ -167,8 +332,8 @@ public sealed class AddTargetPathForm : Form
CreatedCertificateTargetId =
await _coordinator.AddCertificateTargetAsync(
container.SonicContainerId,
_txtDirectory.Text,
_txtFileName.Text,
directory,
fileName,
_chkBackup.Checked,
_txtBackupFolder.Text);
@@ -192,6 +357,57 @@ public sealed class AddTargetPathForm : Form
}
}
private static string? PromptForPassword(IWin32Window owner)
{
using Form dialog = new()
{
Text = "PFX/P12-Kennwort",
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterParent,
ClientSize = new Size(360, 140),
MaximizeBox = false,
MinimizeBox = false,
ShowInTaskbar = false,
BackColor = SettingsUi.Background,
ForeColor = SettingsUi.Text
};
Label label = new()
{
Text = "Kennwort für die Zertifikatsdatei:",
Location = new Point(16, 16),
AutoSize = true
};
TextBox txtPwd = new()
{
Location = new Point(16, 44),
Width = 320,
UseSystemPasswordChar = true
};
Button btnOk = SettingsUi.CreatePrimaryButton("OK");
btnOk.Location = new Point(196, 90);
btnOk.Size = new Size(140, 32);
btnOk.DialogResult = DialogResult.OK;
Button btnCancel = SettingsUi.CreateGhostButton("Abbrechen");
btnCancel.Location = new Point(100, 90);
btnCancel.Size = new Size(90, 32);
btnCancel.DialogResult = DialogResult.Cancel;
dialog.Controls.Add(label);
dialog.Controls.Add(txtPwd);
dialog.Controls.Add(btnOk);
dialog.Controls.Add(btnCancel);
dialog.AcceptButton = btnOk;
dialog.CancelButton = btnCancel;
return dialog.ShowDialog(owner) == DialogResult.OK
? txtPwd.Text
: null;
}
private static void AddField(
Control parent,
string label,
@@ -1,432 +0,0 @@
using ZA.CoreService.ESBCertificateManager.Models;
using ZA.CoreService.ESBCertificateManager.Services;
namespace ZA.CoreService.ESBCertificateManager.Setup;
public sealed class SelectContainersForm : Form
{
private readonly SetupCoordinator _coordinator;
private readonly SonicSystemOption _system;
private readonly SonicContainerScanner _scanner;
private readonly ComboBox _cmbCompany;
private readonly CheckedListBox _lstContainers;
private readonly TextBox _txtManual;
private readonly TextBox _txtUser;
private readonly TextBox _txtPassword;
private readonly Label _lblStatus;
private readonly Button _btnScan;
private readonly Button _btnSave;
private bool _running;
public int SavedCount { get; private set; }
public SelectContainersForm(
SetupCoordinator coordinator,
SonicSystemOption system)
{
_coordinator = coordinator;
_system = system;
_scanner = new SonicContainerScanner(coordinator.Settings.Runtime);
Text = "Container auswählen";
StartPosition = FormStartPosition.CenterParent;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
ClientSize = new Size(640, 620);
BackColor = SettingsUi.Background;
ForeColor = SettingsUi.Text;
Font = new Font("Segoe UI", 10f);
Label title = new()
{
Text = "Container für System",
Location = new Point(28, 20),
AutoSize = true,
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
ForeColor = SettingsUi.Text
};
Label subtitle = new()
{
Text =
$"{system.ConnectionName} · {system.ConnectionUrl}"
+ Environment.NewLine
+ "Scan von Sonic oder manuell eintragen, dann übernehmen.",
Location = new Point(30, 54),
Size = new Size(580, 40),
ForeColor = SettingsUi.Muted
};
Panel card = SettingsUi.CreateCard();
card.Location = new Point(28, 110);
card.Size = new Size(584, 430);
card.Paint += SettingsUi.PaintCardBorder;
_cmbCompany = SettingsUi.CreateComboBox();
_lstContainers = new CheckedListBox
{
BackColor = Color.FromArgb(12, 28, 48),
ForeColor = SettingsUi.Text,
BorderStyle = BorderStyle.FixedSingle,
CheckOnClick = true,
Font = new Font("Segoe UI", 10f)
};
_txtManual = SettingsUi.CreateTextBox();
_txtUser = SettingsUi.CreateTextBox();
_txtPassword = SettingsUi.CreateTextBox();
_txtPassword.UseSystemPasswordChar = true;
AddField(card, "Company", _cmbCompany, 18, 16, 540);
AddField(card, "Gefundene / gewählte Container", _lstContainers, 18, 76, 540, 150);
Label manualLabel = SettingsUi.CreateFieldLabel("Manuell hinzufügen");
manualLabel.Location = new Point(18, 240);
_txtManual.Location = new Point(18, 262);
_txtManual.Width = 400;
Button btnAddManual = SettingsUi.CreateGhostButton("");
btnAddManual.Location = new Point(430, 260);
btnAddManual.Size = new Size(50, 32);
btnAddManual.Click += (_, _) => AddManualContainer();
Button btnSuggest = SettingsUi.CreateGhostButton("ct-ZADBService");
btnSuggest.Location = new Point(490, 260);
btnSuggest.Size = new Size(68, 32);
btnSuggest.Font = new Font("Segoe UI", 7.5f, FontStyle.Bold);
btnSuggest.Click += (_, _) =>
{
_txtManual.Text = "ct-ZADBService";
AddManualContainer();
};
AddField(card, "Sonic-Benutzer (für Scan)", _txtUser, 18, 308, 250);
AddField(card, "Kennwort", _txtPassword, 288, 308, 270);
_btnScan = SettingsUi.CreatePrimaryButton("Von Sonic scannen");
_btnScan.Location = new Point(18, 375);
_btnScan.Size = new Size(200, 36);
_btnScan.Click += async (_, _) => await ScanAsync();
_lblStatus = new Label
{
Location = new Point(230, 380),
Size = new Size(330, 30),
ForeColor = SettingsUi.Muted
};
card.Controls.Add(manualLabel);
card.Controls.Add(_txtManual);
card.Controls.Add(btnAddManual);
card.Controls.Add(btnSuggest);
card.Controls.Add(_btnScan);
card.Controls.Add(_lblStatus);
_btnSave = SettingsUi.CreatePrimaryButton("Auswahl speichern");
_btnSave.Location = new Point(352, 555);
_btnSave.Size = new Size(260, 42);
_btnSave.Click += async (_, _) => await SaveAsync();
Button skip = SettingsUi.CreateGhostButton("Später");
skip.Location = new Point(230, 555);
skip.Size = new Size(110, 42);
skip.Click += (_, _) =>
{
DialogResult = DialogResult.Cancel;
Close();
};
Controls.Add(title);
Controls.Add(subtitle);
Controls.Add(card);
Controls.Add(skip);
Controls.Add(_btnSave);
Shown += async (_, _) => await InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
IReadOnlyList<CompanyOption> companies =
await _coordinator.LoadCompaniesAsync();
_cmbCompany.Items.Clear();
foreach (CompanyOption company in companies)
{
_cmbCompany.Items.Add(company);
}
if (_cmbCompany.Items.Count > 0)
{
int deIndex = 0;
for (int index = 0; index < companies.Count; index++)
{
if (string.Equals(
companies[index].CompanyCode,
"DE",
StringComparison.OrdinalIgnoreCase))
{
deIndex = index;
break;
}
}
_cmbCompany.SelectedIndex = deIndex;
}
IReadOnlyList<SonicCredentialProfile> profiles =
await _coordinator.LoadCredentialsAsync(
_system.SonicConnectionId);
SonicCredentialProfile? profile =
profiles.FirstOrDefault(item => item.IsDefault)
?? profiles.FirstOrDefault();
if (profile is not null)
{
_txtUser.Text = profile.UserName;
_txtPassword.Text = profile.Secret;
_lblStatus.Text =
"Profil geladen — Scan möglich.";
_lblStatus.ForeColor = SettingsUi.Green;
}
else
{
_lblStatus.Text =
"Kein Profil — Benutzer/Kennwort für Scan eingeben oder manuell.";
_lblStatus.ForeColor = SettingsUi.Gold;
}
// Bereits vorhandene Container vorselektieren
IReadOnlyList<ContainerOption> existing =
await _coordinator.LoadContainersAsync(
_system.SonicConnectionId);
foreach (ContainerOption container in existing)
{
AddContainerName(container.ContainerName, check: true);
}
}
catch (Exception ex)
{
_lblStatus.Text = ex.Message;
_lblStatus.ForeColor = SettingsUi.Red;
}
}
private void AddManualContainer()
{
string name = _txtManual.Text.Trim();
if (name.Length == 0)
{
return;
}
AddContainerName(name, check: true);
_txtManual.Clear();
_txtManual.Focus();
}
private void AddContainerName(string name, bool check)
{
for (int index = 0; index < _lstContainers.Items.Count; index++)
{
if (string.Equals(
_lstContainers.Items[index]?.ToString(),
name,
StringComparison.OrdinalIgnoreCase))
{
_lstContainers.SetItemChecked(index, check);
return;
}
}
int added = _lstContainers.Items.Add(name);
_lstContainers.SetItemChecked(added, check);
}
private async Task ScanAsync()
{
if (_running)
{
return;
}
_running = true;
_btnScan.Enabled = false;
_btnSave.Enabled = false;
Cursor = Cursors.WaitCursor;
_lblStatus.Text = "Scanne Domain…";
_lblStatus.ForeColor = SettingsUi.Muted;
try
{
ContainerScanResult result =
await _scanner.ScanAsync(
_system,
_txtUser.Text,
_txtPassword.Text);
if (!result.Success)
{
_lblStatus.Text = result.Message;
_lblStatus.ForeColor = SettingsUi.Red;
return;
}
foreach (string container in result.Containers)
{
AddContainerName(container, check: true);
}
_lblStatus.Text =
result.Containers.Count == 0
? "Scan OK, aber keine Container gefunden — bitte manuell."
: $"{result.Containers.Count} Container gescannt und vorausgewählt.";
_lblStatus.ForeColor =
result.Containers.Count == 0
? SettingsUi.Gold
: SettingsUi.Green;
}
catch (Exception ex)
{
_lblStatus.Text = ex.Message;
_lblStatus.ForeColor = SettingsUi.Red;
}
finally
{
_running = false;
_btnScan.Enabled = true;
_btnSave.Enabled = true;
Cursor = Cursors.Default;
}
}
private async Task SaveAsync()
{
if (_running)
{
return;
}
if (_cmbCompany.SelectedItem is not CompanyOption company)
{
MessageBox.Show(
this,
"Bitte eine Company wählen.",
"Container",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
List<string> selected = _lstContainers.CheckedItems
.Cast<object>()
.Select(item => item.ToString() ?? string.Empty)
.Where(name => name.Length > 0)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (selected.Count == 0)
{
MessageBox.Show(
this,
"Bitte mindestens einen Container angehakt lassen "
+ "oder manuell hinzufügen.",
"Container",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
_running = true;
_btnSave.Enabled = false;
Cursor = Cursors.WaitCursor;
try
{
IReadOnlyList<ContainerOption> existing =
await _coordinator.LoadContainersAsync(
_system.SonicConnectionId);
HashSet<string> existingNames = existing
.Select(item => item.ContainerName)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
int created = 0;
foreach (string containerName in selected)
{
if (existingNames.Contains(containerName))
{
continue;
}
await _coordinator.AddSonicContainerAsync(
company.CompanyId,
_system.SonicConnectionId,
containerName,
containerDisplayName: null,
restartTimeoutSeconds: 180);
created++;
}
SavedCount = created;
MessageBox.Show(
this,
created == 0
? "Alle gewählten Container waren bereits vorhanden."
: $"{created} Container gespeichert und geprüft.",
"Prüfung OK",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
catch (Exception ex)
{
MessageBox.Show(
this,
ex.Message,
"Container",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
finally
{
_running = false;
_btnSave.Enabled = true;
Cursor = Cursors.Default;
}
}
private static void AddField(
Control parent,
string label,
Control input,
int x,
int y,
int width,
int height = 30)
{
Label fieldLabel = SettingsUi.CreateFieldLabel(label);
fieldLabel.Location = new Point(x, y);
input.Location = new Point(x, y + 22);
input.Width = width;
input.Height = height;
parent.Controls.Add(fieldLabel);
parent.Controls.Add(input);
}
}
@@ -1,4 +1,5 @@
using ZA.CoreService.ESBCertificateManager.Models;
using ZA.CoreService.ESBCertificateManager.Services;
namespace ZA.CoreService.ESBCertificateManager.Setup;
@@ -381,9 +382,7 @@ public sealed class SetupWizardForm : Form
Panel toolbar = CreateToolbar(
"+ Container hinzufügen",
async () => await AddContainerAsync(),
secondaryText: "Von Sonic scannen",
onSecondary: async () => await ScanContainersForSelectedSystemAsync());
async () => await AddContainerAsync());
_lvContainers = SettingsUi.CreateListView();
_lvContainers.Dock = DockStyle.Fill;
@@ -400,20 +399,22 @@ public sealed class SetupWizardForm : Form
{
_panelPaths = CreateContentPanel(
"Zertifikat-Pfade",
"Zielverzeichnisse und Dateinamen für Deployments.");
"Dateipfade (UNC/lokal) zum Austausch. Container = nur Neustart-Ziel.");
Panel toolbar = CreateToolbar(
"+ Pfad hinzufügen",
async () => await AddPathAsync());
async () => await AddPathAsync(),
"Pfad prüfen",
async () => await ProbeSelectedPathAsync());
_lvPaths = SettingsUi.CreateListView();
_lvPaths.Dock = DockStyle.Fill;
_lvPaths.Columns.Add("Company", 70);
_lvPaths.Columns.Add("Container", 140);
_lvPaths.Columns.Add("Verzeichnis", 280);
_lvPaths.Columns.Add("Datei", 120);
_lvPaths.Columns.Add("Neustart-Container", 140);
_lvPaths.Columns.Add("Zertifikat-Pfad", 360);
_lvPaths.Columns.Add("Ablauf", 140);
_lvPaths.Columns.Add("Backup", 80);
_lvPaths.Columns.Add("System", 140);
_lvPaths.Columns.Add("System", 120);
FinishPanelLayout(_panelPaths, _lvPaths, toolbar);
}
@@ -644,13 +645,14 @@ public sealed class SetupWizardForm : Form
await _coordinator.LoadCertificateTargetsAsync();
_lvPaths.Items.Clear();
CertificateProbeService probe = new();
foreach (CertificateTargetOption target in targets)
{
ListViewItem item = new(target.CompanyCode);
item.SubItems.Add(target.ContainerName);
item.SubItems.Add(target.TargetDirectory);
item.SubItems.Add(target.TargetFileName);
item.SubItems.Add(target.FullTargetPath);
item.SubItems.Add("…");
item.SubItems.Add(
target.BackupEnabled
? target.BackupDirectoryName
@@ -658,6 +660,11 @@ public sealed class SetupWizardForm : Form
item.SubItems.Add(target.ConnectionName);
item.Tag = target;
_lvPaths.Items.Add(item);
CertificateProbeResult result = await Task.Run(
() => probe.Probe(target.FullTargetPath));
item.SubItems[3].Text = FormatProbeExpiry(result);
}
}
catch (Exception ex)
@@ -666,6 +673,110 @@ public sealed class SetupWizardForm : Form
}
}
private async Task ProbeSelectedPathAsync()
{
if (_lvPaths.SelectedItems.Count == 0
|| _lvPaths.SelectedItems[0].Tag is not CertificateTargetOption target)
{
MessageBox.Show(
this,
"Bitte zuerst einen Zertifikat-Pfad in der Liste wählen.",
"Pfad prüfen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
CertificateProbeService probe = new();
CertificateProbeResult result = probe.Probe(
target.FullTargetPath,
() => PromptCertificatePassword(this));
_lvPaths.SelectedItems[0].SubItems[3].Text =
FormatProbeExpiry(result);
MessageBoxIcon icon = result.Success && result.Certificate is not null
? (result.Certificate.IsCurrentlyValid
? MessageBoxIcon.Information
: MessageBoxIcon.Warning)
: MessageBoxIcon.Warning;
MessageBox.Show(
this,
result.Message + "\n\n" + target.FullTargetPath,
"Pfad prüfen",
MessageBoxButtons.OK,
icon);
}
private static string FormatProbeExpiry(CertificateProbeResult result)
{
if (result.Success && result.Certificate is not null)
{
return result.Certificate.ValidUntil
.ToLocalTime()
.ToString("dd.MM.yyyy HH:mm");
}
if (result.FileExists)
{
return "Kennwort nötig";
}
return result.Success ? "fehlt" : "n/a";
}
private static string? PromptCertificatePassword(IWin32Window owner)
{
using Form dialog = new()
{
Text = "PFX/P12-Kennwort",
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterParent,
ClientSize = new Size(360, 140),
MaximizeBox = false,
MinimizeBox = false,
ShowInTaskbar = false,
BackColor = SettingsUi.Background,
ForeColor = SettingsUi.Text
};
Label label = new()
{
Text = "Kennwort für die Zertifikatsdatei:",
Location = new Point(16, 16),
AutoSize = true
};
TextBox txtPwd = new()
{
Location = new Point(16, 44),
Width = 320,
UseSystemPasswordChar = true
};
Button btnOk = SettingsUi.CreatePrimaryButton("OK");
btnOk.Location = new Point(196, 90);
btnOk.Size = new Size(140, 32);
btnOk.DialogResult = DialogResult.OK;
Button btnCancel = SettingsUi.CreateGhostButton("Abbrechen");
btnCancel.Location = new Point(100, 90);
btnCancel.Size = new Size(90, 32);
btnCancel.DialogResult = DialogResult.Cancel;
dialog.Controls.Add(label);
dialog.Controls.Add(txtPwd);
dialog.Controls.Add(btnOk);
dialog.Controls.Add(btnCancel);
dialog.AcceptButton = btnOk;
dialog.CancelButton = btnCancel;
return dialog.ShowDialog(owner) == DialogResult.OK
? txtPwd.Text
: null;
}
private async Task AddSystemAsync()
{
using AddSonicSystemForm dialog = new(_coordinator);
@@ -706,78 +817,6 @@ public sealed class SetupWizardForm : Form
"Prüfung OK",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
SonicSystemOption? createdSystem = _systems
.FirstOrDefault(system =>
system.SonicConnectionId == createdId);
if (createdSystem is null
&& _lvSystems.SelectedItems.Count > 0)
{
createdSystem =
_lvSystems.SelectedItems[0].Tag as SonicSystemOption;
}
if (createdSystem is null)
{
return;
}
DialogResult next = MessageBox.Show(
this,
"Container jetzt per Sonic-Scan oder manuell zuordnen?",
"Container",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (next != DialogResult.Yes)
{
return;
}
using SelectContainersForm selectForm =
new(_coordinator, createdSystem);
if (selectForm.ShowDialog(this) == DialogResult.OK)
{
await LoadContainersListAsync();
await RefreshAllAsync();
}
}
private async Task ScanContainersForSelectedSystemAsync()
{
SonicSystemOption? system = null;
if (_lvSystems.SelectedItems.Count > 0)
{
system = _lvSystems.SelectedItems[0].Tag as SonicSystemOption;
}
system ??= _systems.FirstOrDefault();
if (system is null)
{
// Systeme-Liste ggf. nachladen
await LoadSystemsListAsync();
system = _systems.FirstOrDefault();
}
if (system is null)
{
ShowWarning(
"Bitte zuerst ein Sonic-System anlegen oder auswählen.");
return;
}
using SelectContainersForm selectForm =
new(_coordinator, system);
if (selectForm.ShowDialog(this) == DialogResult.OK)
{
await LoadContainersListAsync();
await RefreshAllAsync();
}
}
private async Task AddContainerAsync()