Files
Alessio Dal Santo 91dbe9ae11 [Feature] Aggiunta protezione machine-binding tramite MachineGuard
- Nuovo progetto MachineGuard: libreria che verifica se la macchina corrente
  è autorizzata all'esecuzione tramite DPAPI (Data Protection API di Windows)
- Nuovo progetto MachineGuardSetup: tool di configurazione da eseguire come
  Amministratore per registrare la macchina autorizzata
- Data_Coupler.sln: aggiunti entrambi i nuovi progetti alla soluzione
- Data_Coupler.csproj: aggiunto riferimento al progetto MachineGuard
- Program.cs: integrazione MachineGuard all'avvio dell'applicazione;
  se la macchina non è autorizzata l'app viene arrestata immediatamente
  con log critico e scrittura nel Windows Event Log
2026-03-30 16:42:43 +02:00

199 lines
8.9 KiB
C#

using MachineGuard;
// ============================================================
// MachineGuardSetup — Strumento di configurazione machine-binding
// Utilizzo: eseguire come Amministratore su ogni server autorizzato
// Indipendente da Data Coupler — nessuna dipendenza dall'applicazione
// ============================================================
Console.OutputEncoding = System.Text.Encoding.UTF8;
PrintBanner();
if (!OperatingSystem.IsWindows())
{
PrintError("Questo strumento richiede Windows (DPAPI è un'API esclusiva di Windows).");
return 1;
}
if (!IsRunningAsAdministrator())
{
PrintWarning("Attenzione: l'applicazione non è in esecuzione come Amministratore.");
PrintWarning("La scrittura in C:\\ProgramData potrebbe fallire senza privilegi elevati.");
Console.WriteLine();
}
return RunSetupWindows();
// ─────────────────────────────────────────────────────────────
// Entry point per Windows (isolato per soddisfare l'analizzatore)
// ─────────────────────────────────────────────────────────────
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
static int RunSetupWindows()
{
var defaultPath = MachineGuardSetupHelper.GetDefaultSecretFilePath();
Console.WriteLine("╔══════════════════════════════════════════════════════════╗");
Console.WriteLine("║ CONFIGURAZIONE MACHINE-BINDING ║");
Console.WriteLine("╚══════════════════════════════════════════════════════════╝");
Console.WriteLine();
Console.WriteLine($" Percorso predefinito secret: {defaultPath}");
Console.WriteLine();
// Chiedi conferma o percorso personalizzato
Console.Write(" Usare il percorso predefinito? [S/n]: ");
var input = Console.ReadLine()?.Trim().ToUpperInvariant();
Console.WriteLine();
string targetPath;
if (string.IsNullOrEmpty(input) || input == "S" || input == "Y")
{
targetPath = defaultPath;
}
else
{
Console.Write(" Inserire il percorso completo del file secret: ");
var customPath = Console.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(customPath))
{
PrintError("Percorso non valido. Operazione annullata.");
return 1;
}
targetPath = customPath;
}
// Verifica se esiste già un secret
if (File.Exists(targetPath))
{
Console.WriteLine($" ⚠ Il file secret esiste già: {targetPath}");
Console.Write(" Sovrascrivere? [s/N]: ");
var overwrite = Console.ReadLine()?.Trim().ToUpperInvariant();
Console.WriteLine();
if (overwrite != "S" && overwrite != "Y")
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(" Operazione annullata dall'utente.");
Console.ResetColor();
return 0;
}
// Verifica se il secret attuale è già valido
Console.WriteLine(" Verifica del secret esistente...");
if (MachineGuardSetupHelper.VerifySecret(targetPath))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(" ✓ Il secret esistente è GIÀ valido per questa macchina.");
Console.ResetColor();
Console.Write(" Continuare comunque e riscrivere? [s/N]: ");
var rewrite = Console.ReadLine()?.Trim().ToUpperInvariant();
Console.WriteLine();
if (rewrite != "S" && rewrite != "Y")
{
Console.WriteLine(" Operazione annullata. Il secret esistente rimane invariato.");
return 0;
}
}
}
// Scrittura del secret
Console.WriteLine($" Scrittura del secret cifrato con DPAPI (LocalMachine) in:");
Console.WriteLine($" {targetPath}");
Console.WriteLine();
try
{
MachineGuardSetupHelper.WriteSecret(targetPath);
}
catch (UnauthorizedAccessException ex)
{
PrintError($"Accesso negato: {ex.Message}");
PrintError("Riprovare eseguendo il programma come Amministratore (tasto destro → Esegui come amministratore).");
return 1;
}
catch (Exception ex)
{
PrintError($"Errore durante la scrittura del secret: {ex.Message}");
return 1;
}
// Verifica post-scrittura
Console.WriteLine(" Verifica del secret appena scritto...");
if (MachineGuardSetupHelper.VerifySecret(targetPath))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(" ✓ Secret scritto e verificato con successo!");
Console.ResetColor();
Console.WriteLine();
Console.WriteLine(" Questa macchina è ora autorizzata a eseguire Data Coupler.");
Console.WriteLine();
PrintFileInfo(targetPath);
}
else
{
PrintError("Verifica post-scrittura fallita. Il file potrebbe essere corrotto.");
return 1;
}
Console.WriteLine();
Console.WriteLine(" Premere un tasto per uscire...");
if (!Console.IsInputRedirected)
Console.ReadKey(intercept: true);
return 0;
}
// ─────────────────────────────────────────────────────────────
// Funzioni di utilità
// ─────────────────────────────────────────────────────────────
static void PrintBanner()
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine();
Console.WriteLine(" ██████╗ █████╗ ████████╗ █████╗ ██████╗ ██████╗ ██╗ ██╗██████╗ ██╗ ███████╗██████╗ ");
Console.WriteLine(" ██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗ ██╔════╝██╔═══██╗██║ ██║██╔══██╗██║ ██╔════╝██╔══██╗");
Console.WriteLine(" ██║ ██║███████║ ██║ ███████║ ██║ ██║ ██║██║ ██║██████╔╝██║ █████╗ ██████╔╝");
Console.WriteLine(" ██║ ██║██╔══██║ ██║ ██╔══██║ ██║ ██║ ██║██║ ██║██╔═══╝ ██║ ██╔══╝ ██╔══██╗");
Console.WriteLine(" ██████╔╝██║ ██║ ██║ ██║ ██║ ╚██████╗╚██████╔╝╚██████╔╝██║ ███████╗███████╗██║ ██║");
Console.WriteLine(" ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝");
Console.ResetColor();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(" MachineGuardSetup — Configurazione protezione machine-binding per Data Coupler");
Console.WriteLine(" Versione: 1.0 | Tecnologia: DPAPI (DataProtectionScope.LocalMachine)");
Console.ResetColor();
Console.WriteLine(new string('─', 70));
Console.WriteLine();
}
static void PrintError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($" ✗ ERRORE: {message}");
Console.ResetColor();
}
static void PrintWarning(string message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($" ⚠ {message}");
Console.ResetColor();
}
static void PrintFileInfo(string path)
{
var fi = new FileInfo(path);
Console.WriteLine(" Dettagli file:");
Console.WriteLine($" Percorso : {fi.FullName}");
Console.WriteLine($" Dimensione: {fi.Length} byte (cifrati con DPAPI)");
Console.WriteLine($" Creato : {fi.CreationTime:dd/MM/yyyy HH:mm:ss}");
}
static bool IsRunningAsAdministrator()
{
if (!OperatingSystem.IsWindows()) return false;
using var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var principal = new System.Security.Principal.WindowsPrincipal(identity);
return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
}