using BCrypt.Net; using GameDatabase.Context; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Migrations; using System.Text; using System.Text.Json; #nullable disable namespace GameDatabase.Migrations { /// public partial class ReHashPasswords : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { using var context = new TaikoDbContext(); var credentials = context.Credentials.ToList(); foreach (var credential in credentials) { // Check if the password is empty or null if (!string.IsNullOrEmpty(credential.Password)) { // Passwords are currenrly stored as a string containing Password + Salt encoded in base64 4 times. // This is unacceptable so we'll rehash everything with bcrypt. var decodedData = Encoding.UTF8.GetString(Convert.FromBase64String(credential.Password)); // First pass decodedData = Encoding.UTF8.GetString(Convert.FromBase64String(decodedData)); // Second pass decodedData = Encoding.UTF8.GetString(Convert.FromBase64String(decodedData)); // Third pass decodedData = Encoding.UTF8.GetString(Convert.FromBase64String(decodedData)); // Last pass, leaving us with plain text password + salt decodedData = decodedData.Substring(0, decodedData.Length - credential.Salt.Length); // Recovering plain text password credential.Salt = BCrypt.Net.BCrypt.GenerateSalt(10); credential.Password = BCrypt.Net.BCrypt.HashPassword(decodedData, credential.Salt); // Hashing the pass properly this time Console.WriteLine("ReHashed password for baid " + credential.Baid + " (out of " + credentials.Count + " baids)"); } } context.SaveChanges(); } /// protected override void Down(MigrationBuilder migrationBuilder) { // On Down we reset all passes and salts for everyone. migrationBuilder.Sql(@" UPDATE Credential SET Password = '', Salt = '' "); } } }