427 lines
13 KiB
C#
427 lines
13 KiB
C#
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 _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; }
|
||
|
||
public AddTargetPathForm(
|
||
SetupCoordinator coordinator,
|
||
int? preferredSonicContainerId = null)
|
||
{
|
||
_coordinator = coordinator;
|
||
|
||
Text = "Zertifikat-Pfad hinzufügen";
|
||
StartPosition = FormStartPosition.CenterParent;
|
||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||
MaximizeBox = false;
|
||
MinimizeBox = false;
|
||
ShowInTaskbar = false;
|
||
ClientSize = new Size(640, 560);
|
||
BackColor = SettingsUi.Background;
|
||
ForeColor = SettingsUi.Text;
|
||
Font = new Font("Segoe UI", 10f);
|
||
|
||
Label title = new()
|
||
{
|
||
Text = "Zertifikat-Datei-Pfad",
|
||
Location = new Point(28, 18),
|
||
AutoSize = true,
|
||
Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold),
|
||
ForeColor = SettingsUi.Text
|
||
};
|
||
|
||
Label subtitle = new()
|
||
{
|
||
Text =
|
||
"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, 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();
|
||
_txtBackupFolder = SettingsUi.CreateTextBox();
|
||
_txtBackupFolder.Text = "Backup";
|
||
|
||
_chkBackup = new CheckBox
|
||
{
|
||
Text = "Backup vor dem Überschreiben",
|
||
AutoSize = true,
|
||
Checked = true,
|
||
ForeColor = SettingsUi.Text,
|
||
Font = new Font("Segoe UI", 9.5f)
|
||
};
|
||
|
||
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);
|
||
|
||
_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(392, 490);
|
||
_btnSave.Size = new Size(220, 40);
|
||
_btnSave.Click += async (_, _) => await SaveAsync();
|
||
|
||
Button cancel = SettingsUi.CreateGhostButton("Abbrechen");
|
||
cancel.Location = new Point(270, 490);
|
||
cancel.Size = new Size(110, 40);
|
||
cancel.Click += (_, _) =>
|
||
{
|
||
DialogResult = DialogResult.Cancel;
|
||
Close();
|
||
};
|
||
|
||
Controls.Add(title);
|
||
Controls.Add(subtitle);
|
||
Controls.Add(card);
|
||
Controls.Add(cancel);
|
||
Controls.Add(_btnSave);
|
||
|
||
Shown += async (_, _) =>
|
||
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
|
||
{
|
||
IReadOnlyList<ContainerOption> containers =
|
||
await _coordinator.LoadContainersAsync();
|
||
|
||
_cmbContainer.Items.Clear();
|
||
int selected = 0;
|
||
|
||
for (int index = 0; index < containers.Count; index++)
|
||
{
|
||
_cmbContainer.Items.Add(containers[index]);
|
||
|
||
if (preferredSonicContainerId is int id
|
||
&& containers[index].SonicContainerId == id)
|
||
{
|
||
selected = index;
|
||
}
|
||
}
|
||
|
||
if (_cmbContainer.Items.Count > 0)
|
||
{
|
||
_cmbContainer.SelectedIndex = selected;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show(
|
||
this,
|
||
ex.Message,
|
||
"Zertifikat-Pfad",
|
||
MessageBoxButtons.OK,
|
||
MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
private async Task SaveAsync()
|
||
{
|
||
if (_running)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (_cmbContainer.SelectedItem is not ContainerOption container)
|
||
{
|
||
MessageBox.Show(
|
||
this,
|
||
"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;
|
||
|
||
try
|
||
{
|
||
CreatedCertificateTargetId =
|
||
await _coordinator.AddCertificateTargetAsync(
|
||
container.SonicContainerId,
|
||
directory,
|
||
fileName,
|
||
_chkBackup.Checked,
|
||
_txtBackupFolder.Text);
|
||
|
||
DialogResult = DialogResult.OK;
|
||
Close();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show(
|
||
this,
|
||
ex.Message,
|
||
"Zertifikat-Pfad",
|
||
MessageBoxButtons.OK,
|
||
MessageBoxIcon.Error);
|
||
}
|
||
finally
|
||
{
|
||
_running = false;
|
||
_btnSave.Enabled = true;
|
||
Cursor = Cursors.Default;
|
||
}
|
||
}
|
||
|
||
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,
|
||
Control input,
|
||
int x,
|
||
int y,
|
||
int width)
|
||
{
|
||
Label fieldLabel = SettingsUi.CreateFieldLabel(label);
|
||
fieldLabel.Location = new Point(x, y);
|
||
input.Location = new Point(x, y + 22);
|
||
input.Width = width;
|
||
parent.Controls.Add(fieldLabel);
|
||
parent.Controls.Add(input);
|
||
}
|
||
}
|