Initial commit: ESB Certificate Manager.
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
using System.Security.Cryptography;
|
||||
using ZA.CoreService.ESBCertificateManager.Models;
|
||||
|
||||
namespace ZA.CoreService.ESBCertificateManager.Services;
|
||||
|
||||
public sealed class CertificateDeployer
|
||||
{
|
||||
public Task<(bool Success, string Status, string? Detail, string? BackupPath)> DeployAsync(
|
||||
string sourceCertificatePath,
|
||||
DeploymentTarget target,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(() => Deploy(sourceCertificatePath, target, cancellationToken), cancellationToken);
|
||||
}
|
||||
|
||||
private static (bool Success, string Status, string? Detail, string? BackupPath) Deploy(
|
||||
string sourceCertificatePath,
|
||||
DeploymentTarget target,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!File.Exists(sourceCertificatePath))
|
||||
{
|
||||
return (false, "Quelle fehlt", $"Quelldatei nicht gefunden: {sourceCertificatePath}", null);
|
||||
}
|
||||
|
||||
string targetDirectory = PathResolver.ResolvePath(target.TargetDirectory);
|
||||
Directory.CreateDirectory(targetDirectory);
|
||||
|
||||
string destinationPath = Path.Combine(targetDirectory, target.CertificateFileName);
|
||||
string? backupPath = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(destinationPath))
|
||||
{
|
||||
backupPath = $"{destinationPath}.bak-{DateTime.Now:yyyyMMddHHmmss}";
|
||||
File.Copy(destinationPath, backupPath, overwrite: false);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
File.Copy(sourceCertificatePath, destinationPath, overwrite: true);
|
||||
|
||||
string sourceHash = ComputeSha256(sourceCertificatePath);
|
||||
string destHash = ComputeSha256(destinationPath);
|
||||
|
||||
if (!string.Equals(sourceHash, destHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
RestoreFromBackupOrDelete(destinationPath, backupPath);
|
||||
return (false, "Hash-Fehler", "SHA-256 von Quelle und Ziel stimmen nicht überein. Rollback ausgeführt.", backupPath);
|
||||
}
|
||||
|
||||
return (true, "Kopiert", $"Ziel: {destinationPath}", backupPath);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (backupPath is not null && File.Exists(backupPath) && File.Exists(destinationPath))
|
||||
{
|
||||
File.Copy(backupPath, destinationPath, overwrite: true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Rollback best-effort
|
||||
}
|
||||
|
||||
return (false, "Kopierfehler", ex.Message, backupPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RestoreFromBackupOrDelete(string destinationPath, string? backupPath)
|
||||
{
|
||||
if (backupPath is not null && File.Exists(backupPath))
|
||||
{
|
||||
File.Copy(backupPath, destinationPath, overwrite: true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.Exists(destinationPath))
|
||||
{
|
||||
File.Delete(destinationPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ComputeSha256(string filePath)
|
||||
{
|
||||
using FileStream stream = File.OpenRead(filePath);
|
||||
byte[] hash = SHA256.HashData(stream);
|
||||
return Convert.ToHexString(hash);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user