using Dapper; using Microsoft.Extensions.Configuration; using PasswordMigrationUtil; // Namespace de tus clases copiadas/modificadas using System.Data; Console.WriteLine("Iniciando Utilidad de Migración de Contraseñas..."); // --- Configuración --- IConfiguration configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .Build(); string? connectionString = configuration.GetConnectionString("DefaultConnection"); if (string.IsNullOrEmpty(connectionString)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("ERROR: No se encontró la cadena de conexión 'DefaultConnection' en appsettings.json."); Console.ResetColor(); return 1; // Termina con código de error } // --- Inicialización de Servicios --- var connectionFactory = new DbConnectionFactory(connectionString); var passwordHasher = new PasswordHasherService(); int migratedCount = 0; int errorCount = 0; // --- Lógica Principal --- try { using (var connection = connectionFactory.CreateConnection()) { connection.Open(); Console.WriteLine("Conexión a base de datos establecida."); // Seleccionar usuarios que necesitan migración (ClaveSalt es NULL o vacía) // ¡¡AJUSTA 'ClaveHash' AL NOMBRE DE LA COLUMNA QUE TIENE LA CLAVE EN TEXTO PLANO AHORA MISMO!! var usersToMigrateQuery = @" SELECT Id, [User], ClaveHash AS PlainPassword -- Leer la clave plana de la columna correcta FROM dbo.gral_Usuarios WHERE ClaveSalt IS NULL OR ClaveSalt = ''"; Console.WriteLine("Consultando usuarios para migrar..."); var users = await connection.QueryAsync<(int Id, string User, string PlainPassword)>(usersToMigrateQuery); if (!users.Any()) { Console.WriteLine("No se encontraron usuarios que necesiten migración."); return 0; } Console.WriteLine($"Se encontraron {users.Count()} usuarios para migrar."); foreach (var user in users) { Console.Write($"Migrando usuario ID: {user.Id}, Username: {user.User}... "); try { if (string.IsNullOrWhiteSpace(user.PlainPassword)) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("ADVERTENCIA: Contraseña vacía o nula, omitiendo hash."); Console.ResetColor(); // Opcionalmente, podrías poner un hash/salt inválido o manejarlo de otra forma continue; // Saltar al siguiente usuario } // Generar hash y salt (string hash, string salt) = passwordHasher.HashPassword(user.PlainPassword); // Actualizar la base de datos (¡CON PARÁMETROS!) var updateQuery = @" UPDATE dbo.gral_Usuarios SET ClaveHash = @HashedPassword, ClaveSalt = @Salt WHERE Id = @UserId"; var parameters = new { HashedPassword = hash, Salt = salt, UserId = user.Id }; int rowsAffected = await connection.ExecuteAsync(updateQuery, parameters); if (rowsAffected == 1) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("¡Éxito!"); Console.ResetColor(); migratedCount++; } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"ERROR: No se actualizaron filas para el usuario {user.Id}."); Console.ResetColor(); errorCount++; } } catch (Exception exHashUpdate) { errorCount++; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"ERROR al procesar usuario {user.Id}: {exHashUpdate.Message}"); Console.ResetColor(); // Considera loggear exHashUpdate.ToString() para más detalles } } } } catch (Exception exConnect) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"ERROR de conexión o consulta general: {exConnect.Message}"); Console.ResetColor(); return 1; // Termina con código de error } Console.WriteLine("\n--- Resumen de Migración ---"); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"Usuarios migrados exitosamente: {migratedCount}"); Console.ResetColor(); if (errorCount > 0) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Usuarios con errores: {errorCount}"); Console.ResetColor(); Console.WriteLine("Revise los mensajes de error anteriores."); return 1; // Termina con código de error si hubo fallos } else { Console.WriteLine("¡Migración completada sin errores!"); return 0; // Termina exitosamente }